diff --git a/src/app.ts b/src/app.ts index 8ff035c..a8c0f98 100644 --- a/src/app.ts +++ b/src/app.ts @@ -17,24 +17,15 @@ import {GamepadManager} from "./controllers/gamepadManager"; import {CustomEnvironment} from "./util/customEnvironment"; import {Controllers} from "./controllers/controllers"; import {Introduction} from "./tutorial/introduction"; +import {IndexdbPersistenceManager} from "./integration/indexdbPersistenceManager"; export class App { //preTasks = [havokModule]; constructor() { - const config = AppConfig.config; - const logger = log.getLogger('App'); - //log.enableAll(true); - log.setDefaultLevel('info'); - //log.getLogger('App').setLevel('info'); - //log.getLogger('IndexdbPersistenceManager').setLevel('info'); - //log.getLogger('DiagramManager').setLevel('info'); - //log.getLogger('DiagramConnection').setLevel('debug'); - //log.getLogger('DrawioManager').setLevel('warn'); - //log.getLogger('VoiceManager').setLevel('debug'); - //log.getLogger('EntityTree').setLevel('warn'); - //log.getLogger('EditMenu').setLevel('warn'); + const logger = log.getLogger('App'); + log.setDefaultLevel('debug'); const canvas = document.createElement("canvas"); canvas.style.width = "100%"; canvas.style.height = "100%"; @@ -51,12 +42,23 @@ export class App { } async initialize(canvas) { - const config = AppConfig.config; - const logger = log.getLogger('App'); const engine = new Engine(canvas, true); const scene = new Scene(engine); - const environment = new CustomEnvironment(scene); + + const persistenceManager = new IndexdbPersistenceManager("diagram"); + const controllers = new Controllers(); + const toolbox = new Toolbox(scene, controllers); + const diagramManager = new DiagramManager(scene, controllers, toolbox); + diagramManager.setPersistenceManager(persistenceManager); + const config = new AppConfig(persistenceManager); + const environment = new CustomEnvironment(scene, "default", config); + persistenceManager.initialize().then(() => { + if (!config.current?.demoCompleted) { + const intro = new Introduction(scene, config); + intro.start(); + } + }); const camera: ArcRotateCamera = new ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 4, @@ -92,27 +94,14 @@ export class App { } }); - const controllers = new Controllers(); - const diagramManager = new DiagramManager(scene, xr.baseExperience, controllers); + const rig = new Rigplatform(scene, xr, diagramManager, controllers); - const toolbox = new Toolbox(scene, xr.baseExperience, diagramManager, controllers); + //const dioManager = new DrawioManager(scene, diagramManager); - import ('./integration/indexdbPersistenceManager').then((module) => { - const persistenceManager = new module.IndexdbPersistenceManager("diagram"); - diagramManager.setPersistenceManager(persistenceManager); - AppConfig.config.setPersistenceManager(persistenceManager); - persistenceManager.initialize().then(() => { - if (!AppConfig.config?.demoCompleted) { - const intro = new Introduction(scene); - intro.start(); - } - }); + //const newRelicData = new NewRelicData(persistenceManager, scene); - //const newRelicData = new NewRelicData(persistenceManager, scene); - - }); }); diff --git a/src/controllers/base.ts b/src/controllers/base.ts index 9825abc..9d94519 100644 --- a/src/controllers/base.ts +++ b/src/controllers/base.ts @@ -14,7 +14,6 @@ import {DiagramManager} from "../diagram/diagramManager"; import {DiagramEvent, DiagramEventType} from "../diagram/diagramEntity"; import log from "loglevel"; import {Controllers} from "./controllers"; -import {AppConfig} from "../util/appConfig"; export class Base { static stickVector = Vector3.Zero(); @@ -217,8 +216,8 @@ export class Base { this.reparent(mesh); if (!mesh.physicsBody) { - mesh.position = AppConfig.config.snapGridVal(mesh.position); - mesh.rotation = AppConfig.config.snapRotateVal(mesh.rotation); + mesh.position = this.diagramManager.config.snapGridVal(mesh.position); + mesh.rotation = this.diagramManager.config.snapRotateVal(mesh.rotation); } this.previousParentId = null; this.previousScaling = null; diff --git a/src/controllers/left.ts b/src/controllers/left.ts index e34a631..32fbbf6 100644 --- a/src/controllers/left.ts +++ b/src/controllers/left.ts @@ -13,7 +13,7 @@ export class Left extends Base { WebXRInputSource, scene: Scene, xr: WebXRDefaultExperience, diagramManager: DiagramManager, controllers: Controllers) { super(controller, scene, xr, controllers, diagramManager); - this.configMenu = new ConfigMenu(this.scene, xr.baseExperience, this.controllers); + this.configMenu = new ConfigMenu(this.scene, xr.baseExperience, this.controllers, this.diagramManager.config); this.controller.onMotionControllerInitObservable.add((init) => { if (init.components['xr-standard-thumbstick']) { init.components['xr-standard-thumbstick'] diff --git a/src/controllers/rigplatform.ts b/src/controllers/rigplatform.ts index c163415..5124a94 100644 --- a/src/controllers/rigplatform.ts +++ b/src/controllers/rigplatform.ts @@ -20,7 +20,6 @@ import {EditMenu} from "../menus/editMenu"; import {Controllers} from "./controllers"; import log from "loglevel"; import {DiagramManager} from "../diagram/diagramManager"; -import {AppConfig} from "../util/appConfig"; export class Rigplatform { @@ -62,9 +61,9 @@ export class Rigplatform { this.velocity.y = (val * this.velocityArray[this.velocityIndex])*-1; } public turn(val: number) { - const snap = AppConfig.config.currentTurnSnap.value; + const snap = this.diagramManager.config.current?.turnSnap; - if (snap > 0) { + if (snap && snap > 0) { if (!this.turning) { if (Math.abs(val) > .1) { this.turning = true; @@ -192,7 +191,9 @@ export class Rigplatform { } private fixRotation() { this.scene.onAfterPhysicsObservable.add(() => { - if (AppConfig?.config?.currentTurnSnap?.value > 0) { + const turnSnap = this.diagramManager.config.current?.turnSnap; + + if (turnSnap && turnSnap > 0) { const q = this.rigMesh.rotationQuaternion; this.body.setAngularVelocity(Vector3.Zero()); if (q) { diff --git a/src/diagram/diagramManager.ts b/src/diagram/diagramManager.ts index d1c7bab..8056bb0 100644 --- a/src/diagram/diagramManager.ts +++ b/src/diagram/diagramManager.ts @@ -11,7 +11,7 @@ import { PhysicsShapeType, PlaySoundAction, Scene, - WebXRExperienceHelper + Vector3 } from "@babylonjs/core"; import {DiagramEntity, DiagramEvent, DiagramEventType} from "./diagramEntity"; import {IPersistenceManager} from "../integration/iPersistenceManager"; @@ -21,37 +21,21 @@ import {Controllers} from "../controllers/controllers"; import {DiaSounds} from "../util/diaSounds"; import {AppConfig} from "../util/appConfig"; import {TextLabel} from "./textLabel"; +import {Toolbox} from "../toolbox/toolbox"; + export class DiagramManager { public readonly onDiagramEventObservable: Observable = new Observable(); private readonly logger = log.getLogger('DiagramManager'); private persistenceManager: IPersistenceManager = null; + private readonly toolbox: Toolbox; private readonly scene: Scene; - private xr: WebXRExperienceHelper; private sounds: DiaSounds; - - public setPersistenceManager(persistenceManager: IPersistenceManager) { - this.persistenceManager = persistenceManager; - this.persistenceManager.updateObserver.add(this.onRemoteEvent, -1, true, this); - } - - private getPersistenceManager(): IPersistenceManager { - if (!this.persistenceManager) { - this.logger.warn("persistenceManager not set"); - return null; - } - return this.persistenceManager; - } - - private readonly actionManager: ActionManager; - private config: AppConfig; - private controllers: Controllers; - - constructor(scene: Scene, xr: WebXRExperienceHelper, controllers: Controllers) { + constructor(scene: Scene, controllers: Controllers, toolbox: Toolbox) { this.sounds = new DiaSounds(scene); this.scene = scene; - this.xr = xr; + this.toolbox = toolbox; this.controllers = controllers; this.actionManager = new ActionManager(this.scene); this.actionManager.registerAction( @@ -86,6 +70,30 @@ export class DiagramManager { } }); } + + private _config: AppConfig; + + private getPersistenceManager(): IPersistenceManager { + if (!this.persistenceManager) { + this.logger.warn("persistenceManager not set"); + return null; + } + return this.persistenceManager; + } + + private readonly actionManager: ActionManager; + private controllers: Controllers; + + public get config(): AppConfig { + return this._config; + } + + public setPersistenceManager(persistenceManager: IPersistenceManager) { + this.persistenceManager = persistenceManager; + this._config = new AppConfig(persistenceManager); + this.persistenceManager.updateObserver.add(this.onRemoteEvent, -1, true, this); + } + public createCopy(mesh: AbstractMesh, copy: boolean = false): AbstractMesh { let newMesh; if (!mesh.isAnInstance) { @@ -103,12 +111,23 @@ export class DiagramManager { if (copy) { newMesh.scaling = mesh.scaling.clone(); } else { - newMesh.scaling = AppConfig.config.createSnapVal; + if (this.config.current?.createSnap) { + newMesh.scaling.x = this.config.current?.createSnap; + newMesh.scaling.y = this.config.current?.createSnap; + newMesh.scaling.z = this.config.current?.createSnap; + } else { + newMesh.scaling = Vector3.One(); + } + + } newMesh.material = mesh.material; newMesh.metadata = this.deepCopy(mesh.metadata); - DiagramShapePhysics.applyPhysics(this.sounds, newMesh, this.scene); + if (this.config.current?.physicsEnabled) { + DiagramShapePhysics.applyPhysics(this.sounds, newMesh, this.scene); + } + this.persistenceManager.add(newMesh); return newMesh; } @@ -135,17 +154,17 @@ export class DiagramManager { const toolMesh = this.scene.getMeshById("tool-" + event.template + "-" + event.color); if (!toolMesh && (event.template != '#connection-template')) { log.debug('no mesh found for ' + event.template + "-" + event.color, 'adding it'); - this.onDiagramEventObservable.notifyObservers({ - type: DiagramEventType.CHANGECOLOR, - entity: event - }); + //this.getPersistenceManager()?.changeColor(null, Color3.FromHexString(event.color)); + this.toolbox.updateToolbox(event.color); } const mesh = MeshConverter.fromDiagramEntity(event, this.scene); mesh.actionManager = this.actionManager; if (event.parent) { mesh.parent = this.scene.getMeshById(event.parent); } - DiagramShapePhysics.applyPhysics(this.sounds, mesh, this.scene, PhysicsMotionType.DYNAMIC); + if (this.config.current?.physicsEnabled) { + DiagramShapePhysics.applyPhysics(this.sounds, mesh, this.scene, PhysicsMotionType.DYNAMIC); + } } private onDiagramEvent(event: DiagramEvent) { @@ -157,17 +176,17 @@ export class DiagramManager { } if (!mesh && event?.entity?.template) { const toolMesh = this.scene.getMeshById("tool-" + event.entity.template + "-" + event.entity.color); - if (!toolMesh) { + if (!toolMesh && event.type != DiagramEventType.CHANGECOLOR) { log.debug('no mesh found for ' + event.entity.template + "-" + event.entity.color, 'adding it'); - this.onDiagramEventObservable.notifyObservers({ - type: DiagramEventType.CHANGECOLOR, - entity: event.entity - }); + this.toolbox.updateToolbox(event.entity.color); } mesh = MeshConverter.fromDiagramEntity(event.entity, this.scene); if (mesh) { mesh.actionManager = this.actionManager; - DiagramShapePhysics.applyPhysics(this.sounds, mesh, this.scene, PhysicsMotionType.DYNAMIC); + if (this.config.current.physicsEnabled) { + DiagramShapePhysics.applyPhysics(this.sounds, mesh, this.scene, PhysicsMotionType.DYNAMIC); + } + } } @@ -189,13 +208,19 @@ export class DiagramManager { if (!mesh.actionManager) { mesh.actionManager = this.actionManager; } - DiagramShapePhysics - .applyPhysics(this.sounds, mesh, this.scene); + if (this.config.current.physicsEnabled) { + DiagramShapePhysics + .applyPhysics(this.sounds, mesh, this.scene); + } + break; case DiagramEventType.MODIFY: this.getPersistenceManager()?.modify(mesh); - DiagramShapePhysics - .applyPhysics(this.sounds, mesh, this.scene); + if (this.config.current.physicsEnabled) { + DiagramShapePhysics + .applyPhysics(this.sounds, mesh, this.scene); + } + break; case DiagramEventType.CHANGECOLOR: if (!event.oldColor) { @@ -234,9 +259,6 @@ class DiagramShapePhysics { private static logger: log.Logger = log.getLogger('DiagramShapePhysics'); public static applyPhysics(sounds: DiaSounds, mesh: AbstractMesh, scene: Scene, motionType?: PhysicsMotionType) { - if (!AppConfig.config.physicsEnabled) { - return; - } if (!mesh?.metadata?.template) { this.logger.error("applyPhysics: mesh.metadata.template is null", mesh); return; diff --git a/src/integration/iPersistenceManager.ts b/src/integration/iPersistenceManager.ts index b8511ed..727c19a 100644 --- a/src/integration/iPersistenceManager.ts +++ b/src/integration/iPersistenceManager.ts @@ -43,6 +43,8 @@ export interface IPersistenceManager { setConfig(config: AppConfigType); + getConfig(): Promise; + modifyDiagram(diagram: DiagramListing); updateObserver: Observable; diff --git a/src/integration/indexdbPersistenceManager.ts b/src/integration/indexdbPersistenceManager.ts index ab5c5fa..47949c5 100644 --- a/src/integration/indexdbPersistenceManager.ts +++ b/src/integration/indexdbPersistenceManager.ts @@ -95,6 +95,12 @@ export class IndexdbPersistenceManager implements IPersistenceManager { return this.db["newRelicData"].toArray(); } + public async getConfig(): Promise { + const configs = await this.db['config'].toArray(); + const config = configs[0]; + return config; + } + public async initialize() { this.logger.info('initialize', this.db['entities'].length); const configs = await this.db['config'].toArray(); diff --git a/src/menus/configMenu.ts b/src/menus/configMenu.ts index 888bdcf..454f492 100644 --- a/src/menus/configMenu.ts +++ b/src/menus/configMenu.ts @@ -12,19 +12,14 @@ export class ConfigMenu extends BaseMenu { private configPlane: AbstractMesh = null; private yObserver; - - constructor(scene: Scene, xr: WebXRExperienceHelper, controllers: Controllers) { - super(scene, xr, controllers); - this.sounds = new DiaSounds(scene); - if (!this.yObserver) { - this.controllers.controllerObserver.add((event) => { - if (event.type == 'y-button') { - this.toggle(); - } - }); - } - - } + private config: AppConfig; + private gridSnaps: Array<{ label: string, value: number }> = [ + {label: "Off", value: 0}, + {label: "0.01", value: 0.01}, + {label: "0.1", value: 0.1}, + {label: "0.5", value: 0.5}, + {label: "1", value: 1}, + ] public toggle() { if (this.configPlane) { @@ -55,19 +50,35 @@ export class ConfigMenu extends BaseMenu { CameraHelper.setMenuPosition(this.configPlane, this.scene); } + private rotationSnaps: Array<{ label: string, value: number }> = [ + {label: "Off", value: 0}, + {label: "22.5", value: 22.5}, + {label: "45", value: 45}, + {label: "90", value: 90}, + + ] + + constructor(scene: Scene, xr: WebXRExperienceHelper, controllers: Controllers, config: AppConfig) { + super(scene, xr, controllers); + this.config = config; + this.sounds = new DiaSounds(scene); + if (!this.yObserver) { + this.controllers.controllerObserver.add((event) => { + if (event.type == 'y-button') { + this.toggle(); + } + }); + } - private createVal(value) { - AppConfig.config.currentCreateSnapIndex = value; - log.debug("configMenu", "create Snap", value); } private buildCreateScaleControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Create Scale"); selectionPanel.addGroup(radio); - for (const [index, snap] of AppConfig.config.createSnaps().entries()) { - const selected = AppConfig.config.currentCreateSnapIndex == index; - radio.addRadio(snap.label, this.createVal, selected); + for (const [index, snap] of this.gridSnaps.entries()) { + const selected = this.config.current.createSnap == snap.value + radio.addRadio(snap.label, this.createVal.bind(this), selected); } return radio; } @@ -75,9 +86,9 @@ export class ConfigMenu extends BaseMenu { private buildRotationSnapControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Rotation Snap"); selectionPanel.addGroup(radio); - for (const [index, snap] of AppConfig.config.rotateSnaps().entries()) { - const selected = AppConfig.config.currentRotateSnapIndex == index; - radio.addRadio(snap.label, this.rotateVal, selected); + for (const [index, snap] of this.rotationSnaps.entries()) { + const selected = this.config.current.rotateSnap == snap.value + radio.addRadio(snap.label, this.rotateVal.bind(this), selected); } return radio; } @@ -85,9 +96,9 @@ export class ConfigMenu extends BaseMenu { private buildGridSizeControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Grid Snap"); selectionPanel.addGroup(radio); - for (const [index, snap] of AppConfig.config.gridSnaps().entries()) { - const selected = AppConfig.config.currentGridSnapIndex == index; - radio.addRadio(snap.label, this.gridVal, selected); + for (const [index, snap] of this.gridSnaps.entries()) { + const selected = this.config.current.gridSnap == snap.value; + radio.addRadio(snap.label, this.gridVal.bind(this), selected); } return radio; } @@ -95,25 +106,39 @@ export class ConfigMenu extends BaseMenu { private buildTurnSnapControl(selectionPanel: SelectionPanel): RadioGroup { const radio = new RadioGroup("Turn Snap"); selectionPanel.addGroup(radio); - for (const [index, snap] of AppConfig.config.turnSnaps().entries()) { - const selected = AppConfig.config.currentTurnSnapIndex == index; - radio.addRadio(snap.label, this.turnVal, selected); + for (const [index, snap] of this.rotationSnaps.entries()) { + const selected = this.config.current.rotateSnap == snap.value; + radio.addRadio(snap.label, this.turnVal.bind(this), selected); } return radio; } + private createVal(value) { + const config = this.config.current; + config.createSnap = this.gridSnaps[value].value; + this.config.current = config; + + log.debug("configMenu", "create Snap", value); + } + private rotateVal(value) { - AppConfig.config.currentRotateSnapIndex = value; + const config = this.config.current; + config.rotateSnap = this.rotationSnaps[value].value; + this.config.current = config; log.debug("configMenu", "rotate Snap", value); } private turnVal(value) { - AppConfig.config.currentTurnSnapIndex = value; + const config = this.config.current; + config.turnSnap = this.rotationSnaps[value].value; + this.config.current = config; log.debug("configMenu", "turn Snap", value); } private gridVal(value) { - AppConfig.config.currentGridSnapIndex = value; + const config = this.config.current; + config.gridSnap = this.gridSnaps[value].value; + this.config.current = config; log.debug("configMenu", "grid Snap", value); } diff --git a/src/menus/editMenu.ts b/src/menus/editMenu.ts index 31d751b..142e23e 100644 --- a/src/menus/editMenu.ts +++ b/src/menus/editMenu.ts @@ -23,7 +23,6 @@ import {CameraHelper} from "../util/cameraHelper"; import {TextLabel} from "../diagram/textLabel"; import {DiagramConnection} from "../diagram/diagramConnection"; import {GLTF2Export} from "@babylonjs/serializers"; -import {AppConfig} from "../util/appConfig"; export class EditMenu { private state: EditMenuState = EditMenuState.NONE; @@ -263,11 +262,15 @@ export class EditMenu { inputTextView.show(); inputTextView.onTextObservable.addOnce((value) => { console.log(value.text); - AppConfig.config.newRelicKey = value.text; + const config = this.diagramManager.config.current; + config.newRelicKey = value.text; + this.diagramManager.config.current = config; inputTextView.show(); inputTextView.onTextObservable.addOnce((value) => { console.log(value.text); - AppConfig.config.newRelicAccount = value.text; + const config = this.diagramManager.config.current; + config.newRelicAccount = value.text; + this.diagramManager.config.current = config; }); }); diff --git a/src/toolbox/toolbox.ts b/src/toolbox/toolbox.ts index 7d4a0ac..4e99663 100644 --- a/src/toolbox/toolbox.ts +++ b/src/toolbox/toolbox.ts @@ -7,14 +7,11 @@ import { Scene, StandardMaterial, TransformNode, - Vector3, - WebXRExperienceHelper + Vector3 } from "@babylonjs/core"; import {CameraHelper} from "../util/cameraHelper"; import {AdvancedDynamicTexture, Button3D, ColorPicker, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui"; -import {DiagramManager} from "../diagram/diagramManager"; -import {DiagramEventType} from "../diagram/diagramEntity"; import {Controllers} from "../controllers/controllers"; export enum ToolType { @@ -30,24 +27,16 @@ export class Toolbox { private index = 0; public static instance: Toolbox; private readonly scene: Scene; - private readonly xr: WebXRExperienceHelper; public readonly node: TransformNode; - private readonly diagramManager: DiagramManager; private readonly manager: GUI3DManager; private readonly gridsize = 5; private readonly addPanel: StackPanel3D; private readonly controllers: Controllers; private xObserver; - constructor(scene: Scene, xr: WebXRExperienceHelper, diagramManager: DiagramManager, controllers: Controllers) { + constructor(scene: Scene, controllers: Controllers) { this.scene = scene; this.controllers = controllers; - this.diagramManager = diagramManager; - this.diagramManager.onDiagramEventObservable.add((evt) => { - if (evt?.entity?.color && evt.type == DiagramEventType.CHANGECOLOR) { - this.updateToolbox(evt.entity.color); - } - }, -1, true, this); this.addPanel = new StackPanel3D(); this.manager = new GUI3DManager(scene); this.manager.addControl(this.addPanel); @@ -65,12 +54,8 @@ export class Toolbox { handle.position = Vector3.Zero(); this.node.parent = handle; - this.xr = xr; - if (!this.scene.activeCamera) { - return; - } else { - this.buildToolbox(); - } + + this.buildToolbox(); Toolbox.instance = this; if (!this.xObserver) { @@ -227,13 +212,6 @@ export class Toolbox { material.name = "material-" + newColorHex; mesh.id = "toolbox-color-" + newColorHex; mesh.name = "toolbox-color-" + newColorHex; - this.diagramManager.onDiagramEventObservable.notifyObservers( - { - type: DiagramEventType.CHANGECOLOR, - oldColor: oldColor, - newColor: newColor - } - ); }); colorPickerTexture.addControl(colorPicker); diff --git a/src/tutorial/introduction.ts b/src/tutorial/introduction.ts index 62ca5e7..d11788c 100644 --- a/src/tutorial/introduction.ts +++ b/src/tutorial/introduction.ts @@ -26,13 +26,16 @@ export class Introduction { private items: AbstractMesh[] = []; private advance: Button3D; private sounds: DiaSounds; + private config: AppConfig; - constructor(scene: Scene) { + constructor(scene: Scene, config: AppConfig) { this.sounds = new DiaSounds(scene); this.scene = scene; + this.config = config; this.manager = new GUI3DManager(scene); this.physicsHelper = new PhysicsHelper(scene); } + public start() { this.scene.physicsEnabled = true; this.advance = new Button3D("advance"); @@ -167,7 +170,9 @@ export class Introduction { }); this.advance.dispose(); this.manager.dispose(); - AppConfig.config.demoCompleted = true; + const config = this.config.current; + config.demoCompleted = true; + this.config.current = config; this.items = []; } this.step++; diff --git a/src/util/appConfig.ts b/src/util/appConfig.ts index dc311a6..807ebbe 100644 --- a/src/util/appConfig.ts +++ b/src/util/appConfig.ts @@ -1,4 +1,4 @@ -import {Angle, Vector3} from "@babylonjs/core"; +import {Angle, Observable, Vector3} from "@babylonjs/core"; import log from "loglevel"; import round from "round"; import {IPersistenceManager} from "../integration/iPersistenceManager"; @@ -9,244 +9,84 @@ export type SnapValue = { label: string } - export class AppConfig { private readonly logger = log.getLogger('AppConfig'); - private _demoCompleted = false; - private gridSnap = 1; - private _turnSnap = 0; - private rotateSnap = 0; - private createSnap = 0; - private _newRelicKey: string = null; + public readonly onConfigChangedObservable = new Observable(); + private _currentConfig: AppConfigType; + private persistenceManager: IPersistenceManager; - public get newRelicKey(): string { - return this._newRelicKey; - } - - _physicsEnabled = false; - private readonly defaultGridSnapIndex = 1; - private persistenceManager: IPersistenceManager = null; - private gridSnapArray: SnapValue[] = - [{value: 0, label: "Off"}, - {value: 0.05, label: "(Default)"}, - {value: 0.01, label: "1 cm"}, - {value: 0.1, label: "10 cm"}, - {value: 0.25, label: "25 cm"}, - {value: .5, label: ".5 m"}] - private createSnapArray: SnapValue[] = - [{value: .1, label: "Default (10 cm)"}, - {value: 0.2, label: "20 cm"}, - {value: 0.5, label: ".5 m"}, - {value: 1, label: "1 m"}]; - private rotateSnapArray: SnapValue[] = - [{value: 0, label: "Off"}, - {value: 22.5, label: "22.5 Degrees"}, - {value: 45, label: "45 Degrees"}, - {value: 90, label: "90 Degrees"}]; - private turnSnapArray: SnapValue[] = - [{value: 0, label: "Off"}, - {value: 22.5, label: "22.5 Degrees"}, - {value: 45, label: "45 Degrees"}, - {value: 90, label: "90 Degrees"}]; - - public get currentGridSnap(): SnapValue { - return this.gridSnapArray[this.gridSnap || 0]; - } - - public get demoCompleted(): boolean { - return this._demoCompleted || false; - } - - public set demoCompleted(val: boolean) { - this._demoCompleted = val; - this.save(); - } - - public set newRelicKey(val: string) { - this._newRelicKey = val; - this.save(); - } - - private _newRelicAccount: string = null; - - public get newRelicAccount(): string { - return this._newRelicAccount; - } - - public set newRelicAccount(val: string) { - this._newRelicAccount = val; - this.save(); - } - - public get physicsEnabled(): boolean { - return this._physicsEnabled || false; - } - - public set phsyicsEnabled(val: boolean) { - this._physicsEnabled = val; - this.save(); - } - - private static _config: AppConfig; - - public static get config() { - if (!AppConfig._config) { - AppConfig._config = new AppConfig(); - } - return AppConfig._config; - } - - public get currentRotateSnap(): SnapValue { - return this.rotateSnapArray[this.rotateSnap || 0]; - } - - public get currentCreateSnap(): SnapValue { - return this.createSnapArray[this.createSnap || 0]; - } - - public get currentTurnSnap(): SnapValue { - return this.turnSnapArray[this._turnSnap || 0]; - } - - public get currentGridSnapIndex(): number { - return this.gridSnap || 0; - } - - public set currentTurnSnapIndex(val: number) { - this._turnSnap = val; - this.save(); - } - - public set currentGridSnapIndex(val: number) { - this.gridSnap = val; - this.save(); - } - - public get currentCreateSnapIndex(): number { - return this.createSnap || 0; - } - - public set currentCreateSnapIndex(val: number) { - this.createSnap = val; - if (this.currentGridSnapIndex == this.defaultGridSnapIndex) { - this.currentGridSnap.value = this.currentCreateSnap.value / 2; - this.logger.debug("Set grid snap to " + this.currentGridSnap.value); - } - this.save(); - } - - public get currentRotateSnapIndex(): number { - return this.rotateSnap || 0; - } - - public set currentRotateSnapIndex(val: number) { - this.rotateSnap = val; - this.save(); - } - - public get createSnapVal(): Vector3 { - return new Vector3(this.currentCreateSnap.value, this.currentCreateSnap.value, this.currentCreateSnap.value); - } - - public setPersistenceManager(persistenceManager: IPersistenceManager) { + constructor(persistenceManager: IPersistenceManager) { this.persistenceManager = persistenceManager; - this.persistenceManager.configObserver.add(this.configObserver, -1, false, this); + this.persistenceManager.configObserver.add(this.load, -1, false, this, false); } - public gridSnaps(): SnapValue[] { - return this.gridSnapArray; + public get current(): AppConfigType { + if (!this._currentConfig) { + this.persistenceManager.getConfig().then((config) => { + if (!config) { + const newconfig = { + id: 1, + gridSnap: .1, + rotateSnap: 45, + createSnap: .1, + turnSnap: 22.5, + newRelicKey: null, + newRelicAccount: null, + physicsEnabled: false, + demoCompleted: false, + } + this._currentConfig = newconfig; + this.save(); + } else { + this._currentConfig = config; + } + + }); + } + return this._currentConfig; } - public turnSnaps(): SnapValue[] { - return this.turnSnapArray; + public set current(config: AppConfigType) { + this._currentConfig = config; + this.save(); } - public createSnaps(): SnapValue[] { - return this.createSnapArray; + public save() { + this.persistenceManager.setConfig(this._currentConfig); } - public rotateSnaps(): SnapValue[] { - return this.rotateSnapArray; + public load(config: AppConfigType) { + this._currentConfig = config; + this.onConfigChangedObservable.notifyObservers(this._currentConfig); } - public snapGridVal(value: Vector3): Vector3 { - if (this.currentGridSnapIndex == 0) { + public snapGridVal(value: Vector3, snap: number): Vector3 { + if (!snap) { return value; } const position = value.clone(); - position.x = round(position.x, this.currentGridSnap.value); - position.y = round(position.y, this.currentGridSnap.value); - position.z = round(position.z, this.currentGridSnap.value); + position.x = round(value.x, snap); + position.y = round(value.y, snap); + position.z = round(value.z, snap); return position; } - public snapRotateVal(value: Vector3): Vector3 { - if (this.currentRotateSnapIndex == 0) { + public snapRotateVal(value: Vector3, snap: number): Vector3 { + if (!snap) { return value; } const rotation = new Vector3(); - rotation.x = this.snapAngle(value.x); - rotation.y = this.snapAngle(value.y); - rotation.z = this.snapAngle(value.z); + rotation.x = this.snapAngle(value.x, snap); + rotation.y = this.snapAngle(value.y, snap); + rotation.z = this.snapAngle(value.z, snap); return rotation; } - private snapAngle(val: number): number { + private snapAngle(val: number, snap: number): number { + const angle = snap; const deg = Angle.FromRadians(val).degrees(); - const snappedDegrees = round(deg, this.currentRotateSnap.value); - this.logger.debug("deg", val, deg, snappedDegrees, this.currentRotateSnap.value); + const snappedDegrees = round(deg, angle); + this.logger.debug("deg", val, deg, snappedDegrees, angle); return Angle.FromDegrees(snappedDegrees).radians(); } - - private save() { - this.persistenceManager.setConfig( - { - gridSnap: this.currentGridSnap.value, - rotateSnap: this.currentRotateSnap.value, - createSnap: this.currentCreateSnap.value, - turnSnap: this.currentTurnSnap.value, - physicsEnabled: this._physicsEnabled, - newRelicKey: this._newRelicKey, - newRelicAccount: this._newRelicAccount, - demoCompleted: this._demoCompleted - }); - } - - private configObserver(config: AppConfigType) { - if (config) { - if (config.physicsEnabled && config.physicsEnabled != this._physicsEnabled) { - this._physicsEnabled = config.physicsEnabled; - this.logger.debug("Physics enabled changed to " + this._physicsEnabled); - } - if (config.demoCompleted) { - this._demoCompleted = config.demoCompleted; - } - if (config.createSnap != this.currentCreateSnap.value || - config.gridSnap != this.currentGridSnap.value || - config.rotateSnap != this.currentRotateSnap.value) { - this.logger.debug("Config changed", config); - this._turnSnap = this.turnSnapArray.findIndex((snap) => snap.value == config.turnSnap); - if (!this._turnSnap || this._turnSnap == -1) { - this._turnSnap = 0; - } - this.rotateSnap = this.rotateSnapArray.findIndex((snap) => snap.value == config.rotateSnap); - if (!this.rotateSnap || this.rotateSnap == -1) { - this.rotateSnap = 0; - } - this.createSnap = this.createSnapArray.findIndex((snap) => snap.value == config.createSnap); - if (!this.createSnap || this.createSnap == -1) { - this.createSnap = 0; - } - const gridSnap = this.gridSnapArray.findIndex((snap) => snap.value == config.gridSnap); - if (gridSnap == -1) { - this.gridSnap = this.defaultGridSnapIndex; - this.currentGridSnap.value = config.gridSnap; - } - } else { - this.logger.debug("Config unchanged", config); - } - } else { - this.logger.debug("Config not set"); - } - } } \ No newline at end of file diff --git a/src/util/customEnvironment.ts b/src/util/customEnvironment.ts index fca23d7..16e1407 100644 --- a/src/util/customEnvironment.ts +++ b/src/util/customEnvironment.ts @@ -7,21 +7,24 @@ import { PhysicsAggregate, PhysicsShapeType, Scene, - Texture + Sound, + Texture, + Vector3 } from "@babylonjs/core"; import {CustomPhysics} from "./customPhysics"; import {DiaSounds} from "./diaSounds"; +import {AppConfig} from "./appConfig"; + export class CustomEnvironment { private readonly scene: Scene; private readonly name: string; private readonly _groundMeshObservable: Observable = new Observable(); - constructor(scene: Scene, name: string = "default") { + constructor(scene: Scene, name: string = "default", config: AppConfig) { this.scene = scene; this.name = name; - - const physics = new CustomPhysics(this.scene); + const physics = new CustomPhysics(this.scene, config); physics .initializeAsync() .then(() => { @@ -32,7 +35,29 @@ export class CustomEnvironment { '/assets/textures/outdoor_field2.jpeg', {}, scene); try { - new DiaSounds(scene); + const sounds = new DiaSounds(scene); + window.setTimeout((sound) => { + sound.play() + }, 2000, sounds.background); + const birds: Array = [sounds.birds, sounds.dove]; + window.setInterval((sounds: Array) => { + if (Math.random() < .6) { + return; + } + const sound = Math.floor(Math.random() * sounds.length); + const x = Math.floor(Math.random() * 20); + const z = Math.floor(Math.random() * 20); + + const position = new Vector3(x, 0, z); + if (sounds[sound].isPlaying) { + + } else { + sounds[sound].setPosition(position); + sounds[sound].setVolume(Math.random() * .5); + sounds[sound].play(); + } + + }, 2000, birds); } catch (error) { console.log(error); } diff --git a/src/util/customPhysics.ts b/src/util/customPhysics.ts index 6d0e35d..ef1caa3 100644 --- a/src/util/customPhysics.ts +++ b/src/util/customPhysics.ts @@ -4,9 +4,11 @@ import {AppConfig} from "./appConfig"; export class CustomPhysics { private scene: Scene; + private config: AppConfig; - constructor(scene: Scene) { + constructor(scene: Scene, config: AppConfig) { this.scene = scene; + this.config = config; } public async initializeAsync() { @@ -24,10 +26,10 @@ export class CustomPhysics { if (true) { body.disablePreStep = false; const pos: Vector3 = body.getObjectCenterWorld(); - const val: Vector3 = AppConfig.config.snapGridVal(pos); + const val: Vector3 = this.config.snapGridVal(pos); body.transformNode.position.set(val.x, val.y, val.z); const rot: Quaternion = - Quaternion.FromEulerVector(AppConfig.config.snapRotateVal(body.transformNode.rotationQuaternion.toEulerAngles())) + Quaternion.FromEulerVector(this.config.snapRotateVal(body.transformNode.rotationQuaternion.toEulerAngles())) body.transformNode.rotationQuaternion.set( rot.x, rot.y, rot.z, rot.w diff --git a/src/util/diaSounds.ts b/src/util/diaSounds.ts index dc0c0ea..4b920bb 100644 --- a/src/util/diaSounds.ts +++ b/src/util/diaSounds.ts @@ -8,32 +8,16 @@ export class DiaSounds { public get tick() { return new Sound("tick", '/assets/sounds/tick.mp3', this.scene); } + private volume: number = 0.8; - private readonly _bounce; + private readonly _bounce: Sound; + private readonly _background: Sound; private readonly _enter: Sound; public get enter() { return this._enter; } - private readonly _exit: Sound; - - public get exit() { - return this._exit; - } - - private readonly _high: Sound; - - public get high() { - return this._high; - } - - private readonly _low: Sound; - - public get low() { - return this._low; - } - constructor(scene: Scene) { this.scene = scene; this._enter = new Sound("enter", "/assets/sounds/sounds.mp3", this.scene, null, { @@ -72,15 +56,62 @@ export class DiaSounds { offset: 0, length: 0.990 }); - - - this._birds = new Sound("birds", "/assets/sounds/birds.mp3", this.scene, null, { - autoplay: true, + this._background = new Sound("brown", "/assets/sounds/brown.mp3", this.scene, null, { + autoplay: false, + volume: 1, loop: true }); + this._birds = new Sound("warbler", "/assets/sounds/warbler.mp3", this.scene, null, { + spatialSound: true, + autoplay: false, + volume: .5, + loop: false + }); + this.birds.switchPanningModelToHRTF(); + this.birds.maxDistance = 40; + this._dove = new Sound("dove", "/assets/sounds/dove.mp3", this.scene, null, { + spatialSound: true, + autoplay: false, + volume: .5, + loop: false + }); + this._dove.switchPanningModelToHRTF(); + this._dove.maxDistance = 40; + //this._enter.autoplay = true; } + public get background(): Sound { + return this._background; + } + + private readonly _exit: Sound; + + public get exit() { + return this._exit; + } + + private readonly _high: Sound; + + public get high() { + return this._high; + } + + private readonly _low: Sound; + + public get low() { + return this._low; + } + + public get birds(): Sound { + return this._birds; + } + + _dove: Sound; + public get dove() { + return this._dove; + } + public get bounce() { const bounce = this._bounce.clone(); bounce.updateOptions({offset: 0, volume: this.volume, length: .990});