Added tick sound
This commit is contained in:
parent
14363bc1ca
commit
4c52d7b1d7
@ -39,11 +39,7 @@ export class App {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const config = AppConfig.config;
|
const config = AppConfig.config;
|
||||||
|
log.setLevel('debug');
|
||||||
log.setLevel('info');
|
|
||||||
log.getLogger('AppConfig').setLevel('debug');
|
|
||||||
log.getLogger('IndexdbPersistenceManager').setLevel('debug');
|
|
||||||
|
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
canvas.style.width = "100%";
|
canvas.style.width = "100%";
|
||||||
canvas.style.height = "100%";
|
canvas.style.height = "100%";
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
AbstractMesh,
|
AbstractMesh,
|
||||||
InstancedMesh,
|
|
||||||
Mesh,
|
|
||||||
Scene,
|
Scene,
|
||||||
Vector3,
|
Vector3,
|
||||||
WebXRControllerComponent,
|
WebXRControllerComponent,
|
||||||
@ -13,6 +11,7 @@ import {DiagramManager} from "../diagram/diagramManager";
|
|||||||
import {DiagramEvent, DiagramEventType} from "../diagram/diagramEntity";
|
import {DiagramEvent, DiagramEventType} from "../diagram/diagramEntity";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {AppConfig} from "../util/appConfig";
|
import {AppConfig} from "../util/appConfig";
|
||||||
|
import {Controllers} from "./controllers";
|
||||||
|
|
||||||
|
|
||||||
export class Base {
|
export class Base {
|
||||||
@ -28,12 +27,14 @@ export class Base {
|
|||||||
|
|
||||||
protected readonly xr: WebXRDefaultExperience;
|
protected readonly xr: WebXRDefaultExperience;
|
||||||
protected readonly diagramManager: DiagramManager;
|
protected readonly diagramManager: DiagramManager;
|
||||||
|
private logger: log.Logger;
|
||||||
constructor(controller: WebXRInputSource,
|
constructor(controller: WebXRInputSource,
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
xr: WebXRDefaultExperience,
|
xr: WebXRDefaultExperience,
|
||||||
diagramManager: DiagramManager) {
|
diagramManager: DiagramManager) {
|
||||||
|
this.logger = log.getLogger('Base');
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
|
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.xr = xr;
|
this.xr = xr;
|
||||||
this.diagramManager = diagramManager;
|
this.diagramManager = diagramManager;
|
||||||
@ -47,6 +48,15 @@ export class Base {
|
|||||||
}
|
}
|
||||||
this.initGrip(init.components['xr-standard-squeeze']);
|
this.initGrip(init.components['xr-standard-squeeze']);
|
||||||
});
|
});
|
||||||
|
Controllers.controllerObserver.add((event) => {
|
||||||
|
if (event.type == 'pulse') {
|
||||||
|
this.logger.debug(event);
|
||||||
|
if (event.gripId == this.controller.grip.id) {
|
||||||
|
this.controller.motionController.pulse(.25, 30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public disable() {
|
public disable() {
|
||||||
@ -59,15 +69,6 @@ export class Base {
|
|||||||
this.controller.pointer.setEnabled(true);
|
this.controller.pointer.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createCopy(mesh: AbstractMesh) {
|
|
||||||
if (!mesh.isAnInstance) {
|
|
||||||
return new InstancedMesh("new", (mesh as Mesh));
|
|
||||||
} else {
|
|
||||||
return new InstancedMesh("new", (mesh as InstancedMesh).sourceMesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private initGrip(grip: WebXRControllerComponent) {
|
private initGrip(grip: WebXRControllerComponent) {
|
||||||
grip.onButtonStateChangedObservable.add(() => {
|
grip.onButtonStateChangedObservable.add(() => {
|
||||||
if (grip.changes.pressed) {
|
if (grip.changes.pressed) {
|
||||||
@ -98,7 +99,7 @@ export class Base {
|
|||||||
this.grabbedMesh = mesh;
|
this.grabbedMesh = mesh;
|
||||||
} else {
|
} else {
|
||||||
const config = AppConfig.config;
|
const config = AppConfig.config;
|
||||||
const newMesh = this.createCopy(mesh);
|
const newMesh = this.diagramManager.createCopy(mesh);
|
||||||
newMesh.position = mesh.absolutePosition.clone();
|
newMesh.position = mesh.absolutePosition.clone();
|
||||||
newMesh.rotation = mesh.absoluteRotationQuaternion.toEulerAngles().clone();
|
newMesh.rotation = mesh.absoluteRotationQuaternion.toEulerAngles().clone();
|
||||||
newMesh.scaling = config.createSnapVal;
|
newMesh.scaling = config.createSnapVal;
|
||||||
|
|||||||
@ -2,7 +2,8 @@ import {AbstractMesh, Observable, TransformNode} from "@babylonjs/core";
|
|||||||
|
|
||||||
export type ControllerEventType = {
|
export type ControllerEventType = {
|
||||||
type: string,
|
type: string,
|
||||||
value?: number
|
value?: number,
|
||||||
|
gripId?: string;
|
||||||
}
|
}
|
||||||
export class Controllers {
|
export class Controllers {
|
||||||
public static movable: TransformNode | AbstractMesh;
|
public static movable: TransformNode | AbstractMesh;
|
||||||
|
|||||||
@ -1,8 +1,21 @@
|
|||||||
import {Observable, Scene, WebXRExperienceHelper} from "@babylonjs/core";
|
import {
|
||||||
|
AbstractMesh,
|
||||||
|
ActionManager,
|
||||||
|
Color3,
|
||||||
|
ExecuteCodeAction,
|
||||||
|
InstancedMesh,
|
||||||
|
Mesh,
|
||||||
|
Observable,
|
||||||
|
PlaySoundAction,
|
||||||
|
Scene,
|
||||||
|
Sound,
|
||||||
|
WebXRExperienceHelper
|
||||||
|
} from "@babylonjs/core";
|
||||||
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./diagramEntity";
|
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./diagramEntity";
|
||||||
import {IPersistenceManager} from "./persistenceManager";
|
import {IPersistenceManager} from "./persistenceManager";
|
||||||
import {MeshConverter} from "./meshConverter";
|
import {MeshConverter} from "./meshConverter";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
|
import {Controllers} from "../controllers/controllers";
|
||||||
|
|
||||||
export class DiagramManager {
|
export class DiagramManager {
|
||||||
public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable();
|
public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable();
|
||||||
@ -11,15 +24,7 @@ export class DiagramManager {
|
|||||||
private readonly scene: Scene;
|
private readonly scene: Scene;
|
||||||
private xr: WebXRExperienceHelper;
|
private xr: WebXRExperienceHelper;
|
||||||
|
|
||||||
constructor(scene: Scene, xr: WebXRExperienceHelper) {
|
private readonly tick: Sound;
|
||||||
this.scene = scene;
|
|
||||||
this.xr = xr;
|
|
||||||
if (this.onDiagramEventObservable.hasObservers()) {
|
|
||||||
this.logger.warn("onDiagramEventObservable already has Observers, you should be careful");
|
|
||||||
}
|
|
||||||
this.onDiagramEventObservable.add(this.onDiagramEvent, -1, true, this);
|
|
||||||
this.logger.debug("DiagramManager constructed");
|
|
||||||
}
|
|
||||||
|
|
||||||
public setPersistenceManager(persistenceManager: IPersistenceManager) {
|
public setPersistenceManager(persistenceManager: IPersistenceManager) {
|
||||||
this.persistenceManager = persistenceManager;
|
this.persistenceManager = persistenceManager;
|
||||||
@ -33,11 +38,56 @@ export class DiagramManager {
|
|||||||
}
|
}
|
||||||
return this.persistenceManager;
|
return this.persistenceManager;
|
||||||
}
|
}
|
||||||
|
private readonly actionManager: ActionManager;
|
||||||
|
|
||||||
|
constructor(scene: Scene, xr: WebXRExperienceHelper) {
|
||||||
|
this.scene = scene;
|
||||||
|
this.xr = xr;
|
||||||
|
this.tick = new Sound("tick", './tick.mp3', this.scene);
|
||||||
|
this.tick.setVolume(.3);
|
||||||
|
this.actionManager = new ActionManager(this.scene);
|
||||||
|
this.actionManager.registerAction(
|
||||||
|
new PlaySoundAction(ActionManager.OnPointerOverTrigger, this.tick));
|
||||||
|
this.actionManager.registerAction(
|
||||||
|
new ExecuteCodeAction(ActionManager.OnPointerOverTrigger, (evt) => {
|
||||||
|
Controllers.controllerObserver.notifyObservers({
|
||||||
|
type: 'pulse',
|
||||||
|
gripId: evt?.additionalData?.pickResult?.gripTransform?.id
|
||||||
|
})
|
||||||
|
this.logger.debug(evt);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (this.onDiagramEventObservable.hasObservers()) {
|
||||||
|
this.logger.warn("onDiagramEventObservable already has Observers, you should be careful");
|
||||||
|
}
|
||||||
|
this.onDiagramEventObservable.add(this.onDiagramEvent, -1, true, this);
|
||||||
|
this.logger.debug("DiagramManager constructed");
|
||||||
|
}
|
||||||
|
|
||||||
|
public createCopy(mesh: AbstractMesh): AbstractMesh {
|
||||||
|
let newMesh;
|
||||||
|
if (!mesh.isAnInstance) {
|
||||||
|
newMesh = new InstancedMesh("new", (mesh as Mesh));
|
||||||
|
} else {
|
||||||
|
newMesh = new InstancedMesh("new", (mesh as InstancedMesh).sourceMesh);
|
||||||
|
}
|
||||||
|
newMesh.actionManager = this.actionManager;
|
||||||
|
return newMesh;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private onRemoteEvent(event: DiagramEntity) {
|
private onRemoteEvent(event: DiagramEntity) {
|
||||||
//const mesh = Toolbox.instance.newMesh(ToolType[Object.entries(ToolType).find(e => e[1] == event.template)[0]], event.id);
|
|
||||||
this.logger.debug(event);
|
this.logger.debug(event);
|
||||||
|
const toolMesh = this.scene.getMeshById("tool-" + event.template + "-" + event.color);
|
||||||
|
if (!toolMesh) {
|
||||||
|
log.debug('no mesh found for ' + event.template + "-" + event.color, 'adding it');
|
||||||
|
this.onDiagramEventObservable.notifyObservers({
|
||||||
|
type: DiagramEventType.CHANGECOLOR,
|
||||||
|
entity: event
|
||||||
|
});
|
||||||
|
}
|
||||||
const mesh = MeshConverter.fromDiagramEntity(event, this.scene);
|
const mesh = MeshConverter.fromDiagramEntity(event, this.scene);
|
||||||
|
mesh.actionManager = this.actionManager;
|
||||||
if (event.parent) {
|
if (event.parent) {
|
||||||
mesh.parent = this.scene.getMeshById(event.parent);
|
mesh.parent = this.scene.getMeshById(event.parent);
|
||||||
}
|
}
|
||||||
@ -66,7 +116,23 @@ export class DiagramManager {
|
|||||||
this.getPersistenceManager()?.modify(mesh);
|
this.getPersistenceManager()?.modify(mesh);
|
||||||
break;
|
break;
|
||||||
case DiagramEventType.CHANGECOLOR:
|
case DiagramEventType.CHANGECOLOR:
|
||||||
this.getPersistenceManager()?.changeColor(event.oldColor, event.newColor);
|
if (!event.oldColor) {
|
||||||
|
if (!event.newColor) {
|
||||||
|
this.getPersistenceManager()?.changeColor(null, Color3.FromHexString(event.entity.color));
|
||||||
|
this.logger.info("Recieved color change event, sending entity color as new color");
|
||||||
|
} else {
|
||||||
|
this.logger.info("Recieved color change event, no old color, sending new color");
|
||||||
|
this.getPersistenceManager()?.changeColor(null, event.newColor);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (event.newColor) {
|
||||||
|
this.logger.info("changing color from " + event.oldColor + " to " + event.newColor);
|
||||||
|
this.getPersistenceManager()?.changeColor(event.oldColor, event.newColor);
|
||||||
|
} else {
|
||||||
|
this.logger.error("changing color from " + event.oldColor + ", but no new color found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DiagramEventType.REMOVE:
|
case DiagramEventType.REMOVE:
|
||||||
if (mesh) {
|
if (mesh) {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {DiagramEntity} from "./diagramEntity";
|
|||||||
import Dexie from "dexie";
|
import Dexie from "dexie";
|
||||||
import {MeshConverter} from "./meshConverter";
|
import {MeshConverter} from "./meshConverter";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {AppConfigType} from "../util/appConfig";
|
import {AppConfigType} from "../util/appConfigType";
|
||||||
|
|
||||||
|
|
||||||
export class IndexdbPersistenceManager implements IPersistenceManager {
|
export class IndexdbPersistenceManager implements IPersistenceManager {
|
||||||
@ -16,8 +16,8 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
|
|||||||
constructor(name: string) {
|
constructor(name: string) {
|
||||||
this.db = new Dexie(name);
|
this.db = new Dexie(name);
|
||||||
const version = 2;
|
const version = 2;
|
||||||
this.db.version(2).stores({config: "id,gridSnap,rotateSnap,createSnap"});
|
this.db.version(version).stores({config: "id,gridSnap,rotateSnap,createSnap"});
|
||||||
this.db.version(2).stores({entities: "id,position,rotation,last_seen,template,text,scale,color"});
|
this.db.version(version).stores({entities: "id,position,rotation,last_seen,template,text,scale,color"});
|
||||||
this.logger.debug("IndexdbPersistenceManager constructed");
|
this.logger.debug("IndexdbPersistenceManager constructed");
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -83,8 +83,12 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public changeColor(oldColor, newColor) {
|
public changeColor(oldColor, newColor) {
|
||||||
if (!oldColor || !newColor) {
|
if (!oldColor) {
|
||||||
this.logger.error("changeColor called with null color, early return");
|
if (!newColor) {
|
||||||
|
this.logger.error("changeColor called with no new color, early return");
|
||||||
|
} else {
|
||||||
|
this.logger.info("changeColor called with no old Color, new color added to diagram, early return");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.logger.debug(`changeColor ${oldColor.toHexString()} to ${newColor.toHexString()}`);
|
this.logger.debug(`changeColor ${oldColor.toHexString()} to ${newColor.toHexString()}`);
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import {
|
|||||||
StandardMaterial
|
StandardMaterial
|
||||||
} from "@babylonjs/core";
|
} from "@babylonjs/core";
|
||||||
import {v4 as uuidv4} from 'uuid';
|
import {v4 as uuidv4} from 'uuid';
|
||||||
import {Toolbox} from "../toolbox/toolbox";
|
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
|
|
||||||
|
|
||||||
@ -61,14 +60,6 @@ export class MeshConverter {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug('no mesh found for ' + entity.template + "-" + entity.color);
|
log.debug('no mesh found for ' + entity.template + "-" + entity.color);
|
||||||
Toolbox.instance.updateToolbox(entity.color);
|
|
||||||
mesh = scene.getMeshById("tool-" + entity.template + "-" + entity.color);
|
|
||||||
if (!mesh) {
|
|
||||||
log.debug('no mesh found for ' + entity.template + "-" + entity.color);
|
|
||||||
} else {
|
|
||||||
mesh = new InstancedMesh(entity.id, (mesh as Mesh));
|
|
||||||
}
|
|
||||||
//Toolbox.instance.buildTool(Toolbox.getToolTypeFromString(entity.template), entity.color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,9 +142,14 @@ export class MeshConverter {
|
|||||||
const plane = MeshBuilder.CreatePlane("text", {width: planeWidth, height: height}, mesh.getScene());
|
const plane = MeshBuilder.CreatePlane("text", {width: planeWidth, height: height}, mesh.getScene());
|
||||||
plane.material = mat;
|
plane.material = mat;
|
||||||
plane.billboardMode = Mesh.BILLBOARDMODE_ALL;
|
plane.billboardMode = Mesh.BILLBOARDMODE_ALL;
|
||||||
//textNode = this.updateTextNode(mesh, entity.text);
|
|
||||||
|
|
||||||
|
const yOffset = mesh.getBoundingInfo().boundingSphere.radius;
|
||||||
plane.parent = mesh;
|
plane.parent = mesh;
|
||||||
plane.position.y = .5 + (.125 / 2);
|
plane.position.y = yOffset;
|
||||||
|
plane.scaling.y = 1 / mesh.scaling.y;
|
||||||
|
plane.scaling.x = 1 / mesh.scaling.x;
|
||||||
|
plane.scaling.z = 1 / mesh.scaling.z;
|
||||||
return plane;
|
return plane;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import {AbstractMesh, Color3, Observable} from "@babylonjs/core";
|
import {AbstractMesh, Color3, Observable} from "@babylonjs/core";
|
||||||
import {DiagramEntity} from "./diagramEntity";
|
import {DiagramEntity} from "./diagramEntity";
|
||||||
import {AppConfigType} from "../util/appConfig";
|
import {AppConfigType} from "../util/appConfigType";
|
||||||
|
|
||||||
|
|
||||||
export interface IPersistenceManager {
|
export interface IPersistenceManager {
|
||||||
add(mesh: AbstractMesh);
|
add(mesh: AbstractMesh);
|
||||||
|
|||||||
@ -40,6 +40,12 @@ export class Toolbox {
|
|||||||
constructor(scene: Scene, xr: WebXRExperienceHelper, diagramManager: DiagramManager) {
|
constructor(scene: Scene, xr: WebXRExperienceHelper, diagramManager: DiagramManager) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.diagramManager = diagramManager;
|
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.addPanel = new StackPanel3D();
|
||||||
this.manager = new GUI3DManager(scene);
|
this.manager = new GUI3DManager(scene);
|
||||||
this.manager.addControl(this.addPanel);
|
this.manager.addControl(this.addPanel);
|
||||||
@ -62,8 +68,10 @@ export class Toolbox {
|
|||||||
} else {
|
} else {
|
||||||
this.buildToolbox();
|
this.buildToolbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
Toolbox.instance = this;
|
Toolbox.instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private buildToolbox() {
|
private buildToolbox() {
|
||||||
this.node.position.y = -.2;
|
this.node.position.y = -.2;
|
||||||
this.node.scaling= new Vector3(0.5, 0.5, 0.5);
|
this.node.scaling= new Vector3(0.5, 0.5, 0.5);
|
||||||
|
|||||||
@ -2,17 +2,13 @@ import {Angle, Vector3} from "@babylonjs/core";
|
|||||||
import round from "round";
|
import round from "round";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {IPersistenceManager} from "../diagram/persistenceManager";
|
import {IPersistenceManager} from "../diagram/persistenceManager";
|
||||||
|
import {AppConfigType} from "./appConfigType";
|
||||||
|
|
||||||
export type SnapValue = {
|
export type SnapValue = {
|
||||||
value: number,
|
value: number,
|
||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
export type AppConfigType = {
|
|
||||||
id?: number,
|
|
||||||
gridSnap: number,
|
|
||||||
rotateSnap: number,
|
|
||||||
createSnap: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AppConfig {
|
export class AppConfig {
|
||||||
private readonly logger = log.getLogger('AppConfig');
|
private readonly logger = log.getLogger('AppConfig');
|
||||||
|
|||||||
6
src/util/appConfigType.ts
Normal file
6
src/util/appConfigType.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export type AppConfigType = {
|
||||||
|
id?: number,
|
||||||
|
gridSnap: number,
|
||||||
|
rotateSnap: number,
|
||||||
|
createSnap: number
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user