diff --git a/package-lock.json b/package-lock.json index da4b9fe..7d0026c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "immersive", - "version": "0.0.8-13", + "version": "0.0.8-16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "immersive", - "version": "0.0.8-13", + "version": "0.0.8-16", "dependencies": { - "@babylonjs/core": "^7.9.0", - "@babylonjs/gui": "^7.9.0", + "@babylonjs/core": "^7.21.5", + "@babylonjs/gui": "^7.21.5", "@babylonjs/havok": "1.3.4", - "@babylonjs/inspector": "^7.9.0", - "@babylonjs/loaders": "^7.9.0", - "@babylonjs/materials": "^7.9.0", - "@babylonjs/serializers": "^7.9.0", + "@babylonjs/inspector": "^7.21.5", + "@babylonjs/loaders": "^7.21.5", + "@babylonjs/materials": "^7.21.5", + "@babylonjs/serializers": "^7.21.5", "@maptiler/client": "1.8.1", "@picovoice/cobra-web": "^2.0.3", "@picovoice/eagle-web": "^1.0.0", @@ -70,14 +70,14 @@ } }, "node_modules/@babylonjs/core": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-7.9.0.tgz", - "integrity": "sha512-ZhXlcnEZSpu8c4jH3bqwfUF8RZdPZTltkYRxZTwFlqkTy6qI80mCMwQr/s3aKGSmGAQKvi37LAnGV7264W+/XQ==" + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-7.21.5.tgz", + "integrity": "sha512-tfHpwxeZfijS/bvkOsFMSSB33DSjmNwBvgvqUBrBCknvup8cMy4f6x53TIAWXBMv2o+WaMbAcvC3PFVoczVxhQ==" }, "node_modules/@babylonjs/gui": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-7.9.0.tgz", - "integrity": "sha512-61jsrv5h+GpSwQZfiR6/qzXHOuROR3/EWYf8aNBzItvxHAiSeNxpUNR5FdXu2sxBDCMEyUc9fZtO+9wlH0PDYw==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-7.21.5.tgz", + "integrity": "sha512-bazF27ssl3MldRe8rNHE6/KUjNRJC62KigvV3NiJFpO6ujGA3GN4h839QBPx53oeMz/vbQv7RhZ1/LX7Ud9pSg==", "peerDependencies": { "@babylonjs/core": "^7.0.0" } @@ -103,9 +103,9 @@ } }, "node_modules/@babylonjs/inspector": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-7.9.0.tgz", - "integrity": "sha512-bkFAiBBwDbnAmwJkYjlvX8/5CpCKqbkQd/2vcePMDFBh676YwadtwDsJFPfDLL8GRjKyRb4dm7O07rS2MvVQ3g==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-7.21.5.tgz", + "integrity": "sha512-mtk6GTEGXi4ZLrxByma1zn7ulOaG999nQwL49j/Pk1aSSCE4EdSHhmqs9StUIeGvg3/3W+DFKY87/hpOlRaodA==", "dependencies": { "@fortawesome/fontawesome-svg-core": "^6.1.0", "@fortawesome/free-regular-svg-icons": "^6.0.0", @@ -123,26 +123,26 @@ } }, "node_modules/@babylonjs/loaders": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-7.9.0.tgz", - "integrity": "sha512-/wmLNkHhJkTZ4+0TM2aWc76sTgndIZyVNQ8jxQHeCwfq8M3X4DbBQyHC3JZJx+dplz6b0eD6m2oiSEmbBvZwQw==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-7.21.5.tgz", + "integrity": "sha512-l2mj4P4t/r9tHotf6lif2rceI1tK1wDssQ/34/oWxWoNi8L9ZgJ8zZue6kgKS1TqSZIVJOXpp9QQ7gJlBgx/FQ==", "peerDependencies": { "@babylonjs/core": "^7.0.0", "babylonjs-gltf2interface": "^7.0.0" } }, "node_modules/@babylonjs/materials": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-7.9.0.tgz", - "integrity": "sha512-M9s6d5+9sNOJAQHMHKj880dQRUAZoxoHw4VlSeGhETFKFKk9iHGRCOmhmwbU68R1wdIHPUbDV4gijv/pNlcCqQ==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-7.21.5.tgz", + "integrity": "sha512-jrzUdZ3wXiPuvNctTnvH3VX2XcAYWI5lycuMsQ5343MWAr9H+YIHdqGm2ITDOXL5mo+Qbl08l6jg7cvtygzQLg==", "peerDependencies": { "@babylonjs/core": "^7.0.0" } }, "node_modules/@babylonjs/serializers": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-7.9.0.tgz", - "integrity": "sha512-y1wnxGDneECHqW/L2cYsJ6e0aIifDk9eb02H/ORvhDnCrEwEL3cabh+Ouvsrcw/giPQPsZ6XB36OAoZDV5i1Rw==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-7.21.5.tgz", + "integrity": "sha512-HbT5AcQ8S2Qh0tWqygZsp9yfBgtpATcH1Hch2Cep+PbQ5OAcEkHGywAC2EiLkrYINdHw3iLJ1D1+7zYVkqzSzQ==", "peerDependencies": { "@babylonjs/core": "^7.0.0", "babylonjs-gltf2interface": "^7.0.0" diff --git a/package.json b/package.json index 021fc93..40a04c4 100644 --- a/package.json +++ b/package.json @@ -17,13 +17,13 @@ "havok": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps" }, "dependencies": { - "@babylonjs/core": "^7.9.0", - "@babylonjs/gui": "^7.9.0", + "@babylonjs/core": "^7.21.5", + "@babylonjs/gui": "^7.21.5", "@babylonjs/havok": "1.3.4", - "@babylonjs/inspector": "^7.9.0", - "@babylonjs/loaders": "^7.9.0", - "@babylonjs/materials": "^7.9.0", - "@babylonjs/serializers": "^7.9.0", + "@babylonjs/inspector": "^7.21.5", + "@babylonjs/loaders": "^7.21.5", + "@babylonjs/materials": "^7.21.5", + "@babylonjs/serializers": "^7.21.5", "@maptiler/client": "1.8.1", "@picovoice/cobra-web": "^2.0.3", "@picovoice/eagle-web": "^1.0.0", diff --git a/src/diagram/diagramObject.ts b/src/diagram/diagramObject.ts index 7a5deb2..4688441 100644 --- a/src/diagram/diagramObject.ts +++ b/src/diagram/diagramObject.ts @@ -1,10 +1,13 @@ import { AbstractActionManager, AbstractMesh, + Curve3, + GreasedLineMesh, InstancedMesh, Mesh, Observable, Observer, + Ray, Scene, TransformNode, Vector3 @@ -37,6 +40,8 @@ export class DiagramObject { private _labelBack: InstancedMesh; private _meshesPresent: boolean = false; private _positionHash: string; + private _fromPosition: number = 0; + private _toPosition: number = 0; private _disposed: boolean = false; private _fromMesh: AbstractMesh; private _toMesh: AbstractMesh; @@ -136,7 +141,7 @@ export class DiagramObject { public updateLabelPosition() { if (this._label) { this._mesh.computeWorldMatrix(true); - this._mesh.refreshBoundingInfo(); + this._mesh.refreshBoundingInfo({}); if (this._from && this._to) { //this._label.position.x = .06; //this._label.position.z = .06; @@ -172,6 +177,7 @@ export class DiagramObject { position: oldEntity.position, rotation: oldEntity.rotation, scale: oldEntity.scale, + image: oldEntity.image, template: oldEntity.template, color: oldEntity.color, text: oldEntity.text @@ -234,7 +240,7 @@ export class DiagramObject { this._sceneObserver = this._scene.onAfterRenderObservable.add(() => { tick++; - if (tick % 5 === 0) { + if (tick % 3 === 0) { if (this._meshesPresent) { this.updateConnection(); } else { @@ -305,13 +311,50 @@ export class DiagramObject { } private updateConnection() { - this._baseTransform.position = Vector3.Center(this._fromMesh.getAbsolutePosition().clone(), this._toMesh.getAbsolutePosition().clone()); - this._baseTransform.lookAt(this._toMesh.getAbsolutePosition()); - this._mesh.scaling.y = Vector3.Distance(this._fromMesh.getAbsolutePosition(), this._toMesh.getAbsolutePosition()); - this._mesh.material = this._fromMesh.material; - if (!this._mesh.parent) { - this._mesh.parent = this._baseTransform; + + if (this._toMesh.absolutePosition.length() == this._toPosition && this._fromMesh.absolutePosition.length() == this._fromPosition) { + return; } - this._mesh.rotation.x = Math.PI / 2; + + const curve: GreasedLineMesh = ((this._mesh as unknown) as GreasedLineMesh); + const ray = new Ray(this._fromMesh.getAbsolutePosition(), Vector3.Normalize(this._toMesh.getAbsolutePosition().subtract(this._fromMesh.getAbsolutePosition()))); + //const rayHelper = new RayHelper(ray); + //rayHelper.show(this._scene, new Color3(1, 0, 0)); + const hit = this._scene.multiPickWithRay(ray, (mesh) => { + if (mesh.id === this._to || mesh.id === this._from) { + //mesh.updateFacetData(); + return true; + } else { + return false; + } + }); + + //this._fromMesh.updateFacetData(); + //this._toMesh.updateFacetData(); + + //const positions = this._fromMesh.getFacetLocalPositions(); + const hit0matrix = hit[0].pickedMesh.computeWorldMatrix(true); + const hit1matrix = hit[1].pickedMesh.computeWorldMatrix(true); + const hitpoint0 = Vector3.TransformCoordinates(hit[0].pickedPoint, hit0matrix); + const hitpoint1 = Vector3.TransformCoordinates(hit[1].pickedPoint, hit1matrix); + const distance = Math.abs(hit[0].pickedPoint.subtract(hit[1].pickedPoint).lengthSquared()); + + const fromNormal = hit[0].pickedMesh.getFacetNormal(hit[0].faceId); + const toNormal = hit[1].pickedMesh.getFacetNormal(hit[1].faceId); + + const c = Curve3.CreateCubicBezier(hit[0].pickedPoint, hit[0].pickedPoint.add(fromNormal.normalize().scale(distance * .2)), + hit[1].pickedPoint.add(toNormal.normalize().scale(distance * .2)), + hit[1].pickedPoint, 40); + const p = c.getPoints().flatMap((point) => { + return point.asArray() + }) + curve.setParent(null); + curve.setPoints([p]); + this._toPosition = this._toMesh.absolutePosition.length(); + this._fromPosition = this._fromMesh.absolutePosition.length(); + curve.setParent(this._baseTransform); + curve.setEnabled(true); + console.log('done'); + } } \ No newline at end of file diff --git a/src/diagram/functions/buildMeshFromDiagramEntity.ts b/src/diagram/functions/buildMeshFromDiagramEntity.ts index 87c0018..fe90170 100644 --- a/src/diagram/functions/buildMeshFromDiagramEntity.ts +++ b/src/diagram/functions/buildMeshFromDiagramEntity.ts @@ -2,15 +2,22 @@ import {DiagramEntity, DiagramEntityType, DiagramTemplates} from "../types/diagr import { AbstractMesh, Color3, + CreateGreasedLine, + Curve3, + GreasedLineMesh, + GreasedLineMeshColorMode, InstancedMesh, Mesh, MeshBuilder, Scene, StandardMaterial, - Texture + Texture, + Vector3 } from "@babylonjs/core"; import log from "loglevel"; import {v4 as uuidv4} from 'uuid'; +import {xyztovec} from "./vectorConversion"; +import {AnimatedLineTexture} from "../../util/animatedLineTexture"; export function buildMeshFromDiagramEntity(entity: DiagramEntity, scene: Scene): AbstractMesh { const logger = log.getLogger('buildMeshFromDiagramEntity'); @@ -50,12 +57,19 @@ function createNewInstanceIfNecessary(entity: DiagramEntity, scene: Scene): Abst newMesh = buildImage(entity, scene); break; case DiagramTemplates.CONNECTION: - newMesh = MeshBuilder.CreateCylinder(entity.id, { - diameterBottom: .04, - height: 1, - diameterTop: .004, - tessellation: 3 + const origin = new Vector3(0, 0, 0); + const control1 = new Vector3(0, 2, 0); + const control2 = new Vector3(0, 5, -5); + const end = new Vector3(0, 5, -8); + const curve = Curve3.CreateCubicBezier(origin, control1, control2, end, 40); + const path = curve.getPoints(); + newMesh = CreateGreasedLine(entity.id, {points: path, updatable: true}, { + width: .02, + colorMode: GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY }, scene); + (newMesh as GreasedLineMesh).intersectionThreshold = 2; + (newMesh.material as StandardMaterial).emissiveTexture = AnimatedLineTexture.Texture(); + newMesh.setEnabled(false); break; case DiagramTemplates.BOX: case DiagramTemplates.SPHERE: @@ -91,6 +105,7 @@ function createNewInstanceIfNecessary(entity: DiagramEntity, scene: Scene): Abst function buildImage(entity: DiagramEntity, scene: Scene): AbstractMesh { const logger = log.getLogger('buildImage'); + logger.error(entity); logger.debug("buildImage: entity is image"); const plane = MeshBuilder.CreatePlane(entity.id, {size: 1}, scene); const material = new StandardMaterial("planeMaterial", scene); @@ -100,8 +115,12 @@ function buildImage(entity: DiagramEntity, scene: Scene): AbstractMesh { material.backFaceCulling = false; material.disableLighting = true; plane.material = material; + plane.metadata = {image: entity.image}; + plane.scaling = xyztovec(entity.scale); image.decode().then(() => { plane.scaling.x = image.width / image.height; + }).catch((error) => { + logger.error("buildImage: error decoding image", error); }); return plane; } @@ -153,6 +172,9 @@ function mapMetadata(entity: DiagramEntity, newMesh: AbstractMesh, scene: Scene) if (entity.to) { newMesh.metadata.to = entity.to; } + if (entity.image) { + newMesh.metadata.image = entity.image; + } } else { logger.error("buildMeshFromDiagramEntity: mesh is null after it should have been created"); } diff --git a/src/diagram/functions/toDiagramEntity.ts b/src/diagram/functions/toDiagramEntity.ts index e597e8c..abb9783 100644 --- a/src/diagram/functions/toDiagramEntity.ts +++ b/src/diagram/functions/toDiagramEntity.ts @@ -34,7 +34,6 @@ export function toDiagramEntity(mesh: AbstractMesh): DiagramEntity { entity.color = (mesh.material as any).albedoColor.toHexString(); break; } - } else { if (entity.template != "#object-template") { logger.error("toDiagramEntity: mesh.material is null"); diff --git a/src/integration/pouchdbPersistenceManager.ts b/src/integration/database/pouchdbPersistenceManager.ts similarity index 96% rename from src/integration/pouchdbPersistenceManager.ts rename to src/integration/database/pouchdbPersistenceManager.ts index 4d2a76b..d77057b 100644 --- a/src/integration/pouchdbPersistenceManager.ts +++ b/src/integration/database/pouchdbPersistenceManager.ts @@ -1,29 +1,26 @@ import PouchDB from 'pouchdb'; -import {DiagramEntity, DiagramEventType} from "../diagram/types/diagramEntity"; +import {DiagramEntity, DiagramEventType} from "../../diagram/types/diagramEntity"; import {Observable} from "@babylonjs/core"; import axios from "axios"; -import {DiagramManager} from "../diagram/diagramManager"; +import {DiagramManager} from "../../diagram/diagramManager"; import log, {Logger} from "loglevel"; -import {ascii_to_hex} from "./functions/hexFunctions"; -import {getPath} from "../util/functions/getPath"; -import {DiagramEventObserverMask} from "../diagram/types/diagramEventObserverMask"; -import {syncDoc} from "./functions/syncDoc"; -import {checkDb} from "./functions/checkDb"; -import {UserModelType} from "../users/userTypes"; -import {getMe} from "../util/me"; -import {Encryption} from "./encryption"; -import {Presence} from "./presence"; +import {ascii_to_hex} from "../functions/hexFunctions"; +import {getPath} from "../../util/functions/getPath"; +import {DiagramEventObserverMask} from "../../diagram/types/diagramEventObserverMask"; +import {syncDoc} from "../functions/syncDoc"; +import {checkDb} from "../functions/checkDb"; +import {UserModelType} from "../../users/userTypes"; +import {getMe} from "../../util/me"; +import {Encryption} from "../encryption"; +import {Presence} from "../presence"; type PasswordEvent = { detail: string; - } type PasswordEvent2 = { - password: string; id: string; encrypted: boolean; - } export class PouchdbPersistenceManager { private _logger: Logger = log.getLogger('PouchdbPersistenceManager'); @@ -388,7 +385,7 @@ export class PouchdbPersistenceManager { this._logger.debug(dbInfo); const presence: Presence = new Presence(getMe(), remoteDbName); this._diagramManager.onUserEventObservable.add((user: UserModelType) => { - this._logger.debug(user); + //this._logger.debug(user); presence.sendUser(user); }, -1, false, this); this.db.sync(this.remote, {live: true, retry: true}) diff --git a/src/menus/ScaleMenu2.ts b/src/menus/ScaleMenu2.ts index 4fefbd5..5c2f007 100644 --- a/src/menus/ScaleMenu2.ts +++ b/src/menus/ScaleMenu2.ts @@ -41,6 +41,11 @@ export class ScaleMenu2 { } public show(mesh: AbstractMesh) { + if (mesh.metadata.image) { + configureImageScale(this._gizmoManager.gizmos.scaleGizmo.yGizmo, true); + configureImageScale(this._gizmoManager.gizmos.scaleGizmo.xGizmo, true); + configureImageScale(this._gizmoManager.gizmos.scaleGizmo.zGizmo, false); + } this._gizmoManager.attachToMesh(mesh); } @@ -56,4 +61,13 @@ function configureGizmo(gizmo: IAxisScaleGizmo) { gizmo.scaleRatio = 3; gizmo.sensitivity = 3; +} + +function configureImageScale(gizmo: IAxisScaleGizmo, enabled: boolean) { + gizmo.snapDistance = .1; + gizmo.uniformScaling = true; + gizmo.scaleRatio = 3; + gizmo.sensitivity = 3; + gizmo.isEnabled = enabled; + } \ No newline at end of file diff --git a/src/newrelic/newRelicData.ts b/src/newrelic/newRelicData.ts index a45c622..f5994fc 100644 --- a/src/newrelic/newRelicData.ts +++ b/src/newrelic/newRelicData.ts @@ -8,7 +8,7 @@ import { StandardMaterial, Vector3 } from "@babylonjs/core"; -import {PouchdbPersistenceManager} from "../integration/pouchdbPersistenceManager"; +import {PouchdbPersistenceManager} from "../integration/database/pouchdbPersistenceManager"; export class NewRelicData { private key: string; diff --git a/src/objects/curveObject.ts b/src/objects/curveObject.ts new file mode 100644 index 0000000..2ca6efc --- /dev/null +++ b/src/objects/curveObject.ts @@ -0,0 +1,18 @@ +import {CreateGreasedLine, Curve3, Vector3} from "@babylonjs/core"; +import {DefaultScene} from "../defaultScene"; + +export default class CurveObject { + constructor() { + this._buildCurve(); + } + + private _buildCurve() { + const origin = new Vector3(0, 0, 0); + const control1 = new Vector3(0, 2, 0); + const control2 = new Vector3(0, 5, -5); + const end = new Vector3(0, 5, -8); + const curve = Curve3.CreateCubicBezier(origin, control1, control2, end, 10); + const path = curve.getPoints(); + const line = CreateGreasedLine("name", {points: path}, {}, DefaultScene.Scene); + } +} diff --git a/src/util/animatedLineTexture.ts b/src/util/animatedLineTexture.ts new file mode 100644 index 0000000..8e9faca --- /dev/null +++ b/src/util/animatedLineTexture.ts @@ -0,0 +1,30 @@ +import {Engine, RawTexture} from "@babylonjs/core"; +import {DefaultScene} from "../defaultScene"; + +export class AnimatedLineTexture { + private static _textureColors = new Uint8Array([10, 10, 10, 10, 10, 10, 25, 25, 25, 10, 10, 255]) + private static _texture: RawTexture; + + public static Texture() { + if (!AnimatedLineTexture._texture) { + this._texture = new RawTexture( + this._textureColors, + this._textureColors.length / 3, + 1, + Engine.TEXTUREFORMAT_RGB, + DefaultScene.Scene, + false, + true, + Engine.TEXTURE_NEAREST_NEAREST + ) + this._texture.wrapU = RawTexture.WRAP_ADDRESSMODE + this._texture.name = 'blue-white-texture'; + this._texture.uScale = 30; + DefaultScene.Scene.onBeforeRenderObservable.add(() => { + this._texture.uOffset += 0.05 * DefaultScene.Scene.getAnimationRatio() + }); + + } + return this._texture; + } +} \ No newline at end of file diff --git a/src/vrApp.ts b/src/vrApp.ts index bb6cd3a..212b612 100644 --- a/src/vrApp.ts +++ b/src/vrApp.ts @@ -5,7 +5,7 @@ import log, {Logger} from "loglevel"; import {GamepadManager} from "./controllers/gamepadManager"; import {CustomEnvironment} from "./util/customEnvironment"; import {Spinner} from "./objects/spinner"; -import {PouchdbPersistenceManager} from "./integration/pouchdbPersistenceManager"; +import {PouchdbPersistenceManager} from "./integration/database/pouchdbPersistenceManager"; import {addSceneInspector} from "./util/functions/sceneInspector"; import {groundMeshObserver} from "./util/functions/groundMeshObserver"; import {buildQuestLink} from "./util/functions/buildQuestLink"; @@ -16,7 +16,8 @@ import {Introduction} from "./tutorial/introduction"; const webGpu = false; -log.setLevel('debug', false); +log.setLevel('error', false); +log.getLogger('PouchdbPersistenceManager').setLevel('debug', false); const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement); export class VrApp { @@ -53,6 +54,8 @@ export class VrApp { el.addEventListener('click', () => { exportGltf(); }) + } else { + this.logger.error('Download button not found'); } if (!localStorage.getItem('tutorialCompleted')) { this.logger.info('Starting tutorial'); @@ -78,6 +81,7 @@ export class VrApp { } const scene = new Scene(engine); DefaultScene.Scene = scene; + //const a = new CurveObject(); scene.ambientColor = new Color3(.1, .1, .1); //log.resetLevel();