Added tick sound

This commit is contained in:
Michael Mainguy 2023-07-29 07:54:49 -05:00
parent 14363bc1ca
commit 4c52d7b1d7
10 changed files with 129 additions and 54 deletions

View File

@ -39,11 +39,7 @@ export class App {
constructor() {
const config = AppConfig.config;
log.setLevel('info');
log.getLogger('AppConfig').setLevel('debug');
log.getLogger('IndexdbPersistenceManager').setLevel('debug');
log.setLevel('debug');
const canvas = document.createElement("canvas");
canvas.style.width = "100%";
canvas.style.height = "100%";

View File

@ -1,7 +1,5 @@
import {
AbstractMesh,
InstancedMesh,
Mesh,
Scene,
Vector3,
WebXRControllerComponent,
@ -13,6 +11,7 @@ import {DiagramManager} from "../diagram/diagramManager";
import {DiagramEvent, DiagramEventType} from "../diagram/diagramEntity";
import log from "loglevel";
import {AppConfig} from "../util/appConfig";
import {Controllers} from "./controllers";
export class Base {
@ -28,12 +27,14 @@ export class Base {
protected readonly xr: WebXRDefaultExperience;
protected readonly diagramManager: DiagramManager;
private logger: log.Logger;
constructor(controller: WebXRInputSource,
scene: Scene,
xr: WebXRDefaultExperience,
diagramManager: DiagramManager) {
this.logger = log.getLogger('Base');
this.controller = controller;
this.scene = scene;
this.xr = xr;
this.diagramManager = diagramManager;
@ -47,6 +48,15 @@ export class Base {
}
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() {
@ -59,15 +69,6 @@ export class Base {
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) {
grip.onButtonStateChangedObservable.add(() => {
if (grip.changes.pressed) {
@ -98,7 +99,7 @@ export class Base {
this.grabbedMesh = mesh;
} else {
const config = AppConfig.config;
const newMesh = this.createCopy(mesh);
const newMesh = this.diagramManager.createCopy(mesh);
newMesh.position = mesh.absolutePosition.clone();
newMesh.rotation = mesh.absoluteRotationQuaternion.toEulerAngles().clone();
newMesh.scaling = config.createSnapVal;

View File

@ -2,7 +2,8 @@ import {AbstractMesh, Observable, TransformNode} from "@babylonjs/core";
export type ControllerEventType = {
type: string,
value?: number
value?: number,
gripId?: string;
}
export class Controllers {
public static movable: TransformNode | AbstractMesh;

View File

@ -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 {IPersistenceManager} from "./persistenceManager";
import {MeshConverter} from "./meshConverter";
import log from "loglevel";
import {Controllers} from "../controllers/controllers";
export class DiagramManager {
public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable();
@ -11,15 +24,7 @@ export class DiagramManager {
private readonly scene: Scene;
private xr: WebXRExperienceHelper;
constructor(scene: Scene, xr: WebXRExperienceHelper) {
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");
}
private readonly tick: Sound;
public setPersistenceManager(persistenceManager: IPersistenceManager) {
this.persistenceManager = persistenceManager;
@ -33,11 +38,56 @@ export class DiagramManager {
}
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) {
//const mesh = Toolbox.instance.newMesh(ToolType[Object.entries(ToolType).find(e => e[1] == event.template)[0]], event.id);
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);
mesh.actionManager = this.actionManager;
if (event.parent) {
mesh.parent = this.scene.getMeshById(event.parent);
}
@ -66,7 +116,23 @@ export class DiagramManager {
this.getPersistenceManager()?.modify(mesh);
break;
case DiagramEventType.CHANGECOLOR:
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;
case DiagramEventType.REMOVE:
if (mesh) {

View File

@ -4,7 +4,7 @@ import {DiagramEntity} from "./diagramEntity";
import Dexie from "dexie";
import {MeshConverter} from "./meshConverter";
import log from "loglevel";
import {AppConfigType} from "../util/appConfig";
import {AppConfigType} from "../util/appConfigType";
export class IndexdbPersistenceManager implements IPersistenceManager {
@ -16,8 +16,8 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
constructor(name: string) {
this.db = new Dexie(name);
const version = 2;
this.db.version(2).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({config: "id,gridSnap,rotateSnap,createSnap"});
this.db.version(version).stores({entities: "id,position,rotation,last_seen,template,text,scale,color"});
this.logger.debug("IndexdbPersistenceManager constructed");
}
@ -83,8 +83,12 @@ export class IndexdbPersistenceManager implements IPersistenceManager {
}
public changeColor(oldColor, newColor) {
if (!oldColor || !newColor) {
this.logger.error("changeColor called with null color, early return");
if (!oldColor) {
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;
}
this.logger.debug(`changeColor ${oldColor.toHexString()} to ${newColor.toHexString()}`);

View File

@ -10,7 +10,6 @@ import {
StandardMaterial
} from "@babylonjs/core";
import {v4 as uuidv4} from 'uuid';
import {Toolbox} from "../toolbox/toolbox";
import log from "loglevel";
@ -61,14 +60,6 @@ export class MeshConverter {
}
} else {
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());
plane.material = mat;
plane.billboardMode = Mesh.BILLBOARDMODE_ALL;
//textNode = this.updateTextNode(mesh, entity.text);
const yOffset = mesh.getBoundingInfo().boundingSphere.radius;
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;
}
}

View File

@ -1,6 +1,7 @@
import {AbstractMesh, Color3, Observable} from "@babylonjs/core";
import {DiagramEntity} from "./diagramEntity";
import {AppConfigType} from "../util/appConfig";
import {AppConfigType} from "../util/appConfigType";
export interface IPersistenceManager {
add(mesh: AbstractMesh);

View File

@ -40,6 +40,12 @@ export class Toolbox {
constructor(scene: Scene, xr: WebXRExperienceHelper, diagramManager: DiagramManager) {
this.scene = scene;
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);
@ -62,8 +68,10 @@ export class Toolbox {
} else {
this.buildToolbox();
}
Toolbox.instance = this;
}
private buildToolbox() {
this.node.position.y = -.2;
this.node.scaling= new Vector3(0.5, 0.5, 0.5);

View File

@ -2,17 +2,13 @@ import {Angle, Vector3} from "@babylonjs/core";
import round from "round";
import log from "loglevel";
import {IPersistenceManager} from "../diagram/persistenceManager";
import {AppConfigType} from "./appConfigType";
export type SnapValue = {
value: number,
label: string
}
export type AppConfigType = {
id?: number,
gridSnap: number,
rotateSnap: number,
createSnap: number
}
export class AppConfig {
private readonly logger = log.getLogger('AppConfig');

View File

@ -0,0 +1,6 @@
export type AppConfigType = {
id?: number,
gridSnap: number,
rotateSnap: number,
createSnap: number
}