Removed dead code.
This commit is contained in:
parent
53ca47d63e
commit
60758ed84d
@ -9,7 +9,7 @@ import {
|
|||||||
import {DiagramManager} from "../diagram/diagramManager";
|
import {DiagramManager} from "../diagram/diagramManager";
|
||||||
import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity";
|
import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {ControllerEventType, Controllers} from "./controllers";
|
|
||||||
import {grabAndClone} from "./functions/grabAndClone";
|
import {grabAndClone} from "./functions/grabAndClone";
|
||||||
import {ClickMenu} from "../menus/clickMenu";
|
import {ClickMenu} from "../menus/clickMenu";
|
||||||
import {motionControllerObserver} from "./functions/motionControllerObserver";
|
import {motionControllerObserver} from "./functions/motionControllerObserver";
|
||||||
@ -21,10 +21,13 @@ import {MeshTypeEnum} from "../diagram/types/meshTypeEnum";
|
|||||||
import {getMeshType} from "./functions/getMeshType";
|
import {getMeshType} from "./functions/getMeshType";
|
||||||
import {viewOnly} from "../util/functions/getPath";
|
import {viewOnly} from "../util/functions/getPath";
|
||||||
|
|
||||||
|
import {ControllerEventType} from "./types/controllerEventType";
|
||||||
|
import {controllerObservable} from "./controllers";
|
||||||
|
|
||||||
const CLICK_TIME = 300;
|
const CLICK_TIME = 300;
|
||||||
|
|
||||||
|
|
||||||
export class Base {
|
export abstract class AbstractController {
|
||||||
static stickVector = Vector3.Zero();
|
static stickVector = Vector3.Zero();
|
||||||
protected readonly scene: Scene;
|
protected readonly scene: Scene;
|
||||||
protected readonly xr: WebXRDefaultExperience;
|
protected readonly xr: WebXRDefaultExperience;
|
||||||
@ -34,7 +37,7 @@ export class Base {
|
|||||||
protected grabbedObject: DiagramObject = null;
|
protected grabbedObject: DiagramObject = null;
|
||||||
protected grabbedMesh: AbstractMesh = null;
|
protected grabbedMesh: AbstractMesh = null;
|
||||||
protected grabbedMeshType: MeshTypeEnum = null;
|
protected grabbedMeshType: MeshTypeEnum = null;
|
||||||
protected controllers: Controllers;
|
|
||||||
|
|
||||||
private readonly _logger = log.getLogger('Base');
|
private readonly _logger = log.getLogger('Base');
|
||||||
private _clickStart: number = 0;
|
private _clickStart: number = 0;
|
||||||
@ -48,7 +51,6 @@ export class Base {
|
|||||||
diagramManager: DiagramManager) {
|
diagramManager: DiagramManager) {
|
||||||
this._logger.debug('Base Controller Constructor called');
|
this._logger.debug('Base Controller Constructor called');
|
||||||
this.xrInputSource = controller;
|
this.xrInputSource = controller;
|
||||||
this.controllers = diagramManager.controllers;
|
|
||||||
this.scene = DefaultScene.Scene;
|
this.scene = DefaultScene.Scene;
|
||||||
this.xr = xr;
|
this.xr = xr;
|
||||||
|
|
||||||
@ -66,7 +68,7 @@ export class Base {
|
|||||||
|
|
||||||
//@TODO THis works, but it uses initGrip, not sure if this is the best idea
|
//@TODO THis works, but it uses initGrip, not sure if this is the best idea
|
||||||
this.xrInputSource.onMotionControllerInitObservable.add(motionControllerObserver, -1, false, this);
|
this.xrInputSource.onMotionControllerInitObservable.add(motionControllerObserver, -1, false, this);
|
||||||
this.controllers.controllerObservable.add((event) => {
|
controllerObservable.add((event) => {
|
||||||
this._logger.debug(event);
|
this._logger.debug(event);
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case ControllerEventType.PULSE:
|
case ControllerEventType.PULSE:
|
||||||
@ -1,41 +1,6 @@
|
|||||||
import {AbstractMesh, Observable, TransformNode, Vector3, WebXRInputSource} from "@babylonjs/core";
|
import {AbstractMesh, Observable, TransformNode} from "@babylonjs/core";
|
||||||
|
import {ControllerEvent} from "./types/controllerEvent";
|
||||||
|
|
||||||
export type ControllerEvent = {
|
|
||||||
type: ControllerEventType,
|
|
||||||
value?: number,
|
|
||||||
startPosition?: Vector3,
|
|
||||||
endPosition?: Vector3,
|
|
||||||
duration?: number,
|
|
||||||
gripId?: string;
|
|
||||||
controller?: WebXRInputSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ControllerEventType {
|
export var movable: TransformNode | AbstractMesh;
|
||||||
GRIP = 'grip',
|
export const controllerObservable: Observable<ControllerEvent> = new Observable();
|
||||||
HIDE = 'hide',
|
|
||||||
SHOW = 'show',
|
|
||||||
PULSE = 'pulse',
|
|
||||||
SQUEEZE = 'squeeze',
|
|
||||||
CLICK = 'click',
|
|
||||||
Y_BUTTON = 'y-button',
|
|
||||||
X_BUTTON = 'x-button',
|
|
||||||
A_BUTTON = 'a-button',
|
|
||||||
B_BUTTON = 'b-button',
|
|
||||||
THUMBSTICK = 'thumbstick',
|
|
||||||
THUMBSTICK_CHANGED = 'thumbstickChanged',
|
|
||||||
DECREASE_VELOCITY = 'decreaseVelocity',
|
|
||||||
INCREASE_VELOCITY = 'decreaseVelocity',
|
|
||||||
LEFT_RIGHT = 'leftright',
|
|
||||||
FORWARD_BACK = 'forwardback',
|
|
||||||
TURN = 'turn',
|
|
||||||
UP_DOWN = 'updown',
|
|
||||||
TRIGGER = 'trigger',
|
|
||||||
MENU = 'menu',
|
|
||||||
MOTION = 'motion',
|
|
||||||
GAZEPOINT = 'gazepoint',
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Controllers {
|
|
||||||
public movable: TransformNode | AbstractMesh;
|
|
||||||
public readonly controllerObservable: Observable<ControllerEvent> = new Observable();
|
|
||||||
}
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
import {HavokPlugin} from "@babylonjs/core";
|
|
||||||
import {DefaultScene} from "../../defaultScene";
|
|
||||||
import log from "loglevel";
|
|
||||||
|
|
||||||
|
|
||||||
export function beforeRenderObserver() {
|
|
||||||
if (this?.grabbedMesh?.physicsBody) {
|
|
||||||
const scene = DefaultScene.Scene;
|
|
||||||
const hk = (scene.getPhysicsEngine().getPhysicsPlugin() as HavokPlugin);
|
|
||||||
this.lastPosition = this?.grabbedMesh?.physicsBody?.transformNode.absolutePosition.clone();
|
|
||||||
if (this.grabbedMeshParentId) {
|
|
||||||
const parent = scene.getTransformNodeById(this.grabbedMeshParentId);
|
|
||||||
if (parent) {
|
|
||||||
hk.setPhysicsBodyTransformation(this.grabbedMesh.physicsBody, parent);
|
|
||||||
hk.sync(this.grabbedMesh.physicsBody);
|
|
||||||
} else {
|
|
||||||
log.getLogger('beforeRenderObserver').error("parent not found for " + this.grabbedMeshParentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
log.getLogger('beforeRenderObserver').warn("no parent id");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
import {DiagramEvent, DiagramEventType} from "../../diagram/types/diagramEntity";
|
|
||||||
import {toDiagramEntity} from "../../diagram/functions/toDiagramEntity";
|
|
||||||
import {AbstractMesh} from "@babylonjs/core";
|
|
||||||
|
|
||||||
export function buildDrop(mesh: AbstractMesh): DiagramEvent {
|
|
||||||
const entity = toDiagramEntity(mesh);
|
|
||||||
return {
|
|
||||||
type: DiagramEventType.DROP,
|
|
||||||
entity: entity
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -35,7 +35,5 @@ export function grabAndClone(diagramManager: DiagramManager, mesh: AbstractMesh,
|
|||||||
obj.baseTransform.setParent(parent);
|
obj.baseTransform.setParent(parent);
|
||||||
diagramManager.addObject(obj);
|
diagramManager.addObject(obj);
|
||||||
return obj;
|
return obj;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,6 @@ export function handleWasGrabbed(mesh: AbstractMesh): boolean {
|
|||||||
logger.debug("handleWasGrabbed: mesh is a diagram entity");
|
logger.debug("handleWasGrabbed: mesh is a diagram entity");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const result = (mesh?.metadata?.handle == true);
|
const result = (mesh?.metadata?.handle == true);
|
||||||
logger.debug("handleWasGrabbed: mesh ", result);
|
logger.debug("handleWasGrabbed: mesh ", result);
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import {AbstractMesh} from "@babylonjs/core";
|
|
||||||
import log from "loglevel";
|
|
||||||
|
|
||||||
|
|
||||||
export function reparent(mesh: AbstractMesh, previousParentId: string, grabbedMeshParentId: string) {
|
|
||||||
const logger = log.getLogger('reparent');
|
|
||||||
if (previousParentId) {
|
|
||||||
const parent = mesh.getScene().getMeshById(previousParentId);
|
|
||||||
if (parent) {
|
|
||||||
logger.warn('not yet implemented')
|
|
||||||
} else {
|
|
||||||
mesh.setParent(null);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const parent = mesh.getScene().getTransformNodeById(grabbedMeshParentId);
|
|
||||||
if (parent) {
|
|
||||||
logger.warn('setting parent to null', grabbedMeshParentId, parent)
|
|
||||||
mesh.setParent(null);
|
|
||||||
parent.dispose();
|
|
||||||
} else {
|
|
||||||
mesh.setParent(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
import {AbstractMesh, TransformNode} from "@babylonjs/core";
|
|
||||||
|
|
||||||
export function setupTransformNode(mesh: TransformNode, parent: AbstractMesh) {
|
|
||||||
const transformNode = new TransformNode("grabAnchor, this.scene");
|
|
||||||
transformNode.id = "grabAnchor";
|
|
||||||
transformNode.position = mesh.position.clone();
|
|
||||||
transformNode.rotationQuaternion = mesh.rotationQuaternion.clone();
|
|
||||||
transformNode.setParent(parent);
|
|
||||||
return transformNode;
|
|
||||||
}
|
|
||||||
@ -1,12 +1,13 @@
|
|||||||
import {Vector3, WebXRControllerComponent, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core";
|
import {Vector3, WebXRControllerComponent, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core";
|
||||||
import {Base} from "./base";
|
import {AbstractController} from "./abstractController";
|
||||||
import {ControllerEventType} from "./controllers";
|
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {DiagramManager} from "../diagram/diagramManager";
|
import {DiagramManager} from "../diagram/diagramManager";
|
||||||
import {DefaultScene} from "../defaultScene";
|
import {DefaultScene} from "../defaultScene";
|
||||||
|
import {ControllerEventType} from "./types/controllerEventType";
|
||||||
|
import {controllerObservable, movable} from "./controllers";
|
||||||
|
|
||||||
|
|
||||||
export class Left extends Base {
|
export class LeftController extends AbstractController {
|
||||||
private leftLogger = log.getLogger('Left');
|
private leftLogger = log.getLogger('Left');
|
||||||
constructor(controller:
|
constructor(controller:
|
||||||
WebXRInputSource, xr: WebXRDefaultExperience, diagramManager: DiagramManager) {
|
WebXRInputSource, xr: WebXRDefaultExperience, diagramManager: DiagramManager) {
|
||||||
@ -17,7 +18,7 @@ export class Left extends Base {
|
|||||||
init.components['xr-standard-thumbstick']
|
init.components['xr-standard-thumbstick']
|
||||||
.onAxisValueChangedObservable.add((value) => {
|
.onAxisValueChangedObservable.add((value) => {
|
||||||
this.leftLogger.trace(`thumbstick moved ${value.x}, ${value.y}`);
|
this.leftLogger.trace(`thumbstick moved ${value.x}, ${value.y}`);
|
||||||
if (!this.controllers.movable) {
|
if (!movable) {
|
||||||
this.moveRig(value);
|
this.moveRig(value);
|
||||||
} else {
|
} else {
|
||||||
this.moveMovable(value);
|
this.moveMovable(value);
|
||||||
@ -29,7 +30,7 @@ export class Left extends Base {
|
|||||||
init.components['xr-standard-thumbstick'].onButtonStateChangedObservable.add((value) => {
|
init.components['xr-standard-thumbstick'].onButtonStateChangedObservable.add((value) => {
|
||||||
if (value.pressed) {
|
if (value.pressed) {
|
||||||
this.leftLogger.trace('Left', 'thumbstick changed');
|
this.leftLogger.trace('Left', 'thumbstick changed');
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.DECREASE_VELOCITY,
|
type: ControllerEventType.DECREASE_VELOCITY,
|
||||||
value: value.value
|
value: value.value
|
||||||
});
|
});
|
||||||
@ -46,7 +47,7 @@ export class Left extends Base {
|
|||||||
.onButtonStateChangedObservable
|
.onButtonStateChangedObservable
|
||||||
.add((button) => {
|
.add((button) => {
|
||||||
this.leftLogger.trace('trigger pressed');
|
this.leftLogger.trace('trigger pressed');
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.TRIGGER,
|
type: ControllerEventType.TRIGGER,
|
||||||
value: button.value,
|
value: button.value,
|
||||||
controller: this.xrInputSource
|
controller: this.xrInputSource
|
||||||
@ -60,7 +61,7 @@ export class Left extends Base {
|
|||||||
xbutton.onButtonStateChangedObservable.add((button) => {
|
xbutton.onButtonStateChangedObservable.add((button) => {
|
||||||
if (button.pressed) {
|
if (button.pressed) {
|
||||||
this.leftLogger.trace('X button pressed');
|
this.leftLogger.trace('X button pressed');
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.X_BUTTON,
|
type: ControllerEventType.X_BUTTON,
|
||||||
value: button.value
|
value: button.value
|
||||||
});
|
});
|
||||||
@ -74,7 +75,7 @@ export class Left extends Base {
|
|||||||
ybutton.onButtonStateChangedObservable.add((button) => {
|
ybutton.onButtonStateChangedObservable.add((button) => {
|
||||||
if (button.pressed) {
|
if (button.pressed) {
|
||||||
this.leftLogger.trace('Y button pressed');
|
this.leftLogger.trace('Y button pressed');
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.Y_BUTTON,
|
type: ControllerEventType.Y_BUTTON,
|
||||||
value: button.value
|
value: button.value
|
||||||
});
|
});
|
||||||
@ -85,12 +86,12 @@ export class Left extends Base {
|
|||||||
|
|
||||||
private moveMovable(value: { x: number, y: number }) {
|
private moveMovable(value: { x: number, y: number }) {
|
||||||
if (Math.abs(value.x) > .1) {
|
if (Math.abs(value.x) > .1) {
|
||||||
this.controllers.movable.position.x += .005 * Math.sign(value.x);
|
movable.position.x += .005 * Math.sign(value.x);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
if (Math.abs(value.y) > .1) {
|
if (Math.abs(value.y) > .1) {
|
||||||
this.controllers.movable.position.y += -.005 * Math.sign(value.y);
|
movable.position.y += -.005 * Math.sign(value.y);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -98,27 +99,27 @@ export class Left extends Base {
|
|||||||
|
|
||||||
private moveRig(value: { x: number, y: number }) {
|
private moveRig(value: { x: number, y: number }) {
|
||||||
if (Math.abs(value.x) > .1) {
|
if (Math.abs(value.x) > .1) {
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.LEFT_RIGHT,
|
type: ControllerEventType.LEFT_RIGHT,
|
||||||
value: value.x * this.speedFactor
|
value: value.x * this.speedFactor
|
||||||
});
|
});
|
||||||
Base.stickVector.x = 1;
|
AbstractController.stickVector.x = 1;
|
||||||
} else {
|
} else {
|
||||||
Base.stickVector.x = 0;
|
AbstractController.stickVector.x = 0;
|
||||||
}
|
}
|
||||||
if (Math.abs(value.y) > .1) {
|
if (Math.abs(value.y) > .1) {
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.FORWARD_BACK,
|
type: ControllerEventType.FORWARD_BACK,
|
||||||
value: value.y * this.speedFactor
|
value: value.y * this.speedFactor
|
||||||
});
|
});
|
||||||
Base.stickVector.y = 1;
|
AbstractController.stickVector.y = 1;
|
||||||
} else {
|
} else {
|
||||||
Base.stickVector.y = 0;
|
AbstractController.stickVector.y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Base.stickVector.equals(Vector3.Zero())) {
|
if (AbstractController.stickVector.equals(Vector3.Zero())) {
|
||||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.LEFT_RIGHT, value: 0});
|
controllerObservable.notifyObservers({type: ControllerEventType.LEFT_RIGHT, value: 0});
|
||||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.FORWARD_BACK, value: 0});
|
controllerObservable.notifyObservers({type: ControllerEventType.FORWARD_BACK, value: 0});
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,19 +1,21 @@
|
|||||||
import {Base} from "./base";
|
import {AbstractController} from "./abstractController";
|
||||||
import {Vector3, WebXRControllerComponent, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core";
|
import {Vector3, WebXRControllerComponent, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core";
|
||||||
import {ControllerEventType} from "./controllers";
|
|
||||||
|
|
||||||
import {DiagramManager} from "../diagram/diagramManager";
|
import {DiagramManager} from "../diagram/diagramManager";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
|
import {ControllerEventType} from "./types/controllerEventType";
|
||||||
|
import {controllerObservable} from "./controllers";
|
||||||
|
|
||||||
|
|
||||||
export class Right extends Base {
|
export class RightController extends AbstractController {
|
||||||
private rightLogger = log.getLogger("Right");
|
private rightLogger = log.getLogger("Right");
|
||||||
private initBButton(bbutton: WebXRControllerComponent) {
|
private initBButton(bbutton: WebXRControllerComponent) {
|
||||||
if (bbutton) {
|
if (bbutton) {
|
||||||
bbutton.onButtonStateChangedObservable.add((button) => {
|
bbutton.onButtonStateChangedObservable.add((button) => {
|
||||||
if (button.pressed) {
|
if (button.pressed) {
|
||||||
this.rightLogger.debug('B Button Pressed');
|
this.rightLogger.debug('B Button Pressed');
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.B_BUTTON,
|
type: ControllerEventType.B_BUTTON,
|
||||||
value: button.value
|
value: button.value
|
||||||
});
|
});
|
||||||
@ -41,7 +43,7 @@ export class Right extends Base {
|
|||||||
.onButtonStateChangedObservable
|
.onButtonStateChangedObservable
|
||||||
.add((button) => {
|
.add((button) => {
|
||||||
this.rightLogger.debug("right trigger pressed");
|
this.rightLogger.debug("right trigger pressed");
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.TRIGGER,
|
type: ControllerEventType.TRIGGER,
|
||||||
value: button.value,
|
value: button.value,
|
||||||
controller: this.xrInputSource
|
controller: this.xrInputSource
|
||||||
@ -55,7 +57,7 @@ export class Right extends Base {
|
|||||||
abutton.onButtonStateChangedObservable.add((value) => {
|
abutton.onButtonStateChangedObservable.add((value) => {
|
||||||
if (value.pressed) {
|
if (value.pressed) {
|
||||||
this.rightLogger.debug('A button pressed');
|
this.rightLogger.debug('A button pressed');
|
||||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.MENU});
|
controllerObservable.notifyObservers({type: ControllerEventType.MENU});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -70,7 +72,7 @@ export class Right extends Base {
|
|||||||
thumbstick.onButtonStateChangedObservable.add((value) => {
|
thumbstick.onButtonStateChangedObservable.add((value) => {
|
||||||
if (value.pressed) {
|
if (value.pressed) {
|
||||||
this.rightLogger.trace('Right', `thumbstick changed ${value.value}`);
|
this.rightLogger.trace('Right', `thumbstick changed ${value.value}`);
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.INCREASE_VELOCITY,
|
type: ControllerEventType.INCREASE_VELOCITY,
|
||||||
value: value.value
|
value: value.value
|
||||||
});
|
});
|
||||||
@ -81,22 +83,22 @@ export class Right extends Base {
|
|||||||
|
|
||||||
private moveRig(value) {
|
private moveRig(value) {
|
||||||
if (Math.abs(value.x) > .1) {
|
if (Math.abs(value.x) > .1) {
|
||||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.TURN, value: value.x});
|
controllerObservable.notifyObservers({type: ControllerEventType.TURN, value: value.x});
|
||||||
} else {
|
} else {
|
||||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.TURN, value: 0});
|
controllerObservable.notifyObservers({type: ControllerEventType.TURN, value: 0});
|
||||||
}
|
}
|
||||||
if (Math.abs(value.y) > .1) {
|
if (Math.abs(value.y) > .1) {
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.UP_DOWN,
|
type: ControllerEventType.UP_DOWN,
|
||||||
value: value.y * this.speedFactor
|
value: value.y * this.speedFactor
|
||||||
});
|
});
|
||||||
Base.stickVector.z = 1;
|
AbstractController.stickVector.z = 1;
|
||||||
} else {
|
} else {
|
||||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.UP_DOWN, value: 0});
|
controllerObservable.notifyObservers({type: ControllerEventType.UP_DOWN, value: 0});
|
||||||
Base.stickVector.z = 0;
|
AbstractController.stickVector.z = 0;
|
||||||
}
|
}
|
||||||
if (Base.stickVector.equals(Vector3.Zero())) {
|
if (AbstractController.stickVector.equals(Vector3.Zero())) {
|
||||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.UP_DOWN, value: 0});
|
controllerObservable.notifyObservers({type: ControllerEventType.UP_DOWN, value: 0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,17 +1,18 @@
|
|||||||
import {Angle, Mesh, Quaternion, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
|
import {Angle, Mesh, Quaternion, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
|
||||||
import {Right} from "./right";
|
import {RightController} from "./rightController";
|
||||||
import {Left} from "./left";
|
import {LeftController} from "./leftController";
|
||||||
import {ControllerEvent, ControllerEventType, Controllers} from "./controllers";
|
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {DiagramManager} from "../diagram/diagramManager";
|
import {DiagramManager} from "../diagram/diagramManager";
|
||||||
import {buildRig} from "./functions/buildRig";
|
import {buildRig} from "./functions/buildRig";
|
||||||
import {DefaultScene} from "../defaultScene";
|
import {DefaultScene} from "../defaultScene";
|
||||||
|
import {ControllerEvent} from "./types/controllerEvent";
|
||||||
|
import {ControllerEventType} from "./types/controllerEventType";
|
||||||
|
import {controllerObservable} from "./controllers";
|
||||||
|
|
||||||
const RIGHT = "right";
|
const RIGHT = "right";
|
||||||
const LEFT = "left";
|
const LEFT = "left";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export class Rigplatform {
|
export class Rigplatform {
|
||||||
public static instance: Rigplatform;
|
public static instance: Rigplatform;
|
||||||
|
|
||||||
@ -19,14 +20,14 @@ export class Rigplatform {
|
|||||||
public rigMesh: Mesh;
|
public rigMesh: Mesh;
|
||||||
|
|
||||||
private _logger = log.getLogger('Rigplatform');
|
private _logger = log.getLogger('Rigplatform');
|
||||||
private readonly _controllers: Controllers;
|
|
||||||
private readonly _diagramManager: DiagramManager;
|
private readonly _diagramManager: DiagramManager;
|
||||||
private readonly _scene: Scene;
|
private readonly _scene: Scene;
|
||||||
private readonly _velocityArray = [0.01, 0.1, 1, 2, 5];
|
private readonly _velocityArray = [0.01, 0.1, 1, 2, 5];
|
||||||
private readonly _xr: WebXRDefaultExperience;
|
private readonly _xr: WebXRDefaultExperience;
|
||||||
|
|
||||||
private _rightController: Right;
|
private _rightController: RightController;
|
||||||
private _leftController: Left;
|
private _leftController: LeftController;
|
||||||
private _turning: boolean = false;
|
private _turning: boolean = false;
|
||||||
private _velocity: Vector3 = Vector3.Zero();
|
private _velocity: Vector3 = Vector3.Zero();
|
||||||
private _velocityIndex: number = 2;
|
private _velocityIndex: number = 2;
|
||||||
@ -40,7 +41,7 @@ export class Rigplatform {
|
|||||||
) {
|
) {
|
||||||
this._scene = DefaultScene.Scene;
|
this._scene = DefaultScene.Scene;
|
||||||
this._diagramManager = diagramManager;
|
this._diagramManager = diagramManager;
|
||||||
this._controllers = diagramManager.controllers;
|
|
||||||
this._xr = xr;
|
this._xr = xr;
|
||||||
this.rigMesh = buildRig(xr);
|
this.rigMesh = buildRig(xr);
|
||||||
this._fixRotation();
|
this._fixRotation();
|
||||||
@ -112,12 +113,12 @@ export class Rigplatform {
|
|||||||
private _registerObserver() {
|
private _registerObserver() {
|
||||||
if (this._registered) {
|
if (this._registered) {
|
||||||
this._logger.warn('observer already registered, clearing and re registering');
|
this._logger.warn('observer already registered, clearing and re registering');
|
||||||
this._controllers.controllerObservable.clear();
|
controllerObservable.clear();
|
||||||
this._registered = false;
|
this._registered = false;
|
||||||
}
|
}
|
||||||
if (!this._registered) {
|
if (!this._registered) {
|
||||||
this._registered = true;
|
this._registered = true;
|
||||||
this._controllers.controllerObservable.add((event: ControllerEvent) => {
|
controllerObservable.add((event: ControllerEvent) => {
|
||||||
this._logger.debug(event);
|
this._logger.debug(event);
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case ControllerEventType.INCREASE_VELOCITY:
|
case ControllerEventType.INCREASE_VELOCITY:
|
||||||
@ -165,12 +166,12 @@ export class Rigplatform {
|
|||||||
switch (source.inputSource.handedness) {
|
switch (source.inputSource.handedness) {
|
||||||
case RIGHT:
|
case RIGHT:
|
||||||
if (!this._rightController) {
|
if (!this._rightController) {
|
||||||
this._rightController = new Right(source, this._xr, this._diagramManager);
|
this._rightController = new RightController(source, this._xr, this._diagramManager);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LEFT:
|
case LEFT:
|
||||||
if (!this._leftController) {
|
if (!this._leftController) {
|
||||||
this._leftController = new Left(source, this._xr, this._diagramManager);
|
this._leftController = new LeftController(source, this._xr, this._diagramManager);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/controllers/types/controllerEvent.ts
Normal file
12
src/controllers/types/controllerEvent.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import {Vector3, WebXRInputSource} from "@babylonjs/core";
|
||||||
|
import {ControllerEventType} from "./controllerEventType";
|
||||||
|
|
||||||
|
export type ControllerEvent = {
|
||||||
|
type: ControllerEventType,
|
||||||
|
value?: number,
|
||||||
|
startPosition?: Vector3,
|
||||||
|
endPosition?: Vector3,
|
||||||
|
duration?: number,
|
||||||
|
gripId?: string;
|
||||||
|
controller?: WebXRInputSource;
|
||||||
|
}
|
||||||
24
src/controllers/types/controllerEventType.ts
Normal file
24
src/controllers/types/controllerEventType.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
export enum ControllerEventType {
|
||||||
|
GRIP = 'grip',
|
||||||
|
HIDE = 'hide',
|
||||||
|
SHOW = 'show',
|
||||||
|
PULSE = 'pulse',
|
||||||
|
SQUEEZE = 'squeeze',
|
||||||
|
CLICK = 'click',
|
||||||
|
Y_BUTTON = 'y-button',
|
||||||
|
X_BUTTON = 'x-button',
|
||||||
|
A_BUTTON = 'a-button',
|
||||||
|
B_BUTTON = 'b-button',
|
||||||
|
THUMBSTICK = 'thumbstick',
|
||||||
|
THUMBSTICK_CHANGED = 'thumbstickChanged',
|
||||||
|
DECREASE_VELOCITY = 'decreaseVelocity',
|
||||||
|
INCREASE_VELOCITY = 'decreaseVelocity',
|
||||||
|
LEFT_RIGHT = 'leftright',
|
||||||
|
FORWARD_BACK = 'forwardback',
|
||||||
|
TURN = 'turn',
|
||||||
|
UP_DOWN = 'updown',
|
||||||
|
TRIGGER = 'trigger',
|
||||||
|
MENU = 'menu',
|
||||||
|
MOTION = 'motion',
|
||||||
|
GAZEPOINT = 'gazepoint',
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import {AbstractMesh, KeyboardEventTypes, Scene} from "@babylonjs/core";
|
import {AbstractMesh, KeyboardEventTypes, Scene} from "@babylonjs/core";
|
||||||
import {Rigplatform} from "./rigplatform";
|
import {Rigplatform} from "./rigplatform";
|
||||||
import {Controllers} from "./controllers";
|
|
||||||
import {DiagramManager} from "../diagram/diagramManager";
|
import {DiagramManager} from "../diagram/diagramManager";
|
||||||
import {wheelHandler} from "./functions/wheelHandler";
|
import {wheelHandler} from "./functions/wheelHandler";
|
||||||
import log, {Logger} from "loglevel";
|
import log, {Logger} from "loglevel";
|
||||||
@ -12,7 +12,7 @@ export class WebController {
|
|||||||
private rig: Rigplatform;
|
private rig: Rigplatform;
|
||||||
private diagramManager: DiagramManager;
|
private diagramManager: DiagramManager;
|
||||||
private mouseDown: boolean = false;
|
private mouseDown: boolean = false;
|
||||||
private readonly controllers: Controllers;
|
|
||||||
private upDownWheel: boolean = false;
|
private upDownWheel: boolean = false;
|
||||||
private fowardBackWheel: boolean = false;
|
private fowardBackWheel: boolean = false;
|
||||||
private canvas: HTMLCanvasElement;
|
private canvas: HTMLCanvasElement;
|
||||||
@ -20,11 +20,11 @@ export class WebController {
|
|||||||
constructor(scene: Scene,
|
constructor(scene: Scene,
|
||||||
rig: Rigplatform,
|
rig: Rigplatform,
|
||||||
diagramManager: DiagramManager,
|
diagramManager: DiagramManager,
|
||||||
controllers: Controllers) {
|
) {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
this.rig = rig;
|
this.rig = rig;
|
||||||
this.diagramManager = diagramManager;
|
this.diagramManager = diagramManager;
|
||||||
this.controllers = controllers;
|
|
||||||
this.canvas = document.querySelector('#gameCanvas');
|
this.canvas = document.querySelector('#gameCanvas');
|
||||||
//this.referencePlane = MeshBuilder.CreatePlane('referencePlane', {size: 10}, this.scene);
|
//this.referencePlane = MeshBuilder.CreatePlane('referencePlane', {size: 10}, this.scene);
|
||||||
//this.referencePlane.setEnabled(false);
|
//this.referencePlane.setEnabled(false);
|
||||||
@ -160,7 +160,7 @@ export class WebController {
|
|||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
this.scene.onPointerDown = (evt, state) => {
|
this.scene.onPointerDown = (evt) => {
|
||||||
if (evt.pointerType == "mouse") {
|
if (evt.pointerType == "mouse") {
|
||||||
this.mouseDown = true;
|
this.mouseDown = true;
|
||||||
/*if (evt.shiftKey) {
|
/*if (evt.shiftKey) {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import {AbstractActionManager, AbstractMesh, ActionManager, Observable, Scene} from "@babylonjs/core";
|
import {AbstractActionManager, AbstractMesh, ActionManager, Observable, Scene} from "@babylonjs/core";
|
||||||
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./types/diagramEntity";
|
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./types/diagramEntity";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {Controllers} from "../controllers/controllers";
|
|
||||||
import {AppConfig} from "../util/appConfig";
|
import {AppConfig} from "../util/appConfig";
|
||||||
import {buildEntityActionManager} from "./functions/buildEntityActionManager";
|
import {buildEntityActionManager} from "./functions/buildEntityActionManager";
|
||||||
import {DefaultScene} from "../defaultScene";
|
import {DefaultScene} from "../defaultScene";
|
||||||
@ -11,12 +11,14 @@ import {DiagramObject} from "./diagramObject";
|
|||||||
import {getMe} from "../util/me";
|
import {getMe} from "../util/me";
|
||||||
import {UserModelType} from "../users/userTypes";
|
import {UserModelType} from "../users/userTypes";
|
||||||
import {vectoxys} from "./functions/vectorConversion";
|
import {vectoxys} from "./functions/vectorConversion";
|
||||||
|
import {controllerObservable} from "../controllers/controllers";
|
||||||
|
import {ControllerEvent} from "../controllers/types/controllerEvent";
|
||||||
|
|
||||||
|
|
||||||
export class DiagramManager {
|
export class DiagramManager {
|
||||||
private readonly _logger = log.getLogger('DiagramManager');
|
private readonly _logger = log.getLogger('DiagramManager');
|
||||||
public readonly _config: AppConfig;
|
public readonly _config: AppConfig;
|
||||||
private readonly _controllers: Controllers;
|
private readonly _controllerObservable: Observable<ControllerEvent>;
|
||||||
private readonly _diagramEntityActionManager: ActionManager;
|
private readonly _diagramEntityActionManager: ActionManager;
|
||||||
public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable();
|
public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable();
|
||||||
public readonly onUserEventObservable: Observable<UserModelType> = new Observable();
|
public readonly onUserEventObservable: Observable<UserModelType> = new Observable();
|
||||||
@ -31,9 +33,9 @@ export class DiagramManager {
|
|||||||
this._me = getMe();
|
this._me = getMe();
|
||||||
this._scene = DefaultScene.Scene;
|
this._scene = DefaultScene.Scene;
|
||||||
this._config = new AppConfig();
|
this._config = new AppConfig();
|
||||||
this._controllers = new Controllers();
|
|
||||||
this._diagramMenuManager = new DiagramMenuManager(this.onDiagramEventObservable, this._controllers, this._config, readyObservable);
|
this._diagramMenuManager = new DiagramMenuManager(this.onDiagramEventObservable, controllerObservable, this._config, readyObservable);
|
||||||
this._diagramEntityActionManager = buildEntityActionManager(this._controllers);
|
this._diagramEntityActionManager = buildEntityActionManager(controllerObservable);
|
||||||
this.onDiagramEventObservable.add(this.onDiagramEvent, DiagramEventObserverMask.FROM_DB, true, this);
|
this.onDiagramEventObservable.add(this.onDiagramEvent, DiagramEventObserverMask.FROM_DB, true, this);
|
||||||
|
|
||||||
|
|
||||||
@ -116,11 +118,6 @@ export class DiagramManager {
|
|||||||
return this._diagramObjects.has(mesh?.id)
|
return this._diagramObjects.has(mesh?.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public get controllers(): Controllers {
|
|
||||||
return this._controllers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public createCopy(id: string): DiagramObject {
|
public createCopy(id: string): DiagramObject {
|
||||||
const diagramObject = this._diagramObjects.get(id);
|
const diagramObject = this._diagramObjects.get(id);
|
||||||
if (!diagramObject) {
|
if (!diagramObject) {
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import {DiagramEvent, DiagramEventType} from "./types/diagramEntity";
|
|||||||
import {AbstractMesh, ActionEvent, Observable, Scene, Vector3, WebXRInputSource} from "@babylonjs/core";
|
import {AbstractMesh, ActionEvent, Observable, Scene, Vector3, WebXRInputSource} from "@babylonjs/core";
|
||||||
import {InputTextView} from "../information/inputTextView";
|
import {InputTextView} from "../information/inputTextView";
|
||||||
import {DefaultScene} from "../defaultScene";
|
import {DefaultScene} from "../defaultScene";
|
||||||
import {ControllerEvent, ControllerEventType, Controllers} from "../controllers/controllers";
|
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {Toolbox} from "../toolbox/toolbox";
|
import {Toolbox} from "../toolbox/toolbox";
|
||||||
import {ClickMenu} from "../menus/clickMenu";
|
import {ClickMenu} from "../menus/clickMenu";
|
||||||
@ -13,6 +12,8 @@ import {ConnectionPreview} from "../menus/connectionPreview";
|
|||||||
import {ScaleMenu2} from "../menus/ScaleMenu2";
|
import {ScaleMenu2} from "../menus/ScaleMenu2";
|
||||||
import {viewOnly} from "../util/functions/getPath";
|
import {viewOnly} from "../util/functions/getPath";
|
||||||
import {GroupMenu} from "../menus/groupMenu";
|
import {GroupMenu} from "../menus/groupMenu";
|
||||||
|
import {ControllerEvent} from "../controllers/types/controllerEvent";
|
||||||
|
import {ControllerEventType} from "../controllers/types/controllerEventType";
|
||||||
|
|
||||||
|
|
||||||
export class DiagramMenuManager {
|
export class DiagramMenuManager {
|
||||||
@ -26,10 +27,10 @@ export class DiagramMenuManager {
|
|||||||
private _logger = log.getLogger('DiagramMenuManager');
|
private _logger = log.getLogger('DiagramMenuManager');
|
||||||
private _connectionPreview: ConnectionPreview;
|
private _connectionPreview: ConnectionPreview;
|
||||||
|
|
||||||
constructor(notifier: Observable<DiagramEvent>, controllers: Controllers, config: AppConfig, readyObservable: Observable<boolean>) {
|
constructor(notifier: Observable<DiagramEvent>, controllerObservable: Observable<ControllerEvent>, config: AppConfig, readyObservable: Observable<boolean>) {
|
||||||
this._scene = DefaultScene.Scene;
|
this._scene = DefaultScene.Scene;
|
||||||
this._notifier = notifier;
|
this._notifier = notifier;
|
||||||
this._inputTextView = new InputTextView(controllers);
|
this._inputTextView = new InputTextView(controllerObservable);
|
||||||
this.configMenu = new ConfigMenu(config);
|
this.configMenu = new ConfigMenu(config);
|
||||||
|
|
||||||
this._inputTextView.onTextObservable.add((evt) => {
|
this._inputTextView.onTextObservable.add((evt) => {
|
||||||
@ -43,7 +44,7 @@ export class DiagramMenuManager {
|
|||||||
//this.scaleMenu.handleMesh.setEnabled(false)
|
//this.scaleMenu.handleMesh.setEnabled(false)
|
||||||
this.configMenu.handleTransformNode.setEnabled(false);
|
this.configMenu.handleTransformNode.setEnabled(false);
|
||||||
}
|
}
|
||||||
controllers.controllerObservable.add((event: ControllerEvent) => {
|
controllerObservable.add((event: ControllerEvent) => {
|
||||||
if (event.type == ControllerEventType.B_BUTTON) {
|
if (event.type == ControllerEventType.B_BUTTON) {
|
||||||
if (event.value > .8) {
|
if (event.value > .8) {
|
||||||
const platform = this._scene.getMeshByName("platform");
|
const platform = this._scene.getMeshByName("platform");
|
||||||
|
|||||||
@ -1,47 +0,0 @@
|
|||||||
import {afterEach, describe, expect, it, vi} from 'vitest'
|
|
||||||
import {applyScaling} from './applyScaling'
|
|
||||||
import {Vector3} from "@babylonjs/core";
|
|
||||||
|
|
||||||
describe('applyScaling', () => {
|
|
||||||
afterEach(() => {
|
|
||||||
vi.restoreAllMocks();
|
|
||||||
})
|
|
||||||
it('should copy scaling', () => {
|
|
||||||
const oldMesh = {
|
|
||||||
scaling: {
|
|
||||||
clone: () => 'cloned'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const newMesh = {
|
|
||||||
scaling: null
|
|
||||||
}
|
|
||||||
applyScaling(oldMesh as any, newMesh as any, true, 0)
|
|
||||||
expect(newMesh.scaling).toBe('cloned')
|
|
||||||
})
|
|
||||||
it('scaling to be set to 1,1,1 if snap passed as null', () => {
|
|
||||||
const spy = vi.spyOn(Vector3, 'One');
|
|
||||||
//expect(spy).toHaveBeenCalledTimes(1);
|
|
||||||
const oldMesh = {
|
|
||||||
scaling: {}
|
|
||||||
}
|
|
||||||
const newMesh = {
|
|
||||||
scaling: null
|
|
||||||
}
|
|
||||||
applyScaling(oldMesh as any, newMesh as any, false, null)
|
|
||||||
expect(newMesh.scaling.x).toBe(1);
|
|
||||||
expect(newMesh.scaling.y).toBe(1);
|
|
||||||
expect(newMesh.scaling.z).toBe(1);
|
|
||||||
})
|
|
||||||
it('scaling to be set to 2,2,2 snap passed as Vector3(2,2,2)', () => {
|
|
||||||
const oldMesh = {
|
|
||||||
scaling: {}
|
|
||||||
}
|
|
||||||
const newMesh = {
|
|
||||||
scaling: new Vector3()
|
|
||||||
}
|
|
||||||
applyScaling(oldMesh as any, newMesh as any, false, 2)
|
|
||||||
expect(newMesh.scaling.x).toBe(2);
|
|
||||||
expect(newMesh.scaling.y).toBe(2);
|
|
||||||
expect(newMesh.scaling.z).toBe(2);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
import {AbstractMesh, Vector3} from "@babylonjs/core";
|
|
||||||
|
|
||||||
export function applyScaling(oldMesh: AbstractMesh,
|
|
||||||
newMesh: AbstractMesh,
|
|
||||||
copy: boolean,
|
|
||||||
snap: number) {
|
|
||||||
if (copy) {
|
|
||||||
newMesh.scaling = oldMesh.scaling.clone();
|
|
||||||
} else {
|
|
||||||
if (snap) {
|
|
||||||
newMesh.scaling.set(snap, snap, snap);
|
|
||||||
} else {
|
|
||||||
newMesh.scaling = Vector3.One();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +1,17 @@
|
|||||||
import {ActionManager, ExecuteCodeAction, HighlightLayer, InstancedMesh, StandardMaterial,} from "@babylonjs/core";
|
import {
|
||||||
import {ControllerEventType, Controllers} from "../../controllers/controllers";
|
ActionManager,
|
||||||
|
ExecuteCodeAction,
|
||||||
|
HighlightLayer,
|
||||||
|
InstancedMesh,
|
||||||
|
Observable,
|
||||||
|
StandardMaterial,
|
||||||
|
} from "@babylonjs/core";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
import {DefaultScene} from "../../defaultScene";
|
import {DefaultScene} from "../../defaultScene";
|
||||||
|
import {ControllerEventType} from "../../controllers/types/controllerEventType";
|
||||||
|
import {ControllerEvent} from "../../controllers/types/controllerEvent";
|
||||||
|
|
||||||
export function buildEntityActionManager(controllers: Controllers) {
|
export function buildEntityActionManager(controllerObservable: Observable<ControllerEvent>) {
|
||||||
const highlightLayer = new HighlightLayer('highlightLayer', DefaultScene.Scene);
|
const highlightLayer = new HighlightLayer('highlightLayer', DefaultScene.Scene);
|
||||||
highlightLayer.innerGlow = false;
|
highlightLayer.innerGlow = false;
|
||||||
highlightLayer.outerGlow = true;
|
highlightLayer.outerGlow = true;
|
||||||
@ -37,10 +45,10 @@ export function buildEntityActionManager(controllers: Controllers) {
|
|||||||
logger.error(e);
|
logger.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
controllers.controllerObservable.notifyObservers({
|
controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.PULSE,
|
type: ControllerEventType.PULSE,
|
||||||
gripId: evt?.additionalData?.pickResult?.gripTransform?.id
|
gripId: evt?.additionalData?.pickResult?.gripTransform?.id
|
||||||
})
|
});
|
||||||
logger.debug(evt);
|
logger.debug(evt);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,73 +0,0 @@
|
|||||||
import {afterEach, describe, expect, it, vi} from 'vitest'
|
|
||||||
import {buildMeshFromDiagramEntity} from './buildMeshFromDiagramEntity'
|
|
||||||
import {DiagramEntityType} from "../types/diagramEntity";
|
|
||||||
import {Vector3} from "@babylonjs/core";
|
|
||||||
|
|
||||||
describe('buildMeshFromDiagramEntity', () => {
|
|
||||||
afterEach(() => {
|
|
||||||
vi.restoreAllMocks();
|
|
||||||
})
|
|
||||||
it('should return null if entity is null', () => {
|
|
||||||
|
|
||||||
const scene = {
|
|
||||||
getMeshById: () => null
|
|
||||||
}
|
|
||||||
const entity = buildMeshFromDiagramEntity(null, scene as any);
|
|
||||||
expect(entity).toBe(null);
|
|
||||||
});
|
|
||||||
it('should return existing mesh if id exists in scene', () => {
|
|
||||||
const material = 'material';
|
|
||||||
const scene = {
|
|
||||||
getMeshById: (id) => {
|
|
||||||
return {
|
|
||||||
id: id,
|
|
||||||
material: material
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const dEntity = {
|
|
||||||
type: DiagramEntityType.USER,
|
|
||||||
}
|
|
||||||
const entity = buildMeshFromDiagramEntity(dEntity, scene as any);
|
|
||||||
expect(entity.material).toBe(material);
|
|
||||||
});
|
|
||||||
it('should generate new mesh if id is missing', () => {
|
|
||||||
|
|
||||||
vi.mock('../diagramConnection', () => {
|
|
||||||
const DiagramConnection = vi.fn();
|
|
||||||
DiagramConnection.prototype.mesh =
|
|
||||||
{
|
|
||||||
id: 'id',
|
|
||||||
material: 'material',
|
|
||||||
getChildren: vi.fn(),
|
|
||||||
getScene: vi.fn()
|
|
||||||
}
|
|
||||||
return {DiagramConnection}
|
|
||||||
});
|
|
||||||
const scene = {
|
|
||||||
getMeshById: () => {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
const dEntity = {
|
|
||||||
type: DiagramEntityType.USER,
|
|
||||||
template: "#connection-template",
|
|
||||||
color: "$FF00FF",
|
|
||||||
position: {x: 1, y: 2, z: 3},
|
|
||||||
rotation: {x: 4, y: 5, z: 6},
|
|
||||||
scale: {x: 7, y: 8, z: 9},
|
|
||||||
text: 'new text'
|
|
||||||
|
|
||||||
}
|
|
||||||
const entity = buildMeshFromDiagramEntity(dEntity, scene as any);
|
|
||||||
|
|
||||||
expect(entity.id).toBe('id');
|
|
||||||
expect(entity.material).toBe('material');
|
|
||||||
expect(entity.position).toEqual(new Vector3(1, 2, 3));
|
|
||||||
expect(entity.rotation).toEqual(new Vector3(4, 5, 6));
|
|
||||||
expect(entity.scaling).toEqual(new Vector3(7, 8, 9));
|
|
||||||
expect(entity.metadata.text).toEqual('new text');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
import {PresentationStep} from "./presentationStep";
|
|
||||||
import log, {Logger} from "loglevel";
|
|
||||||
import {Scene} from "@babylonjs/core";
|
|
||||||
import {isDiagramEntity} from "./functions/isDiagramEntity";
|
|
||||||
|
|
||||||
export class PresentationManager {
|
|
||||||
_currentStep: PresentationStep = null;
|
|
||||||
private scene: Scene;
|
|
||||||
private logger: Logger = log.getLogger("PresentationManager");
|
|
||||||
|
|
||||||
constructor(scene: Scene) {
|
|
||||||
this.scene = scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
_steps: PresentationStep[] = [];
|
|
||||||
|
|
||||||
public get steps(): PresentationStep[] {
|
|
||||||
return this._steps;
|
|
||||||
}
|
|
||||||
|
|
||||||
public addStep(): PresentationStep {
|
|
||||||
const step = new PresentationStep();
|
|
||||||
this._currentStep = step;
|
|
||||||
if (this._steps.length > 0) {
|
|
||||||
this._steps[this._steps.length - 1].next = step;
|
|
||||||
} else {
|
|
||||||
this.scene.getActiveMeshes().forEach((mesh) => {
|
|
||||||
if (isDiagramEntity(mesh)) {
|
|
||||||
step.entities.push({
|
|
||||||
entity: mesh,
|
|
||||||
endPosition: mesh.position.clone(),
|
|
||||||
endRotation: mesh.rotation.clone(),
|
|
||||||
endScaling: mesh.scaling.clone()
|
|
||||||
})
|
|
||||||
step.duration = 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this._steps.push(step);
|
|
||||||
return step;
|
|
||||||
}
|
|
||||||
|
|
||||||
public play() {
|
|
||||||
this._currentStep.play();
|
|
||||||
if (this._currentStep.next) {
|
|
||||||
this._currentStep = this._currentStep.next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public reset() {
|
|
||||||
this._currentStep = this._steps[0];
|
|
||||||
this._steps[0].play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
import {AbstractMesh, Animation, Vector3} from "@babylonjs/core";
|
|
||||||
|
|
||||||
export type EntityTransform = {
|
|
||||||
entity: AbstractMesh,
|
|
||||||
endPosition?: Vector3,
|
|
||||||
endRotation?: Vector3,
|
|
||||||
endScaling?: Vector3
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PresentationStep {
|
|
||||||
public id: string;
|
|
||||||
public name: string;
|
|
||||||
public duration: number = 2;
|
|
||||||
public entities: Array<EntityTransform> = [];
|
|
||||||
public next: PresentationStep;
|
|
||||||
private readonly fps: number = 30;
|
|
||||||
|
|
||||||
private get endFrame(): number {
|
|
||||||
return this.fps * this.duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public play() {
|
|
||||||
this.entities.forEach((entityTransform) => {
|
|
||||||
if (entityTransform.endPosition) {
|
|
||||||
|
|
||||||
const transform = new Animation("transform", "position",
|
|
||||||
this.fps, Animation.ANIMATIONTYPE_VECTOR3, Animation.ANIMATIONLOOPMODE_CONSTANT);
|
|
||||||
const keyframes = [
|
|
||||||
{frame: 0, value: entityTransform.entity.position},
|
|
||||||
{frame: this.endFrame, value: entityTransform.endPosition}
|
|
||||||
]
|
|
||||||
transform.setKeys(keyframes);
|
|
||||||
entityTransform.entity.animations.push(transform);
|
|
||||||
entityTransform.entity.getScene().beginAnimation(entityTransform.entity, 0, this.endFrame, false);
|
|
||||||
}
|
|
||||||
if (entityTransform.endRotation) {
|
|
||||||
//entityTransform.entity.rotation = entityTransform.endRotation;
|
|
||||||
}
|
|
||||||
if (entityTransform.endScaling) {
|
|
||||||
//entityTransform.entity.scaling = entityTransform.endScaling;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +1,10 @@
|
|||||||
import {AbstractMesh, MeshBuilder, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core";
|
import {AbstractMesh, MeshBuilder, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core";
|
||||||
import log, {Logger} from "loglevel";
|
import log, {Logger} from "loglevel";
|
||||||
import {AdvancedDynamicTexture, Control, InputText, VirtualKeyboard} from "@babylonjs/gui";
|
import {AdvancedDynamicTexture, Control, InputText, VirtualKeyboard} from "@babylonjs/gui";
|
||||||
import {ControllerEventType, Controllers} from "../controllers/controllers";
|
|
||||||
import {Handle} from "../objects/handle";
|
import {Handle} from "../objects/handle";
|
||||||
import {DefaultScene} from "../defaultScene";
|
import {DefaultScene} from "../defaultScene";
|
||||||
|
import {ControllerEvent} from "../controllers/types/controllerEvent";
|
||||||
|
import {ControllerEventType} from "../controllers/types/controllerEventType";
|
||||||
|
|
||||||
export type TextEvent = {
|
export type TextEvent = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -16,15 +17,15 @@ export class InputTextView {
|
|||||||
private readonly scene: Scene;
|
private readonly scene: Scene;
|
||||||
private readonly inputMesh: AbstractMesh;
|
private readonly inputMesh: AbstractMesh;
|
||||||
|
|
||||||
private readonly controllers: Controllers;
|
private readonly controllerObservable: Observable<ControllerEvent>;
|
||||||
|
|
||||||
private readonly handle: Handle;
|
private readonly handle: Handle;
|
||||||
private inputText: InputText;
|
private inputText: InputText;
|
||||||
private diagramMesh: AbstractMesh;
|
private diagramMesh: AbstractMesh;
|
||||||
private keyboard: VirtualKeyboard;
|
private keyboard: VirtualKeyboard;
|
||||||
|
|
||||||
constructor(controllers: Controllers) {
|
constructor(controllerObservable: Observable<ControllerEvent>) {
|
||||||
this.controllers = controllers;
|
this.controllerObservable = controllerObservable;
|
||||||
this.scene = DefaultScene.Scene;
|
this.scene = DefaultScene.Scene;
|
||||||
this.inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene);
|
this.inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene);
|
||||||
this.handle = new Handle(this.inputMesh, 'Input');
|
this.handle = new Handle(this.inputMesh, 'Input');
|
||||||
@ -113,7 +114,7 @@ export class InputTextView {
|
|||||||
this.logger.debug(eventData);
|
this.logger.debug(eventData);
|
||||||
const gripId = eventState?.userInfo?.pickInfo?.gripTransform?.id;
|
const gripId = eventState?.userInfo?.pickInfo?.gripTransform?.id;
|
||||||
if (gripId) {
|
if (gripId) {
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
this.controllerObservable.notifyObservers({
|
||||||
type: ControllerEventType.PULSE,
|
type: ControllerEventType.PULSE,
|
||||||
gripId: gripId
|
gripId: gripId
|
||||||
});
|
});
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export class PouchdbPersistenceManager {
|
|||||||
}
|
}
|
||||||
this._logger.debug(evt);
|
this._logger.debug(evt);
|
||||||
});
|
});
|
||||||
document.addEventListener('dbcreated', (evt) => {
|
document.addEventListener('dbcreated', (evt: CustomEvent) => {
|
||||||
const detail = ((evt.detail as unknown) as PasswordEvent2);
|
const detail = ((evt.detail as unknown) as PasswordEvent2);
|
||||||
const password = detail.password;
|
const password = detail.password;
|
||||||
const id = detail.id;
|
const id = detail.id;
|
||||||
|
|||||||
@ -1,305 +0,0 @@
|
|||||||
import log from "loglevel";
|
|
||||||
import {Color3, Scene, Vector3} from "@babylonjs/core";
|
|
||||||
import {DiagramManager} from "../diagram/diagramManager";
|
|
||||||
import {DiagramEventType} from "../diagram/types/diagramEntity";
|
|
||||||
|
|
||||||
type DrawIOEntity = {
|
|
||||||
text?: string,
|
|
||||||
id?: string,
|
|
||||||
parent?: string,
|
|
||||||
parentEntity?: DrawIOEntity,
|
|
||||||
geometry?: DrawIOGeometry,
|
|
||||||
|
|
||||||
}
|
|
||||||
type DrawIOGeometry = {
|
|
||||||
zIndex?: number,
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
width: number,
|
|
||||||
height: number
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class EntityTree {
|
|
||||||
private readonly logger = log.getLogger('EntityTree');
|
|
||||||
private root: DrawIOEntity;
|
|
||||||
private readonly nodes: Map<string, DrawIOEntity> = new Map<string, DrawIOEntity>();
|
|
||||||
private readonly unparented: Array<DrawIOEntity> = new Array<DrawIOEntity>();
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.root = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNodes(): Array<DrawIOEntity> {
|
|
||||||
this.reparent();
|
|
||||||
const output: Array<DrawIOEntity> = new Array<DrawIOEntity>();
|
|
||||||
this.nodes.forEach((node) => {
|
|
||||||
if (node.parentEntity) {
|
|
||||||
node.geometry = this.computeOffset(node);
|
|
||||||
}
|
|
||||||
output.push(node);
|
|
||||||
});
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public reparent() {
|
|
||||||
this.unparented.forEach((node) => {
|
|
||||||
if (this.nodes.has(node.parent)) {
|
|
||||||
this.logger.debug('reparenting node: ' + node.id + ' to parent: ' + node.parent);
|
|
||||||
node.parentEntity = this.nodes.get(node.parent);
|
|
||||||
} else {
|
|
||||||
this.logger.warn('parent node does not exist for id: ' + node.id +
|
|
||||||
' parent id: ' + node.parent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public addNode(node: DrawIOEntity) {
|
|
||||||
if (this.nodes.has(node.id)) {
|
|
||||||
this.logger.warn('node already exists for id: ' + node.id);
|
|
||||||
} else {
|
|
||||||
if (node.parent) {
|
|
||||||
if (this.nodes.has(node.parent)) {
|
|
||||||
node.parentEntity = this.nodes.get(node.parent);
|
|
||||||
this.nodes.set(node.id, node);
|
|
||||||
} else {
|
|
||||||
this.logger.warn('parent node does not exist for id: ' + node.id +
|
|
||||||
' parent id: ' + node.parent);
|
|
||||||
this.unparented.push(node);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.logger.warn('no parent for node id: ' + node.id + 'setting as root');
|
|
||||||
this.nodes.set(node.id, node);
|
|
||||||
this.root = node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private computeOffset(node: DrawIOEntity): DrawIOGeometry {
|
|
||||||
if (node.parentEntity) {
|
|
||||||
const parentgeo = this.computeOffset(node.parentEntity);
|
|
||||||
if (parentgeo) {
|
|
||||||
const parentzIndex = 1 + parentgeo.zIndex ? parentgeo.zIndex : 0;
|
|
||||||
return {
|
|
||||||
x: node.geometry.x,
|
|
||||||
y: node.geometry.y,
|
|
||||||
width: node.geometry.width,
|
|
||||||
height: node.geometry.height,
|
|
||||||
zIndex: node.geometry.zIndex ? node.geometry.zIndex + parentzIndex : parentzIndex + 1
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
x: node.geometry.x,
|
|
||||||
y: node.geometry.y,
|
|
||||||
width: node.geometry.width,
|
|
||||||
height: node.geometry.height,
|
|
||||||
zIndex: node.geometry.zIndex ? node.geometry.zIndex : 0
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (node.geometry) {
|
|
||||||
if (node.geometry.zIndex === undefined) {
|
|
||||||
node.geometry.zIndex = 0;
|
|
||||||
}
|
|
||||||
return node.geometry;
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
zIndex: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type DrawIOConnector = {
|
|
||||||
id: string,
|
|
||||||
source: string,
|
|
||||||
target: string,
|
|
||||||
text: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class DrawioManager {
|
|
||||||
private diagramManager: DiagramManager;
|
|
||||||
private connectors: Array<DrawIOConnector> = [];
|
|
||||||
private readonly scene: Scene;
|
|
||||||
private readonly logger = log.getLogger('DrawioManager');
|
|
||||||
private minY = 0;
|
|
||||||
private minX = 0;
|
|
||||||
private maxX = 0;
|
|
||||||
private maxY = 0;
|
|
||||||
private maxZ = 0;
|
|
||||||
|
|
||||||
constructor(scene: Scene, diagramManager: DiagramManager) {
|
|
||||||
this.scene = scene;
|
|
||||||
this.diagramManager = diagramManager;
|
|
||||||
this.buildGraph();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private async fetchData(url: string): Promise<Document> {
|
|
||||||
this.logger.debug("starting to get graph");
|
|
||||||
const graph = await fetch(url);
|
|
||||||
this.logger.debug('got graph');
|
|
||||||
const graphXml = await graph.text();
|
|
||||||
return new DOMParser().parseFromString(graphXml, 'text/html');
|
|
||||||
}
|
|
||||||
|
|
||||||
private getDiagram(doc: Document, index: number): Element {
|
|
||||||
const firstDiagram = doc.querySelectorAll('diagram')[index];
|
|
||||||
return firstDiagram.querySelector('mxGraphModel');
|
|
||||||
}
|
|
||||||
|
|
||||||
private parseDiagram(mxDiagram: Element): EntityTree {
|
|
||||||
const entityTree = new EntityTree();
|
|
||||||
|
|
||||||
mxDiagram.querySelectorAll('mxCell').forEach((cell) => {
|
|
||||||
const value = cell.getAttribute('value');
|
|
||||||
let ent = null;
|
|
||||||
if (value) {
|
|
||||||
ent = new DOMParser().parseFromString(value, 'text/html');
|
|
||||||
const errorNode = ent.querySelector("parsererror");
|
|
||||||
if (errorNode) {
|
|
||||||
this.logger.error(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const text = ent ? this.getText(ent, '') : '';
|
|
||||||
const id = cell.getAttribute('id');
|
|
||||||
const parent = cell.getAttribute('parent');
|
|
||||||
const source = cell.getAttribute('source');
|
|
||||||
const target = cell.getAttribute('target');
|
|
||||||
const edge = cell.getAttribute('target');
|
|
||||||
if (source && target && edge) {
|
|
||||||
this.connectors.push({id: id, source: source, target: target, text: text});
|
|
||||||
} else {
|
|
||||||
|
|
||||||
const geo = cell.querySelector('[id="' + id + '"] > mxGeometry');
|
|
||||||
let geometry;
|
|
||||||
if (geo) {
|
|
||||||
geometry = {
|
|
||||||
x: Number.parseFloat(geo.getAttribute('x')),
|
|
||||||
y: Number.parseFloat(geo.getAttribute('y')),
|
|
||||||
width: Number.parseFloat(geo.getAttribute('width')),
|
|
||||||
height: Number.parseFloat(geo.getAttribute('height')),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
geometry = {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: 0,
|
|
||||||
height: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//entities.push({text: text, id: id, parent: parent, geometry: this.fixMinMax(geometry)});
|
|
||||||
if (text) {
|
|
||||||
this.logger.debug('Text' + text);
|
|
||||||
this.logger.debug('Geometry' + JSON.stringify(geometry));
|
|
||||||
}
|
|
||||||
if (geometry) {
|
|
||||||
if (Number.isNaN(geometry.x) || Number.isNaN(geometry.y)
|
|
||||||
|| Number.isNaN(geometry.width) ||
|
|
||||||
Number.isNaN(geometry.height)) {
|
|
||||||
this.logger.warn('invalid geometry for node: ' + id, geometry);
|
|
||||||
} else {
|
|
||||||
entityTree.addNode({text: text, id: id, parent: parent, geometry: geometry});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return entityTree
|
|
||||||
}
|
|
||||||
|
|
||||||
private async buildGraph() {
|
|
||||||
|
|
||||||
const doc = await this.fetchData('/arch_demo.xml');
|
|
||||||
const mxDiagram = this.getDiagram(doc, 0);
|
|
||||||
this.logger.debug('begin parse');
|
|
||||||
const entities: EntityTree = this.parseDiagram(mxDiagram);
|
|
||||||
|
|
||||||
entities.getNodes().forEach((node) => {
|
|
||||||
if (node.geometry.x < this.minX) {
|
|
||||||
this.minX = node.geometry.x;
|
|
||||||
this.logger.debug('minX: ' + this.minX);
|
|
||||||
}
|
|
||||||
if (node.geometry.y < this.minY) {
|
|
||||||
this.minY = node.geometry.y;
|
|
||||||
this.logger.debug('minY: ' + this.minY);
|
|
||||||
}
|
|
||||||
if (node.geometry.x + node.geometry.width > this.maxX) {
|
|
||||||
this.maxX = node.geometry.x + node.geometry.width;
|
|
||||||
this.logger.debug('maxX: ' + this.maxX);
|
|
||||||
}
|
|
||||||
if (node.geometry.y + node.geometry.height > this.maxY) {
|
|
||||||
this.maxY = node.geometry.y + node.geometry.height;
|
|
||||||
this.logger.debug('maxY: ' + this.maxY);
|
|
||||||
}
|
|
||||||
if (node.geometry.zIndex > this.maxZ) {
|
|
||||||
this.maxZ = node.geometry.zIndex;
|
|
||||||
this.logger.debug('maxZ: ' + this.maxZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
this.logger.info('minX: ' + this.minX + ' minY: ' + this.minY + ' maxX: ' + this.maxX + ' maxY: ' + this.maxY);
|
|
||||||
|
|
||||||
|
|
||||||
this.logger.debug('done parsing');
|
|
||||||
this.logger.debug(this.connectors);
|
|
||||||
this.createSceneData(entities.getNodes());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private createSceneData(nodes) {
|
|
||||||
const yOffset = 20;
|
|
||||||
const scale = .001;
|
|
||||||
nodes.forEach((entity) => {
|
|
||||||
this.diagramManager.onDiagramEventObservable.notifyObservers(
|
|
||||||
{
|
|
||||||
type: DiagramEventType.ADD,
|
|
||||||
entity: {
|
|
||||||
text: entity.text,
|
|
||||||
id: entity.id,
|
|
||||||
position: new Vector3(
|
|
||||||
(entity.geometry.x * scale) - (entity.geometry.width * scale / 2),
|
|
||||||
yOffset - (entity.geometry.y * scale) + (entity.geometry.height * scale / 2),
|
|
||||||
entity.geometry.zIndex * .1),
|
|
||||||
scale: new Vector3(entity.geometry.width * scale, entity.geometry.height * scale, .05),
|
|
||||||
color: Color3.Blue().toHexString(),
|
|
||||||
template: '#box-template'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private getText(obj: Node, text: string): string {
|
|
||||||
if (obj.nodeType == Node.TEXT_NODE) {
|
|
||||||
if (obj.textContent) {
|
|
||||||
return obj.textContent.trim();
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (obj.childNodes) {
|
|
||||||
let t = '';
|
|
||||||
obj.childNodes.forEach((child) => {
|
|
||||||
t += ' ' + this.getText(child, '');
|
|
||||||
});
|
|
||||||
return text.trim() + ' ' + t.trim();
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
import {Observable} from "@babylonjs/core";
|
|
||||||
|
|
||||||
export class NativeVoiceRecognition {
|
|
||||||
public readonly onTextObservable: Observable<string> = new Observable<string>();
|
|
||||||
private recognition: SpeechRecognition;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
|
|
||||||
this.onTextObservable = new Observable<string>();
|
|
||||||
this.setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
public stop() {
|
|
||||||
this.recognition.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
private setup() {
|
|
||||||
|
|
||||||
//const SpeechRecognition2 = SpeechRecognition || webkitSpeechRecognition
|
|
||||||
// const SpeechGrammarList = SpeechGrammarList || window.webkitSpeechGrammarList
|
|
||||||
//const SpeechRecognitionEvent = SpeechRecognitionEvent || webkitSpeechRecognitionEvent
|
|
||||||
try {
|
|
||||||
this.recognition = new webkitSpeechRecognition();
|
|
||||||
} catch (e) {
|
|
||||||
this.recognition = new SpeechRecognition();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.recognition.continuous = false;
|
|
||||||
this.recognition.lang = 'en-US';
|
|
||||||
this.recognition.interimResults = true;
|
|
||||||
this.recognition.maxAlternatives = 1;
|
|
||||||
this.recognition.onresult = (event) => {
|
|
||||||
this.onTextObservable.notifyObservers(event.results[0][0].transcript);
|
|
||||||
|
|
||||||
}
|
|
||||||
this.recognition.onend = () => {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
this.recognition.onstart = () => {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
this.recognition.start();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
import {Color3, Material, Mesh, MeshBuilder, Scene, StandardMaterial, TransformNode, Vector3} from "@babylonjs/core";
|
|
||||||
import axios from "axios";
|
|
||||||
import {AdvancedDynamicTexture, TextBlock} from "@babylonjs/gui";
|
|
||||||
|
|
||||||
export class NewRelicQuery {
|
|
||||||
private readonly scene: Scene;
|
|
||||||
private data: { name: string, point: Vector3 }[] = [];
|
|
||||||
private baseTransform: TransformNode;
|
|
||||||
private seriesNumber = 0;
|
|
||||||
private maxY = 0;
|
|
||||||
private minY = 0;
|
|
||||||
private maxZ = 0;
|
|
||||||
private minZ = 0;
|
|
||||||
|
|
||||||
constructor(scene: Scene) {
|
|
||||||
this.scene = scene;
|
|
||||||
this.baseTransform = new TransformNode("graphBase", this.scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getSales() {
|
|
||||||
const data = await axios.get('/data.json')
|
|
||||||
const series = data.data[0].series[0].series;
|
|
||||||
for (const s of series) {
|
|
||||||
this.buildSeries(s);
|
|
||||||
}
|
|
||||||
this.buildModel();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//private materials: Material[];
|
|
||||||
private buildSeries(series) {
|
|
||||||
const name = series.name;
|
|
||||||
const material = new StandardMaterial(name + 'Material', this.scene);
|
|
||||||
material.diffuseColor = new Color3(Math.random(), Math.random(), Math.random());
|
|
||||||
//material.ambientColor = new Color3(0, 0, 0);
|
|
||||||
material.specularColor = new Color3(1, 1, 1);
|
|
||||||
material.alpha = .9;
|
|
||||||
|
|
||||||
|
|
||||||
//this.materials.push(material);
|
|
||||||
const data = series.data;
|
|
||||||
for (const point in data) {
|
|
||||||
this.buildPoint(name, data[point]);
|
|
||||||
|
|
||||||
}
|
|
||||||
this.buildTextLabel(name, new Vector3(this.seriesNumber, .25, -.25));
|
|
||||||
this.seriesNumber++;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildTextLabel(text: string, position: Vector3) {
|
|
||||||
|
|
||||||
const plane = MeshBuilder.CreatePlane("plane", {width: .5, height: .25}, this.scene);
|
|
||||||
plane.billboardMode = Mesh.BILLBOARDMODE_ALL;
|
|
||||||
const advancedTexture = AdvancedDynamicTexture.CreateForMesh(plane, 1024, 512, false);
|
|
||||||
const text1 = new TextBlock();
|
|
||||||
text1.text = text;
|
|
||||||
advancedTexture.background = "#000000";
|
|
||||||
text1.color = "white";
|
|
||||||
text1.fontSize = 128;
|
|
||||||
advancedTexture.addControl(text1);
|
|
||||||
plane.position.set(position.x, position.y, position.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildNumericLabel(number: number, position: Vector3) {
|
|
||||||
const rounded = Math.round(number);
|
|
||||||
let shortNumber: string = '???';
|
|
||||||
if (Math.log10(rounded) < 3) {
|
|
||||||
shortNumber = rounded.toString();
|
|
||||||
}
|
|
||||||
if (Math.log10(rounded) >= 3 && Math.log10(rounded) < 6) {
|
|
||||||
shortNumber = (Math.round(rounded / 100) / 10).toString() + 'K';
|
|
||||||
}
|
|
||||||
if (Math.log10(rounded) >= 6) {
|
|
||||||
shortNumber = (Math.round(rounded / 100000) / 10).toString() + 'M';
|
|
||||||
}
|
|
||||||
this.buildTextLabel(shortNumber, position);
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildModel() {
|
|
||||||
const zScale = 20 / (this.maxZ - this.minZ);
|
|
||||||
const yScale = 20 / (this.maxY - this.minY);
|
|
||||||
for (const point of this.data) {
|
|
||||||
const z = (point.point.z - this.minZ) * zScale;
|
|
||||||
const y = (point.point.y - this.minY) * yScale;
|
|
||||||
//const baseMesh = (this.scene.getMeshByName(point.name+ 'Mesh') as Mesh);
|
|
||||||
const bar = MeshBuilder.CreateBox(name + 'Mesh', {width: 1, height: 1, depth: 1}, this.scene);
|
|
||||||
bar.material = this.scene.getMaterialByName(point.name + 'Material');
|
|
||||||
|
|
||||||
//const bar = new InstancedMesh(point.name + point.point.z, baseMesh);
|
|
||||||
bar.scaling.x = .5;
|
|
||||||
bar.scaling.y = y;
|
|
||||||
bar.scaling.z = .5;
|
|
||||||
/*MeshBuilder.CreateBox(point.name + point.point.z, {width: .5,
|
|
||||||
height: y, depth: .5}, this.scene);
|
|
||||||
*/
|
|
||||||
bar.position.set(point.point.x, y / 2, z);
|
|
||||||
this.buildNumericLabel(point.point.y, new Vector3(point.point.x, y, z));
|
|
||||||
const base = MeshBuilder.CreatePlane('base', {width: 20, height: 20}, this.scene);
|
|
||||||
const material = new StandardMaterial("baseMaterial", this.scene);
|
|
||||||
material.diffuseColor = new Color3(0, 1, 0);
|
|
||||||
base.material = material;
|
|
||||||
base.position.set(10, .001, 10);
|
|
||||||
base.parent = this.baseTransform;
|
|
||||||
base.rotation.x = Math.PI / 2;
|
|
||||||
bar.parent = this.baseTransform;
|
|
||||||
|
|
||||||
// bar.material = this.scene.getMaterialByName(point.name+'Material');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildPoint(name, point) {
|
|
||||||
if (point[1] > this.maxY) {
|
|
||||||
this.maxY = point[1];
|
|
||||||
}
|
|
||||||
if (this.minY === 0 || point[1] < this.minY) {
|
|
||||||
this.minY = point[1];
|
|
||||||
}
|
|
||||||
if (point[0] > this.maxZ) {
|
|
||||||
this.maxZ = point[0];
|
|
||||||
}
|
|
||||||
if (this.minZ === 0 || point[0] < this.minZ) {
|
|
||||||
this.minZ = point[0];
|
|
||||||
}
|
|
||||||
this.data.push({name: name, point: new Vector3(this.seriesNumber, point[1], point[0])});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,145 +0,0 @@
|
|||||||
import RecordRTC from 'recordrtc';
|
|
||||||
import log from "loglevel";
|
|
||||||
import {Observable} from "@babylonjs/core";
|
|
||||||
import {TranscriptType, VoiceTranscript} from "./voiceTranscript";
|
|
||||||
|
|
||||||
type VoiceManagerEvent = {
|
|
||||||
audio_start?: number;
|
|
||||||
audio_end?: number;
|
|
||||||
confidence?: number;
|
|
||||||
text?: string;
|
|
||||||
words?: Array<any>;
|
|
||||||
created?: string;
|
|
||||||
message_type?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class VoiceManager {
|
|
||||||
private socket: WebSocket;
|
|
||||||
private token: string;
|
|
||||||
public readonly transcriptionObserver: Observable<VoiceTranscript> = new Observable<VoiceTranscript>();
|
|
||||||
private recorder: RecordRTC;
|
|
||||||
private data: any[] = [];
|
|
||||||
private logger = log.getLogger('VoiceManager');
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.setupRecorder();
|
|
||||||
}
|
|
||||||
|
|
||||||
public startRecording() {
|
|
||||||
this.connectToVoice();
|
|
||||||
}
|
|
||||||
|
|
||||||
public stopRecording() {
|
|
||||||
this.recorder.reset();
|
|
||||||
this.socket.send('{"terminate_session": true}');
|
|
||||||
this.socket = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async connectToVoice() {
|
|
||||||
const response = await fetch('/.netlify/functions/voice');
|
|
||||||
const data = await response.json();
|
|
||||||
this.token = data.token;
|
|
||||||
if (!this.socket) {
|
|
||||||
this.socket = new WebSocket(`wss://api.assemblyai.com/v2/realtime/ws?sample_rate=16000&token=${this.token}`);
|
|
||||||
this.socket.onmessage = this.messageRecieved;
|
|
||||||
this.socket.onopen = this.socketOpen;
|
|
||||||
this.socket.onclose = this.socketClose;
|
|
||||||
} else {
|
|
||||||
switch (this.socket.readyState) {
|
|
||||||
case 0:
|
|
||||||
this.logger.debug('socket opening');
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
this.logger.debug('socket already open');
|
|
||||||
//await this.recorder.startRecording();
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
this.logger.debug('socket is closing');
|
|
||||||
this.socket = null;
|
|
||||||
//await this.setupConnection();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
this.logger.debug('Socket is closed');
|
|
||||||
this.socket = null;
|
|
||||||
//await this.setupConnection();
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
this.logger.debug(`socket state is unknown: ${this.socket.readyState}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async setupRecorder() {
|
|
||||||
if (!this.recorder) {
|
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({audio: true});
|
|
||||||
this.recorder = new RecordRTC(stream, {
|
|
||||||
type: 'audio', mimeType: 'audio/webm;codecs=pcm', // endpoint requires 16bit PCM audio
|
|
||||||
recorderType: RecordRTC.StereoAudioRecorder, timeSlice: 300, // set 250 ms intervals of data that sends to AAI
|
|
||||||
desiredSampRate: 16000, numberOfAudioChannels: 1, // real-time requires only one channel
|
|
||||||
bufferSize: 4096, audioBitsPerSecond: 128000, ondataavailable: (blob) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = () => {
|
|
||||||
const base64data: string = (reader.result as string);
|
|
||||||
// audio data must be sent as a base64 encoded string
|
|
||||||
if (this.socket && (this.socket.readyState === 1)) {
|
|
||||||
this.socket.send(JSON.stringify({audio_data: base64data.split('base64,')[1]}));
|
|
||||||
} else {
|
|
||||||
this.logger.warn('no socket available');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(blob);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private messageRecieved = (message: any) => {
|
|
||||||
const res = (JSON.parse(message.data) as VoiceManagerEvent);
|
|
||||||
if (this.data) {
|
|
||||||
//this.logger.debug(`Received data: ${JSON.stringify(res)}`);
|
|
||||||
switch (res.message_type) {
|
|
||||||
case 'PartialTranscript':
|
|
||||||
if (res.words.length > 0) {
|
|
||||||
this.logger.debug(`PartialTranscript: ${res.text}`);
|
|
||||||
this.transcriptionObserver.notifyObservers(
|
|
||||||
{
|
|
||||||
text: res.text, words: res.words, confidence: res.confidence,
|
|
||||||
type: TranscriptType.PartialTranscript
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'FinalTranscript':
|
|
||||||
if (res.words.length > 0) {
|
|
||||||
this.transcriptionObserver.notifyObservers(
|
|
||||||
{
|
|
||||||
text: res.text, words: res.words, confidence: res.confidence,
|
|
||||||
type: TranscriptType.FinalTranscript
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case 'SessionBegins':
|
|
||||||
this.logger.debug(`SessionBegins: ${res}`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private socketClose = async () => {
|
|
||||||
this.logger.debug('Socket closed');
|
|
||||||
this.socket = null;
|
|
||||||
this.recorder.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private socketOpen = async () => {
|
|
||||||
this.logger.debug('voice socket opened');
|
|
||||||
if (!this.recorder) {
|
|
||||||
this.logger.error('recorder not initialized');
|
|
||||||
} else {
|
|
||||||
this.recorder.startRecording();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
export type VoiceTranscript = {
|
|
||||||
words: VoiceTranscript[];
|
|
||||||
text: string;
|
|
||||||
type: TranscriptType;
|
|
||||||
confidence: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum TranscriptType {
|
|
||||||
PartialTranscript = 'PartialTranscript',
|
|
||||||
FinalTranscript = 'FinalTranscript'
|
|
||||||
}
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import {Scene, WebXRDefaultExperience} from "@babylonjs/core";
|
import {Scene, WebXRDefaultExperience} from "@babylonjs/core";
|
||||||
import {Controllers} from "../controllers/controllers";
|
|
||||||
import {Handle} from "../objects/handle";
|
import {Handle} from "../objects/handle";
|
||||||
import {DefaultScene} from "../defaultScene";
|
import {DefaultScene} from "../defaultScene";
|
||||||
|
|
||||||
@ -7,12 +6,11 @@ export abstract class AbstractMenu {
|
|||||||
protected handle: Handle;
|
protected handle: Handle;
|
||||||
protected scene: Scene;
|
protected scene: Scene;
|
||||||
protected xr: WebXRDefaultExperience;
|
protected xr: WebXRDefaultExperience;
|
||||||
protected controllers: Controllers;
|
|
||||||
|
|
||||||
protected constructor(xr: WebXRDefaultExperience, controllers: Controllers) {
|
|
||||||
|
protected constructor(xr: WebXRDefaultExperience) {
|
||||||
this.scene = DefaultScene.Scene;
|
this.scene = DefaultScene.Scene;
|
||||||
this.xr = xr;
|
this.xr = xr;
|
||||||
this.controllers = controllers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public toggle() {
|
public toggle() {
|
||||||
|
|||||||
@ -1,37 +0,0 @@
|
|||||||
import {AbstractMesh, Angle, Color3, MeshBuilder, Scene, StandardMaterial, Vector3} from "@babylonjs/core";
|
|
||||||
import log, {Logger} from "loglevel";
|
|
||||||
import {MaptilerMap} from "../maps/maptilerMap";
|
|
||||||
|
|
||||||
export class CameraMenu {
|
|
||||||
private readonly _scene: Scene;
|
|
||||||
private readonly _logger: Logger = log.getLogger('CameraMenu');
|
|
||||||
|
|
||||||
constructor(scene: Scene) {
|
|
||||||
this._scene = scene;
|
|
||||||
this.buildMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildMap() {
|
|
||||||
const maptilerMap = new MaptilerMap('YnvhjBiU8oCWP0GXNdHL', this._scene, 'map-node', 3);
|
|
||||||
maptilerMap.node.position.y = 3;
|
|
||||||
maptilerMap.node.position.z = -4;
|
|
||||||
maptilerMap.node.rotation.y = Math.PI;
|
|
||||||
maptilerMap.node.rotation.x = Angle.FromDegrees(10).radians()
|
|
||||||
maptilerMap.node.scaling = new Vector3(1, 1, 1);
|
|
||||||
maptilerMap.setLocation('loves park, il', 16).then(() => {
|
|
||||||
//maptilerMap.plotPoint(42.33181896128866, -88.86844896012006, this.buildPoint());
|
|
||||||
});
|
|
||||||
maptilerMap.onPickObservable.add((evt) => {
|
|
||||||
maptilerMap.plotPoint(evt.lat, evt.lon, this.buildPoint());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildPoint(): AbstractMesh {
|
|
||||||
const mesh = MeshBuilder.CreateIcoSphere('point', {radius: .02}, this._scene);
|
|
||||||
const material: StandardMaterial = new StandardMaterial('pointMat', this._scene);
|
|
||||||
material.diffuseColor = Color3.Red();
|
|
||||||
mesh.material = material;
|
|
||||||
mesh.isPickable = true;
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
import {AbstractMenu} from "./abstractMenu";
|
|
||||||
import {WebXRDefaultExperience} from "@babylonjs/core";
|
|
||||||
import {Controllers} from "../controllers/controllers";
|
|
||||||
import {makeButton} from "./functions/makeButton";
|
|
||||||
|
|
||||||
//a class called SequenceMenu that extends AbstraceMenu and has three buttons labeled '1', '2', and '3'
|
|
||||||
export class SequenceMenu extends AbstractMenu {
|
|
||||||
constructor(xr: WebXRDefaultExperience, controllers: Controllers) {
|
|
||||||
super(xr, controllers);
|
|
||||||
this.buildMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildMenu() {
|
|
||||||
const button1 = makeButton("1", "1");
|
|
||||||
const button2 = makeButton("2", "1");
|
|
||||||
const button3 = makeButton("3", "1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,198 +0,0 @@
|
|||||||
import {
|
|
||||||
AbstractMesh,
|
|
||||||
Color3,
|
|
||||||
DynamicTexture,
|
|
||||||
InstancedMesh,
|
|
||||||
MeshBuilder,
|
|
||||||
Scene,
|
|
||||||
StandardMaterial,
|
|
||||||
Vector3
|
|
||||||
} from "@babylonjs/core";
|
|
||||||
import {PouchdbPersistenceManager} from "../integration/database/pouchdbPersistenceManager";
|
|
||||||
|
|
||||||
export class NewRelicData {
|
|
||||||
private key: string;
|
|
||||||
private account: string;
|
|
||||||
private data: any[];
|
|
||||||
private readonly scene: Scene;
|
|
||||||
private persistenceManager: PouchdbPersistenceManager;
|
|
||||||
private policyLabels: AbstractMesh[] = [];
|
|
||||||
|
|
||||||
constructor(persistenceManager: PouchdbPersistenceManager, scene: Scene) {
|
|
||||||
this.persistenceManager = persistenceManager;
|
|
||||||
this.scene = scene;
|
|
||||||
this.persistenceManager.getNewRelicData()
|
|
||||||
.then((data) => {
|
|
||||||
this.data = data;
|
|
||||||
this.getNewRelicData().then(() => {
|
|
||||||
this.drawGraph();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public setCredentials(key: string, account: string) {
|
|
||||||
this.key = key;
|
|
||||||
this.account = account;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async clearData() {
|
|
||||||
this.data = [];
|
|
||||||
await this.persistenceManager.setNewRelicData(this.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async getNewRelicData() {
|
|
||||||
if (this.data && this.data.length > 0) {
|
|
||||||
console.warn("Already have data, early return");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await fetch('https://deepdiagram.com/.netlify/functions/nerdgraph', {
|
|
||||||
method: 'POST',
|
|
||||||
credentials: 'include',
|
|
||||||
body: '{"query": "{actor { nrql(query: \\"select * from NrAiIncident \\", accounts: ' + this.account + ') { results } } }"}',
|
|
||||||
headers: {"Api-Key": this.key}
|
|
||||||
});
|
|
||||||
const data = await res.json();
|
|
||||||
if (data?.data?.actor?.nrql?.results) {
|
|
||||||
const newdata = data.data.actor.nrql.results.map((item: any) => {
|
|
||||||
item.id = item.incidentId;
|
|
||||||
item.policyName = item.policyName ? item.policyName : "No Policy";
|
|
||||||
return item
|
|
||||||
});
|
|
||||||
await this.persistenceManager.setNewRelicData(newdata);
|
|
||||||
this.data = newdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public drawGraph() {
|
|
||||||
this.data.sort((a, b) => {
|
|
||||||
return parseInt(a.openTime) - parseInt(b.openTime);
|
|
||||||
});
|
|
||||||
|
|
||||||
const duration = this.data[this.data.length - 1].openTime - this.data[0].openTime;
|
|
||||||
const interval = 10 / duration;
|
|
||||||
const first = parseInt(this.data[0].openTime);
|
|
||||||
const material = new StandardMaterial("material", this.scene);
|
|
||||||
material.diffuseColor = new Color3(0, 0, .7);
|
|
||||||
material.alpha = .3;
|
|
||||||
const baseMesh = MeshBuilder.CreateBox("baseItem", {width: 1, height: 1, depth: 1}, this.scene);
|
|
||||||
baseMesh.material = material;
|
|
||||||
|
|
||||||
const warningMaterial = new StandardMaterial("warningMaterial", this.scene);
|
|
||||||
warningMaterial.diffuseColor = new Color3(.7, .7, .2);
|
|
||||||
warningMaterial.alpha = .5;
|
|
||||||
const warningMesh = MeshBuilder.CreateBox("warningItem", {width: 1, height: 1, depth: 1}, this.scene);
|
|
||||||
warningMesh.material = warningMaterial;
|
|
||||||
|
|
||||||
const criticalMaterial = new StandardMaterial("criticalMaterial", this.scene);
|
|
||||||
criticalMaterial.diffuseColor = new Color3(.9, .2, .2);
|
|
||||||
criticalMaterial.alpha = .7;
|
|
||||||
const criticalMesh = MeshBuilder.CreateBox("criticalItem", {width: 1, height: 1, depth: 1}, this.scene);
|
|
||||||
criticalMesh.material = criticalMaterial;
|
|
||||||
|
|
||||||
|
|
||||||
const policies: Map<String, { x: number, y: number }> = new Map<string, { x: number, y: number }>();
|
|
||||||
this.data.forEach((item) => {
|
|
||||||
const policy = item.policyName ? item.policyName : "No Policy";
|
|
||||||
let x;
|
|
||||||
let y: number = 0;
|
|
||||||
if (policies.has(policy)) {
|
|
||||||
const value = policies.get(policy);
|
|
||||||
x = value.x;
|
|
||||||
y = value.y + .105;
|
|
||||||
policies.set(policy, {x, y});
|
|
||||||
} else {
|
|
||||||
policies.set(policy, {x: policies.size / 10, y: 0});
|
|
||||||
x = policies.get(policy).x;
|
|
||||||
const policyLabel = this.buildText(policy);
|
|
||||||
policyLabel.scaling = new Vector3(3, 3, 3);
|
|
||||||
policyLabel.position = new Vector3(x, .4, 0);
|
|
||||||
policyLabel.rotation.x = Math.PI / 2;
|
|
||||||
policyLabel.rotation.y = -Math.PI / 2;
|
|
||||||
|
|
||||||
this.policyLabels.push(policyLabel);
|
|
||||||
}
|
|
||||||
const start = parseInt(item.openTime) - first;
|
|
||||||
let end = duration;
|
|
||||||
if (item.closeTime) {
|
|
||||||
end = parseInt(item.closeTime) - first;
|
|
||||||
}
|
|
||||||
let box: AbstractMesh;
|
|
||||||
switch (item.priority) {
|
|
||||||
case "critical":
|
|
||||||
box = new InstancedMesh(item.id, criticalMesh);
|
|
||||||
break;
|
|
||||||
case "warning":
|
|
||||||
box = new InstancedMesh(item.id, warningMesh);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
box = new InstancedMesh(item.id, baseMesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
box.position = new Vector3(x, y + .5, (start * interval));
|
|
||||||
if (item.closeTime) {
|
|
||||||
box.scaling = new Vector3(.1, .1, (end - start) * interval);
|
|
||||||
} else {
|
|
||||||
box.scaling = new Vector3(.1, .1, .01);
|
|
||||||
}
|
|
||||||
box.position.z = box.position.z + box.scaling.z / 2;
|
|
||||||
|
|
||||||
const startLabel = this.buildText(new Date(start + first).toLocaleString());
|
|
||||||
startLabel.position = box.position.add(new Vector3(.05, .05, 0));
|
|
||||||
startLabel.position.z = (start * interval) - .01;
|
|
||||||
|
|
||||||
const endLabel = this.buildText(new Date(end + first).toLocaleString());
|
|
||||||
endLabel.position = box.position.add(new Vector3(.05, .05, 0));
|
|
||||||
endLabel.position.z = (end * interval) + .01;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
this.scene.onBeforeRenderObservable.add(() => {
|
|
||||||
this.policyLabels.forEach((label) => {
|
|
||||||
label.position.z = this.scene.activeCamera.globalPosition.z;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildText(text: string) {
|
|
||||||
//Set font
|
|
||||||
const height = 0.03;
|
|
||||||
const font_size = 24;
|
|
||||||
const font = "bold " + font_size + "px Arial";
|
|
||||||
//Set height for dynamic texture
|
|
||||||
const DTHeight = 1.5 * font_size; //or set as wished
|
|
||||||
//Calc Ratio
|
|
||||||
const ratio = height / DTHeight;
|
|
||||||
|
|
||||||
//Use a temporary dynamic texture to calculate the length of the text on the dynamic texture canvas
|
|
||||||
const temp = new DynamicTexture("DynamicTexture", 32, this.scene);
|
|
||||||
const tmpctx = temp.getContext();
|
|
||||||
tmpctx.font = font;
|
|
||||||
const DTWidth = tmpctx.measureText(text).width + 8;
|
|
||||||
|
|
||||||
//Calculate width the plane has to be
|
|
||||||
const planeWidth = DTWidth * ratio;
|
|
||||||
|
|
||||||
//Create dynamic texture and write the text
|
|
||||||
const dynamicTexture = new DynamicTexture("DynamicTexture", {
|
|
||||||
width: DTWidth,
|
|
||||||
height: DTHeight
|
|
||||||
}, this.scene, false);
|
|
||||||
const mat = new StandardMaterial("mat", this.scene);
|
|
||||||
mat.diffuseTexture = dynamicTexture;
|
|
||||||
dynamicTexture.drawText(text, null, null, font, "#000000", "#ffffff", true);
|
|
||||||
|
|
||||||
//Create plane and set dynamic texture as material
|
|
||||||
const plane = MeshBuilder.CreatePlane("text", {width: planeWidth, height: height}, this.scene);
|
|
||||||
|
|
||||||
plane.material = mat;
|
|
||||||
|
|
||||||
return plane;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
import {AbstractMenu} from "../menus/abstractMenu";
|
|
||||||
import {Scene, WebXRDefaultExperience} from "@babylonjs/core";
|
|
||||||
import {Controllers} from "../controllers/controllers";
|
|
||||||
import log, {Logger} from "loglevel";
|
|
||||||
import {Grid} from "@babylonjs/gui";
|
|
||||||
|
|
||||||
export class NewRelicMenu extends AbstractMenu {
|
|
||||||
private logger: Logger = log.getLogger('NewRelicMenu');
|
|
||||||
|
|
||||||
constructor(scene: Scene, xr: WebXRDefaultExperience, controllers: Controllers) {
|
|
||||||
super(scene, xr, controllers);
|
|
||||||
this.buildMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
buildMenu() {
|
|
||||||
this.logger.debug('buildMenu');
|
|
||||||
//this.makeButton("credentials", "credentials");
|
|
||||||
const grid = new Grid("grid");
|
|
||||||
grid.addColumnDefinition(.5);
|
|
||||||
grid.addColumnDefinition(.5);
|
|
||||||
grid.addRowDefinition(.5);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleClick(_info, state) {
|
|
||||||
this.logger.debug("clicked " + state.currentTarget.name);
|
|
||||||
switch (state.currentTarget.name) {
|
|
||||||
case "credentials":
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -13,7 +13,7 @@ export function MainMenu({onClick}) {
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div className="overlay mini" id="main">
|
<div className="overlay mini" id="main">
|
||||||
<img alte="deep diagram logo" height="120" src="/assets/ddd.svg" width="320"/>
|
<img alt="deep diagram logo" height="120" src="/assets/ddd.svg" width="320"/>
|
||||||
<div id="enterXR" className="inactive"><a href="#" id="enterVRLink">Enter VR</a></div>
|
<div id="enterXR" className="inactive"><a href="#" id="enterVRLink">Enter VR</a></div>
|
||||||
<QuestLink/>
|
<QuestLink/>
|
||||||
|
|
||||||
|
|||||||
@ -1,72 +0,0 @@
|
|||||||
import {
|
|
||||||
AbstractMesh,
|
|
||||||
MeshBuilder,
|
|
||||||
PhysicsAggregate,
|
|
||||||
PhysicsShapeType,
|
|
||||||
Scene,
|
|
||||||
SceneLoader,
|
|
||||||
TransformNode,
|
|
||||||
Vector3
|
|
||||||
} from "@babylonjs/core";
|
|
||||||
import {ControllerEventType, Controllers} from "../controllers/controllers";
|
|
||||||
import log, {Logger} from "loglevel";
|
|
||||||
|
|
||||||
export class Ball {
|
|
||||||
private readonly logger: Logger = log.getLogger('Ball');
|
|
||||||
private readonly scene: Scene;
|
|
||||||
private transformNode: TransformNode;
|
|
||||||
private mesh: AbstractMesh;
|
|
||||||
_position: Vector3 = new Vector3(0, .5, 0);
|
|
||||||
private parent: AbstractMesh;
|
|
||||||
private controllers: Controllers;
|
|
||||||
private physicsAggregate: PhysicsAggregate;
|
|
||||||
|
|
||||||
constructor(scene: Scene) {
|
|
||||||
this.scene = scene;
|
|
||||||
this.buildBall();
|
|
||||||
}
|
|
||||||
|
|
||||||
public setControllers(controllers: Controllers) {
|
|
||||||
this.controllers = controllers;
|
|
||||||
this.controllers.controllerObservable.add((event) => {
|
|
||||||
if (event.type == ControllerEventType.MOTION) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public kick(direction: Vector3, force: number) {
|
|
||||||
this.physicsAggregate.body.applyImpulse(direction.scale(force), Vector3.Zero());
|
|
||||||
}
|
|
||||||
|
|
||||||
public get position(): Vector3 {
|
|
||||||
return this.physicsAggregate.transformNode.absolutePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildBall() {
|
|
||||||
SceneLoader.ImportMesh(null, "/assets/models/", "ball.gltf", this.scene,
|
|
||||||
(meshes) => {
|
|
||||||
this.logger.debug('ball loaded');
|
|
||||||
this.mesh = meshes[0];
|
|
||||||
this.parent = MeshBuilder.CreateSphere("ballParent", {diameter: .17}, this.scene);
|
|
||||||
|
|
||||||
this.parent.isVisible = false;
|
|
||||||
this.parent.position = this._position;
|
|
||||||
|
|
||||||
this.scene.onBeforeRenderObservable.add(() => {
|
|
||||||
if (!this.physicsAggregate &&
|
|
||||||
this.scene?.getPhysicsEngine()?.getPhysicsPlugin()) {
|
|
||||||
this.logger.debug("creating physics aggregate");
|
|
||||||
this.physicsAggregate = new PhysicsAggregate(this.parent,
|
|
||||||
PhysicsShapeType.SPHERE, {mass: 1, restitution: .6, friction: .6}, this.scene);
|
|
||||||
this.physicsAggregate.body.setLinearDamping(.3);
|
|
||||||
this.physicsAggregate.body.setAngularDamping(2);
|
|
||||||
this.mesh.setParent(this.physicsAggregate.transformNode);
|
|
||||||
this.mesh.position.y = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}, -1, false, this, false);
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,141 +0,0 @@
|
|||||||
import {
|
|
||||||
InstancedMesh,
|
|
||||||
Mesh,
|
|
||||||
MeshBuilder,
|
|
||||||
Scene,
|
|
||||||
StandardMaterial,
|
|
||||||
TransformNode,
|
|
||||||
Vector2,
|
|
||||||
Vector3
|
|
||||||
} from "@babylonjs/core";
|
|
||||||
import {Ball} from "./ball";
|
|
||||||
import {Team} from "./team";
|
|
||||||
|
|
||||||
export class Field {
|
|
||||||
private readonly scene: Scene;
|
|
||||||
public ball: Ball;
|
|
||||||
private readonly goalMesh: Mesh;
|
|
||||||
private material: StandardMaterial;
|
|
||||||
private team1: Team;
|
|
||||||
private readonly fieldCenter: TransformNode;
|
|
||||||
private team2: Team;
|
|
||||||
public gazePoint: Vector3;
|
|
||||||
|
|
||||||
constructor(scene: Scene) {
|
|
||||||
this.scene = scene;
|
|
||||||
this.fieldCenter = new TransformNode("fieldCenter", this.scene);
|
|
||||||
this.team1 = new Team(scene, 1, "one");
|
|
||||||
this.team2 = new Team(scene, -1, "two");
|
|
||||||
|
|
||||||
this.goalMesh = MeshBuilder.CreateCylinder("goalPost", {diameter: .1, height: 1}, this.scene);
|
|
||||||
this.material = new StandardMaterial("material", this.scene);
|
|
||||||
this.material.diffuseColor.set(1, 1, 1);
|
|
||||||
this.material.alpha = .5;
|
|
||||||
this.goalMesh.material = this.getMaterial();
|
|
||||||
this.goalMesh.setEnabled(false);
|
|
||||||
this.ball = new Ball(this.scene);
|
|
||||||
this.buildField();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private buildField() {
|
|
||||||
const width = .08;
|
|
||||||
this.buildLine(new Vector2(35, 0), new Vector2(width, 100));
|
|
||||||
this.buildLine(new Vector2(-35, 0), new Vector2(width, 100));
|
|
||||||
this.buildLine(new Vector2(-9.16, 50 - 2.75), new Vector2(width, 5.5 - width));
|
|
||||||
this.buildLine(new Vector2(9.16, 50 - 2.75), new Vector2(width, 5.5 - width));
|
|
||||||
this.buildLine(new Vector2(-9.16, -50 + 2.75), new Vector2(width, 5.5 - width));
|
|
||||||
this.buildLine(new Vector2(9.16, -50 + 2.75), new Vector2(width, 5.5 - width));
|
|
||||||
|
|
||||||
this.buildLine(new Vector2(-18.33, 50 - 8.25), new Vector2(width, 16.5 - width));
|
|
||||||
this.buildLine(new Vector2(18.33, 50 - 8.25), new Vector2(width, 16.5 - width));
|
|
||||||
this.buildLine(new Vector2(-18.33, -50 + 8.25), new Vector2(width, 16.5 - width));
|
|
||||||
this.buildLine(new Vector2(18.33, -50 + 8.25), new Vector2(width, 16.5 - width));
|
|
||||||
|
|
||||||
this.buildLine(new Vector2(0, -50), new Vector2(70 - width, width));
|
|
||||||
this.buildLine(new Vector2(0, 50), new Vector2(70 - width, width));
|
|
||||||
|
|
||||||
this.buildLine(new Vector2(0, -44.5), new Vector2(18.32 + width, width));
|
|
||||||
this.buildLine(new Vector2(0, 44.5), new Vector2(18.32 + width, width));
|
|
||||||
|
|
||||||
this.buildLine(new Vector2(0, -33.5), new Vector2(36.66 + width, width));
|
|
||||||
this.buildLine(new Vector2(0, 33.5), new Vector2(36.66 + width, width));
|
|
||||||
|
|
||||||
this.buildCircle(new Vector2(0, 50 - 11));
|
|
||||||
this.buildCircle(new Vector2(0, -50 + 11));
|
|
||||||
|
|
||||||
|
|
||||||
this.buildLine(new Vector2(0, 0), new Vector2(70 - width, width));
|
|
||||||
this.buildArc(new Vector2(0, 0));
|
|
||||||
this.buildArc(new Vector2(0, 50 - 11), Math.PI / 11, Math.PI / 1.275);
|
|
||||||
this.buildArc(new Vector2(0, -50 + 11), Math.PI / 11, (Math.PI / 1.275) - Math.PI);
|
|
||||||
this.buildGoalPost(new Vector2(3.66, -50));
|
|
||||||
this.buildGoalPost(new Vector2(-3.66, -50));
|
|
||||||
this.buildGoalPost(new Vector2(3.66, 50));
|
|
||||||
this.buildGoalPost(new Vector2(-3.66, 50));
|
|
||||||
this.buildGoalPost(new Vector2(0, 50), false, 7.32, 2.44);
|
|
||||||
this.buildGoalPost(new Vector2(0, -50), false, 7.32, 2.44);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildGoalPost(position: Vector2, vertical: boolean = true, length: number = 2.44, y: number = 0) {
|
|
||||||
const goalPost = new InstancedMesh("goalPost", this.goalMesh);
|
|
||||||
goalPost.position.x = position.x;
|
|
||||||
goalPost.position.z = position.y;
|
|
||||||
if (!vertical) {
|
|
||||||
goalPost.rotation.z = Math.PI / 2;
|
|
||||||
goalPost.position.y = y;
|
|
||||||
} else {
|
|
||||||
goalPost.position.y = length / 2;
|
|
||||||
}
|
|
||||||
goalPost.scaling.y = length;
|
|
||||||
goalPost.visibility = 1;
|
|
||||||
goalPost.setParent(this.fieldCenter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildCircle(position: Vector2) {
|
|
||||||
const circle = MeshBuilder.CreateDisc("disc", {radius: .25, tessellation: 180}, this.scene);
|
|
||||||
circle.position.x = position.x;
|
|
||||||
circle.position.z = position.y;
|
|
||||||
circle.position.y = .01;
|
|
||||||
circle.rotation.x = Math.PI / 2;
|
|
||||||
circle.material = this.getMaterial();
|
|
||||||
circle.setParent(this.fieldCenter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildArc(position: Vector2, arc: number = Math.PI, rotation: number = 0) {
|
|
||||||
const myShape = [
|
|
||||||
new Vector3(1, 0, 0),
|
|
||||||
new Vector3(1, 0, 1.012),
|
|
||||||
new Vector3(.975, 0, 1.012)
|
|
||||||
];
|
|
||||||
const circle = MeshBuilder.CreateLathe("lathe", {
|
|
||||||
arc: arc,
|
|
||||||
shape: myShape, radius: 9.15, tessellation: 180
|
|
||||||
}, this.scene);
|
|
||||||
circle.material = this.getMaterial();
|
|
||||||
circle.position.y = 0.01;
|
|
||||||
circle.position.x = position.x;
|
|
||||||
circle.position.z = position.y;
|
|
||||||
circle.rotation = new Vector3(0, rotation, 0);
|
|
||||||
circle.setParent(this.fieldCenter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getMaterial(): StandardMaterial {
|
|
||||||
const material = new StandardMaterial("material", this.scene);
|
|
||||||
material.diffuseColor.set(1, 1, 1);
|
|
||||||
material.alpha = .5;
|
|
||||||
return material;
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildLine(position: Vector2, shape: Vector2) {
|
|
||||||
const line = MeshBuilder.CreatePlane("line", {width: shape.x, height: shape.y}, this.scene);
|
|
||||||
line.material = this.getMaterial();
|
|
||||||
line.rotation.x = Math.PI / 2;
|
|
||||||
line.position.y = .01;
|
|
||||||
line.position.x = position.x;
|
|
||||||
line.position.z = position.y;
|
|
||||||
line.setParent(this.fieldCenter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,149 +0,0 @@
|
|||||||
import {
|
|
||||||
AbstractMesh,
|
|
||||||
AnimationGroup,
|
|
||||||
AssetContainer,
|
|
||||||
Mesh,
|
|
||||||
MeshBuilder,
|
|
||||||
Observable,
|
|
||||||
PBRMaterial,
|
|
||||||
PhysicsAggregate,
|
|
||||||
PhysicsMotionType,
|
|
||||||
PhysicsShapeType,
|
|
||||||
Scene,
|
|
||||||
SceneLoader,
|
|
||||||
Skeleton,
|
|
||||||
Texture,
|
|
||||||
Vector2,
|
|
||||||
Vector3
|
|
||||||
} from "@babylonjs/core";
|
|
||||||
import log, {Logger} from "loglevel";
|
|
||||||
|
|
||||||
export class PlayerFactory {
|
|
||||||
private readonly logger: Logger = log.getLogger('PlayerFactory')
|
|
||||||
public onReadyObservable: Observable<any> = new Observable();
|
|
||||||
private readonly scene: Scene;
|
|
||||||
private container: AssetContainer;
|
|
||||||
|
|
||||||
constructor(scene: Scene) {
|
|
||||||
this.scene = scene;
|
|
||||||
SceneLoader.LoadAssetContainer("/assets/models/",
|
|
||||||
"player2.glb",
|
|
||||||
this.scene,
|
|
||||||
(container: AssetContainer) => {
|
|
||||||
this.container = container;
|
|
||||||
this.onReadyObservable.notifyObservers(this);
|
|
||||||
this.logger.debug('Player Model Loaded');
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public buildPlayer(position: Vector3, number: number, uniformTexture: Texture = null, teamName: string = "team"): Player {
|
|
||||||
this.logger.debug(`Building player #${number}, for team ${teamName}`);
|
|
||||||
return new Player(this.scene, position, this.container, number, uniformTexture, teamName);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Player {
|
|
||||||
private readonly logger: Logger = log.getLogger('Player');
|
|
||||||
public readonly onReadyObservable: Observable<any> = new Observable();
|
|
||||||
private readonly scene: Scene;
|
|
||||||
private readonly position: Vector3;
|
|
||||||
private mesh: Mesh;
|
|
||||||
private parent: AbstractMesh;
|
|
||||||
private animationGroup: AnimationGroup;
|
|
||||||
private physicsAggregate: PhysicsAggregate;
|
|
||||||
private skeleton: Skeleton;
|
|
||||||
private readonly number: number;
|
|
||||||
private readonly teamName: string;
|
|
||||||
private forward = true;
|
|
||||||
private destination: Vector2;
|
|
||||||
|
|
||||||
constructor(scene: Scene, position: Vector3, container: AssetContainer, number: number = 0, texture: Texture = null, teamName: string = "team") {
|
|
||||||
this.scene = scene;
|
|
||||||
this.position = position;
|
|
||||||
this.number = number;
|
|
||||||
this.teamName = teamName;
|
|
||||||
const data = container.instantiateModelsToScene(undefined, false, {doNotInstantiate: true});
|
|
||||||
this.mesh = (data.rootNodes[0] as Mesh);
|
|
||||||
if (texture) {
|
|
||||||
((this.mesh.getChildren()[0].getChildren()[2] as Mesh).material as PBRMaterial).albedoTexture = texture;
|
|
||||||
// (this.mesh.material as PBRMaterial).albedoTexture = texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.skeleton = data.skeletons[0];
|
|
||||||
this.animationGroup = data.animationGroups[6];
|
|
||||||
this.buildPlayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public lookAt(location: Vector2) {
|
|
||||||
const body = this.physicsAggregate.body;
|
|
||||||
|
|
||||||
body.disablePreStep = false;
|
|
||||||
|
|
||||||
body.transformNode.lookAt(new Vector3(location.x, body.transformNode.position.y, location.y));
|
|
||||||
this.scene.onAfterRenderObservable.addOnce(() => {
|
|
||||||
|
|
||||||
this.physicsAggregate.body.disablePreStep = true;
|
|
||||||
this.animationGroup.stop();
|
|
||||||
this.animationGroup.onAnimationGroupEndObservable.add(() => {
|
|
||||||
if (this.forward) {
|
|
||||||
this.animationGroup.start(false, .1, 256, 267);
|
|
||||||
} else {
|
|
||||||
this.animationGroup.start(false, .1, 267, 256);
|
|
||||||
}
|
|
||||||
this.forward = !this.forward;
|
|
||||||
}, -1, false, this);
|
|
||||||
this.animationGroup.start(false, .1, 256, 267);
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public runTo(location: Vector2) {
|
|
||||||
this.logger.debug(`Running to ${JSON.stringify(location)}`)
|
|
||||||
this.destination = location;
|
|
||||||
const body = this.physicsAggregate.transformNode.physicsBody;
|
|
||||||
body.setMotionType(PhysicsMotionType.ANIMATED);
|
|
||||||
body.disablePreStep = false;
|
|
||||||
body.transformNode.lookAt(new Vector3(location.x, body.transformNode.position.y, location.y));
|
|
||||||
const vel = new Vector3(location.x, body.transformNode.position.y, location.y);
|
|
||||||
this.scene.onBeforeRenderObservable.addOnce(() => {
|
|
||||||
body.setLinearVelocity(vel.subtract(body.transformNode.position).normalize().scale(2));
|
|
||||||
});
|
|
||||||
this.scene.onAfterRenderObservable.addOnce(() => {
|
|
||||||
this.physicsAggregate.body.disablePreStep = true;
|
|
||||||
this.animationGroup.stop();
|
|
||||||
this.animationGroup.start(true, 1.0, 0, 250);
|
|
||||||
});
|
|
||||||
this.scene.onAfterPhysicsObservable.add(() => {
|
|
||||||
if (body.getLinearVelocity().length() > .1) {
|
|
||||||
|
|
||||||
if (this.destination.subtract(new Vector2(body.transformNode.position.x,
|
|
||||||
body.transformNode.position.z)).length() < .1) {
|
|
||||||
body.setLinearVelocity(Vector3.Zero());
|
|
||||||
body.setMotionType(PhysicsMotionType.DYNAMIC);
|
|
||||||
this.animationGroup.stop();
|
|
||||||
this.animationGroup.start(false, .1, 256, 267);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildPlayer() {
|
|
||||||
this.parent = MeshBuilder.CreateCylinder(`team${this.teamName}player${this.number}`, {
|
|
||||||
diameter: .5,
|
|
||||||
height: 1.6
|
|
||||||
}, this.scene);
|
|
||||||
this.parent.position = this.position;
|
|
||||||
this.parent.isVisible = false;
|
|
||||||
this.physicsAggregate = new PhysicsAggregate(this.parent,
|
|
||||||
PhysicsShapeType.CYLINDER, {mass: 100, restitution: .02, friction: .3}, this.scene);
|
|
||||||
this.physicsAggregate.body.setAngularDamping(.5);
|
|
||||||
|
|
||||||
this.mesh.parent = this.physicsAggregate.transformNode;
|
|
||||||
this.mesh.metadata = {type: "player", grabbable: true};
|
|
||||||
this.mesh.position.x = 3;
|
|
||||||
this.mesh.position.y = -.84;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,201 +0,0 @@
|
|||||||
import {Color3, MeshBuilder, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
|
|
||||||
import {AbstractMenu} from "../menus/abstractMenu";
|
|
||||||
import {ControllerEvent, ControllerEventType, Controllers} from "../controllers/controllers";
|
|
||||||
import {Control3D, GUI3DManager, PlanePanel, Slider3D} from "@babylonjs/gui";
|
|
||||||
import log, {Logger} from "loglevel";
|
|
||||||
import {Field} from "./field";
|
|
||||||
import {makeButton} from "../menus/functions/makeButton";
|
|
||||||
|
|
||||||
|
|
||||||
enum SoccerMenuState {
|
|
||||||
PLAY,
|
|
||||||
PLAN,
|
|
||||||
TRAIN,
|
|
||||||
NONE
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SoccerMenu extends AbstractMenu {
|
|
||||||
private manager: GUI3DManager;
|
|
||||||
private state: SoccerMenuState = SoccerMenuState.NONE;
|
|
||||||
private readonly field: Field;
|
|
||||||
private readonly logger: Logger = log.getLogger('SoccerMenu')
|
|
||||||
private startTime: number;
|
|
||||||
private startPosition: Vector3;
|
|
||||||
|
|
||||||
constructor(xr: WebXRDefaultExperience, controllers: Controllers) {
|
|
||||||
super(xr, controllers);
|
|
||||||
this.field = new Field(this.scene);
|
|
||||||
this.manager = new GUI3DManager(this.scene);
|
|
||||||
|
|
||||||
this.controllers.controllerObservable.add(this.controllerEventHandler, -1, false, this);
|
|
||||||
this.buildMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
private controllerEventHandler(event: ControllerEvent) {
|
|
||||||
switch (this.state) {
|
|
||||||
case SoccerMenuState.PLAY:
|
|
||||||
this.playControllerEventHandler(event);
|
|
||||||
break;
|
|
||||||
case SoccerMenuState.PLAN:
|
|
||||||
break;
|
|
||||||
case SoccerMenuState.TRAIN:
|
|
||||||
break;
|
|
||||||
case SoccerMenuState.NONE:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private forceFactor: number = 10;
|
|
||||||
|
|
||||||
private buildKickLine(direction: Vector3, force: number) {
|
|
||||||
|
|
||||||
const start = this.field.ball.position.clone();
|
|
||||||
const line = MeshBuilder.CreateLines("kickLine", {points: [start, start.add(direction.scale(force))]}, this.scene);
|
|
||||||
line.color = new Color3(1, 1, .5);
|
|
||||||
line.isPickable = false;
|
|
||||||
setTimeout(() => {
|
|
||||||
line.dispose();
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
makeSlider(name: string): Control3D {
|
|
||||||
const slider = new Slider3D(name, false);
|
|
||||||
slider.scaling.x = 2;
|
|
||||||
slider.minimum = 10;
|
|
||||||
slider.maximum = 30;
|
|
||||||
|
|
||||||
slider.value = this.forceFactor;
|
|
||||||
|
|
||||||
slider.onValueChangedObservable.add((value) => {
|
|
||||||
this.logger.debug(`slider value ${value}`);
|
|
||||||
this.forceFactor = value;
|
|
||||||
});
|
|
||||||
return slider;
|
|
||||||
}
|
|
||||||
|
|
||||||
private playControllerEventHandler(event: ControllerEvent) {
|
|
||||||
switch (event.type) {
|
|
||||||
case ControllerEventType.TRIGGER:
|
|
||||||
if (event.value > .8) {
|
|
||||||
if (!this.startTime) {
|
|
||||||
this.startTime = new Date().getTime();
|
|
||||||
const start = event.controller.grip.absolutePosition.clone();
|
|
||||||
//transform start to this.xr.baseExperience.camera space
|
|
||||||
start.subtractInPlace(this.xr.baseExperience.camera.globalPosition);
|
|
||||||
//const e = this.xr.baseExperience.camera.absoluteRotation.toEulerAngles();
|
|
||||||
//start.applyRotationQuaternionInPlace(Quaternion.FromEulerAngles(0, e.y, 0));
|
|
||||||
this.startPosition = start;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.startTime) {
|
|
||||||
const end = event.controller.grip.absolutePosition.clone();
|
|
||||||
//transform start to this.xr.baseExperience.camera space
|
|
||||||
end.subtractInPlace(this.xr.baseExperience.camera.globalPosition);
|
|
||||||
//const e = this.xr.baseExperience.camera.absoluteRotation.toEulerAngles();
|
|
||||||
//end.applyRotationQuaternionInPlace(Quaternion.FromEulerAngles(0, e.y, 0));
|
|
||||||
if (this.startTime && this.startPosition) {
|
|
||||||
const duration = new Date().getTime() - this.startTime;
|
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
|
||||||
type: ControllerEventType.MOTION,
|
|
||||||
startPosition: this.startPosition,
|
|
||||||
endPosition: end,
|
|
||||||
duration: duration
|
|
||||||
});
|
|
||||||
this.startTime = null;
|
|
||||||
this.startPosition = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const worldRay = this.scene.activeCamera.getForwardRay();
|
|
||||||
worldRay.origin = this.scene.activeCamera.globalPosition;
|
|
||||||
const pickInfo = this.scene.pickWithRay(worldRay, function (mesh) {
|
|
||||||
return mesh.name != 'platform';
|
|
||||||
});
|
|
||||||
if (pickInfo?.hit) {
|
|
||||||
const circle = MeshBuilder.CreateDisc("circle", {radius: .04}, this.scene);
|
|
||||||
|
|
||||||
const normal = pickInfo.getNormal(true, false).scale(-1);
|
|
||||||
circle.position = pickInfo.pickedPoint.add(normal.scale(-.01));
|
|
||||||
circle.lookAt(pickInfo.pickedPoint.add(normal));
|
|
||||||
setTimeout(() => {
|
|
||||||
circle.dispose();
|
|
||||||
}, 1500);
|
|
||||||
|
|
||||||
if (pickInfo?.pickedMesh?.name == 'Football Ball.001') {
|
|
||||||
this.controllers.controllerObservable.notifyObservers({
|
|
||||||
type: ControllerEventType.GAZEPOINT,
|
|
||||||
endPosition: pickInfo.pickedPoint,
|
|
||||||
startPosition: this.xr.baseExperience.camera.globalPosition
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const mesh = this.scene.getPointerOverMesh();
|
|
||||||
if (mesh) {
|
|
||||||
const meta = mesh?.parent?.parent?.parent
|
|
||||||
if (meta) {
|
|
||||||
this.logger.debug(meta.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ControllerEventType.MOTION:
|
|
||||||
const start = event.startPosition.clone();
|
|
||||||
const direction = start.subtract(event.endPosition);
|
|
||||||
const force = direction.length() * this.forceFactor;
|
|
||||||
const dir = direction.normalize();
|
|
||||||
//const e = this.xr.baseExperience.camera.absoluteRotation.toEulerAngles();
|
|
||||||
//direction.applyRotationQuaternionInPlace(Quaternion.FromEulerAngles(0, e.y, 0));
|
|
||||||
this.buildKickLine(dir, force);
|
|
||||||
this.field.ball.kick(dir, force);
|
|
||||||
break;
|
|
||||||
case ControllerEventType.GAZEPOINT:
|
|
||||||
if (event.endPosition) {
|
|
||||||
this.field.gazePoint = event.endPosition.clone();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
makeButton(name: string, id: string) {
|
|
||||||
const button = makeButton(name, id);
|
|
||||||
button.onPointerClickObservable.add(this.handleClick, -1, false, this);
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildMenu() {
|
|
||||||
const panel = new PlanePanel();
|
|
||||||
this.manager.addControl(panel);
|
|
||||||
panel.columns = 10;
|
|
||||||
panel.addControl(makeButton("Play", "play"));
|
|
||||||
panel.addControl(makeButton("Plan", "plan"));
|
|
||||||
panel.addControl(makeButton("Train", "Train"));
|
|
||||||
panel.addControl(makeButton("Modify", "modify"));
|
|
||||||
const slider = panel.addControl(this.makeSlider("force"));
|
|
||||||
|
|
||||||
this.manager.rootContainer.children[0].node.position.y = .2;
|
|
||||||
this.manager.controlScaling = .2;
|
|
||||||
//panel.updateLayout();
|
|
||||||
//slider.position.x = 1;
|
|
||||||
//this.createHandle(this.manager.rootContainer.children[0].node);
|
|
||||||
//this.handle.mesh.position = getFrontPosition(3, this.scene).add(new Vector3(0, .5, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleClick(_info, state) {
|
|
||||||
this.logger.debug("clicked " + state.currentTarget.name);
|
|
||||||
switch (state.currentTarget.name) {
|
|
||||||
case "play":
|
|
||||||
this.state = SoccerMenuState.PLAY;
|
|
||||||
break;
|
|
||||||
case "plan":
|
|
||||||
this.state = SoccerMenuState.PLAN;
|
|
||||||
break;
|
|
||||||
case "train":
|
|
||||||
this.state = SoccerMenuState.TRAIN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
import {Player, PlayerFactory} from "./player";
|
|
||||||
import {Scene, Texture, Vector2, Vector3} from "@babylonjs/core";
|
|
||||||
|
|
||||||
export class Team {
|
|
||||||
private readonly scene: Scene;
|
|
||||||
private players: Player[] = [];
|
|
||||||
private readonly goalSide: number = -1;
|
|
||||||
private playerFactory: PlayerFactory;
|
|
||||||
private positions: Vector2[] = [
|
|
||||||
new Vector2(3, 1),
|
|
||||||
new Vector2(-3, 1),
|
|
||||||
new Vector2(5, 2),
|
|
||||||
new Vector2(15, 5),
|
|
||||||
new Vector2(-15, 5),
|
|
||||||
new Vector2(2, 10),
|
|
||||||
new Vector2(-2, 15),
|
|
||||||
new Vector2(15, 20),
|
|
||||||
new Vector2(-15, 20),
|
|
||||||
new Vector2(0, 35),
|
|
||||||
new Vector2(0, 47),
|
|
||||||
];
|
|
||||||
|
|
||||||
private readonly name: string;
|
|
||||||
private uniforms: Texture[] = [];
|
|
||||||
constructor(scene: Scene, side: number = 1, name: string = "team") {
|
|
||||||
this.scene = scene;
|
|
||||||
this.goalSide = side;
|
|
||||||
this.name = name;
|
|
||||||
this.uniforms.push(new Texture("/assets/textures/team1.png", this.scene))
|
|
||||||
this.uniforms.push(new Texture("/assets/textures/team2.png", this.scene))
|
|
||||||
|
|
||||||
this.playerFactory = new PlayerFactory(this.scene);
|
|
||||||
this.playerFactory.onReadyObservable.add(() => {
|
|
||||||
this.buildTeam();
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildTeam() {
|
|
||||||
for (let i = 0; i < 11; i++) {
|
|
||||||
const player = this.playerFactory
|
|
||||||
.buildPlayer(new Vector3(this.positions[i].x * this.goalSide, 1, this.positions[i].y * this.goalSide), i,
|
|
||||||
this.uniforms[this.goalSide == 1 ? 0 : 1],
|
|
||||||
this.name);
|
|
||||||
player.lookAt(new Vector2(0, -50 * this.goalSide))
|
|
||||||
this.players.push(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,24 +7,12 @@ export class AnimatedLineTexture {
|
|||||||
|
|
||||||
public static Texture() {
|
public static Texture() {
|
||||||
if (!AnimatedLineTexture._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 = new Texture('/assets/textures/arrow.png', DefaultScene.Scene);
|
this._texture = new Texture('/assets/textures/arrow.png', DefaultScene.Scene);
|
||||||
//this._texture.wrapU = RawTexture.WRAP_ADDRESSMODE
|
this._texture.name = 'connection-texture';
|
||||||
this._texture.name = 'blue-white-texture';
|
|
||||||
this._texture.uScale = 30;
|
this._texture.uScale = 30;
|
||||||
DefaultScene.Scene.onBeforeRenderObservable.add(() => {
|
DefaultScene.Scene.onBeforeRenderObservable.add(() => {
|
||||||
this._texture.uOffset -= 0.01 * DefaultScene.Scene.getAnimationRatio()
|
this._texture.uOffset -= 0.01 * DefaultScene.Scene.getAnimationRatio()
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
return this._texture;
|
return this._texture;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,111 +0,0 @@
|
|||||||
import {Scene, Sound} from "@babylonjs/core";
|
|
||||||
|
|
||||||
export class DiaSounds {
|
|
||||||
private readonly scene: Scene;
|
|
||||||
private readonly _tick: Sound;
|
|
||||||
|
|
||||||
constructor(scene: Scene) {
|
|
||||||
this.scene = scene;
|
|
||||||
const soundSprite = [
|
|
||||||
{obj: "_enter", name: "enter", url: "/assets/sounds/sounds.mp3"},
|
|
||||||
{obj: "_exit", name: "exit", url: "/assets/sounds/sounds.mp3"},
|
|
||||||
{obj: "_high", name: "high", url: "/assets/sounds/sounds.mp3"},
|
|
||||||
{obj: "_low", name: "low", url: "/assets/sounds/sounds.mp3"},
|
|
||||||
];
|
|
||||||
|
|
||||||
soundSprite.forEach((item: { obj: any, name: string, url: string }, idx) => {
|
|
||||||
this[item.obj] = new Sound(item.name, item.url, this.scene, null, {
|
|
||||||
autoplay: false,
|
|
||||||
loop: false,
|
|
||||||
volume: this.volume,
|
|
||||||
offset: idx,
|
|
||||||
length: 1.0
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this._tick = new Sound("tick", '/assets/sounds/tick.mp3', this.scene);
|
|
||||||
this._bounce = new Sound("bounce", "/assets/sounds/drumsprite.mp3", this.scene, null, {
|
|
||||||
autoplay: false,
|
|
||||||
loop: false,
|
|
||||||
offset: 0,
|
|
||||||
length: 0.990
|
|
||||||
});
|
|
||||||
this._background = new Sound("brown", "/assets/sounds/brown.mp3", this.scene, null, {
|
|
||||||
autoplay: false,
|
|
||||||
volume: 1,
|
|
||||||
loop: true
|
|
||||||
});
|
|
||||||
const spatialOptions = {
|
|
||||||
spatialSound: true,
|
|
||||||
autoplay: false,
|
|
||||||
volume: .5,
|
|
||||||
loop: false
|
|
||||||
}
|
|
||||||
this._backgroundEffects.push(this.buildSpatialSound("warbler2", "/assets/sounds/warbler2.mp3"));
|
|
||||||
this._backgroundEffects.push(this.buildSpatialSound("warbler3", "/assets/sounds/warbler3.mp3"));
|
|
||||||
this._backgroundEffects.push(this.buildSpatialSound("crickets", "/assets/sounds/crickets.mp3"));
|
|
||||||
this._backgroundEffects.push(this.buildSpatialSound("dove", "/assets/sounds/dove.mp3"))
|
|
||||||
}
|
|
||||||
|
|
||||||
private volume: number = 0.8;
|
|
||||||
private readonly _bounce: Sound;
|
|
||||||
private readonly _background: Sound;
|
|
||||||
private readonly _enter: Sound;
|
|
||||||
|
|
||||||
public get enter() {
|
|
||||||
return this._enter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get tick() {
|
|
||||||
return this._tick;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_backgroundEffects: Array<Sound> = [];
|
|
||||||
public get backgroundEffects(): Array<Sound> {
|
|
||||||
return this._backgroundEffects;
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildSpatialSound(name: string, url: string) {
|
|
||||||
const spatialOptions = {
|
|
||||||
spatialSound: true,
|
|
||||||
autoplay: false,
|
|
||||||
volume: .5,
|
|
||||||
loop: false
|
|
||||||
}
|
|
||||||
const sound = new Sound(name, url, this.scene, null, spatialOptions);
|
|
||||||
sound.switchPanningModelToHRTF();
|
|
||||||
sound.maxDistance = 40;
|
|
||||||
return sound;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 bounce() {
|
|
||||||
const bounce = this._bounce.clone();
|
|
||||||
bounce.updateOptions({offset: 0, volume: this.volume, length: .990});
|
|
||||||
bounce.onEndedObservable.add(() => {
|
|
||||||
bounce.dispose();
|
|
||||||
});
|
|
||||||
return bounce;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import {Scene} from "@babylonjs/core";
|
|
||||||
|
|
||||||
export class DiagramExporter {
|
|
||||||
private scene: Scene;
|
|
||||||
|
|
||||||
constructor(scene: Scene) {
|
|
||||||
this.scene = scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
public exportgltf() {
|
|
||||||
import("@babylonjs/serializers").then((serializers) => {
|
|
||||||
serializers.GLTF2Export.GLBAsync(this.scene, 'diagram.glb', {
|
|
||||||
shouldExportNode: function (node) {
|
|
||||||
return (node?.metadata?.exportable as boolean);
|
|
||||||
}
|
|
||||||
}).then((gltf) => {
|
|
||||||
gltf.downloadFiles();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import {TransformNode} from "@babylonjs/core";
|
|
||||||
|
|
||||||
|
|
||||||
const debug = true;
|
|
||||||
|
|
||||||
export function displayDebug(text: string[]) {
|
|
||||||
if (debug) {
|
|
||||||
drawDebugText(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawDebugText(text: string[]) {
|
|
||||||
const transform = new TransformNode("debugTransform");
|
|
||||||
transform.parent = transform.getScene().activeCamera;
|
|
||||||
transform.getScene().onActiveCameraChanged.add(() => {
|
|
||||||
transform.parent = transform.getScene().activeCamera;
|
|
||||||
});
|
|
||||||
console.log(text);
|
|
||||||
transform.position.z = 1;
|
|
||||||
transform.position.y = .2;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -94,6 +94,6 @@ export async function groundMeshObserver(ground: AbstractMesh,
|
|||||||
rig.turnSnap = config.turnSnap;
|
rig.turnSnap = config.turnSnap;
|
||||||
}, -1, false, this);
|
}, -1, false, this);
|
||||||
|
|
||||||
const webController = new WebController(ground.getScene(), rig, diagramManager, diagramManager.controllers);
|
const webController = new WebController(ground.getScene(), rig, diagramManager);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,17 +1,8 @@
|
|||||||
import {DefaultScene} from "../../defaultScene";
|
import {DefaultScene} from "../../defaultScene";
|
||||||
|
|
||||||
|
|
||||||
export function addSceneInspector() {
|
export function addSceneInspector() {
|
||||||
const scene = DefaultScene.Scene;
|
|
||||||
window.addEventListener("keydown", (ev) => {
|
window.addEventListener("keydown", (ev) => {
|
||||||
if (ev.key == "z") {
|
|
||||||
//voiceManager.startRecording();
|
|
||||||
}
|
|
||||||
if (ev.key == "x") {
|
|
||||||
//voiceManager.stopRecording();
|
|
||||||
}
|
|
||||||
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
|
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
|
||||||
|
|
||||||
const web = document.querySelector('#webApp');
|
const web = document.querySelector('#webApp');
|
||||||
(web as HTMLDivElement).style.display = 'none';
|
(web as HTMLDivElement).style.display = 'none';
|
||||||
|
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
import {
|
|
||||||
Color3,
|
|
||||||
DynamicTexture,
|
|
||||||
InstancedMesh,
|
|
||||||
Mesh,
|
|
||||||
MeshBuilder,
|
|
||||||
Scene,
|
|
||||||
StandardMaterial,
|
|
||||||
TransformNode
|
|
||||||
} from "@babylonjs/core";
|
|
||||||
import {DefaultScene} from "../defaultScene";
|
|
||||||
|
|
||||||
export class TextMeshGenerator {
|
|
||||||
private _scene: Scene;
|
|
||||||
private _textMeshes: Map<string, Mesh> = new Map<string, Mesh>();
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this._scene = DefaultScene.Scene;
|
|
||||||
this.initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getMesh(input: string): TransformNode {
|
|
||||||
const transformNode = new TransformNode("textMesh-" + input, this._scene);
|
|
||||||
let x = 0;
|
|
||||||
for (const char of input) {
|
|
||||||
const mesh = new InstancedMesh("instance_" + input, this._textMeshes.get(char));
|
|
||||||
mesh.parent = transformNode;
|
|
||||||
x = x + Math.abs(mesh.getBoundingInfo().boundingBox.minimum.x);
|
|
||||||
mesh.position.x = x;
|
|
||||||
x = x + mesh.getBoundingInfo().boundingBox.maximum.x;
|
|
||||||
}
|
|
||||||
return transformNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public generateCharMesh(input: string): Mesh {
|
|
||||||
console.log("Generating text mesh for: " + input);
|
|
||||||
//Set font
|
|
||||||
const height = 0.05;
|
|
||||||
const font_size = 28;
|
|
||||||
const font = "bold " + font_size + "px Arial";
|
|
||||||
//Set height for dynamic texture
|
|
||||||
const DTHeight = 1.5 * font_size; //or set as wished
|
|
||||||
//Calc Ratio
|
|
||||||
const ratio = height / DTHeight;
|
|
||||||
|
|
||||||
//Use a temporary dynamic texture to calculate the length of the text on the dynamic texture canvas
|
|
||||||
const temp = new DynamicTexture("DynamicTexture", 32, this._scene);
|
|
||||||
const tmpctx = temp.getContext();
|
|
||||||
tmpctx.font = font;
|
|
||||||
const DTWidth = tmpctx.measureText(input).width + 8;
|
|
||||||
|
|
||||||
//Calculate width the plane has to be
|
|
||||||
const planeWidth = DTWidth * ratio;
|
|
||||||
const dynamicTexture = new DynamicTexture("DynamicTexture", {
|
|
||||||
width: DTWidth,
|
|
||||||
height: DTHeight
|
|
||||||
}, this._scene, false);
|
|
||||||
dynamicTexture.drawText(input, null, null, font, "#ffffff", "#000000", true);
|
|
||||||
temp.dispose();
|
|
||||||
const mat = new StandardMaterial("mat", this._scene);
|
|
||||||
mat.diffuseColor = Color3.Black();
|
|
||||||
mat.disableLighting = true;
|
|
||||||
mat.backFaceCulling = true;
|
|
||||||
mat.emissiveTexture = dynamicTexture;
|
|
||||||
const plane = MeshBuilder.CreatePlane("character" + input, {width: planeWidth, height: height}, this._scene);
|
|
||||||
plane.material = mat;
|
|
||||||
return plane;
|
|
||||||
}
|
|
||||||
|
|
||||||
private initialize() {
|
|
||||||
for (let i = 32; i < 127; ++i) {
|
|
||||||
const mesh = this.generateCharMesh(String.fromCharCode(i));
|
|
||||||
this._textMeshes.set(String.fromCharCode(i), mesh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
import {VuMeterEngine, WebVoiceProcessor} from "@picovoice/web-voice-processor";
|
|
||||||
import {EagleProfilerWorker, EagleWorker} from "@picovoice/eagle-web";
|
|
||||||
import {PvEngine} from "@picovoice/web-voice-processor/dist/types/types";
|
|
||||||
import {base64} from "rfc4648";
|
|
||||||
import {CobraWorker} from "@picovoice/cobra-web";
|
|
||||||
|
|
||||||
export class VoiceRecognizer {
|
|
||||||
|
|
||||||
private readonly profile = 'TT4GLAFik3sHYasWTbmNc7CX2xmJifp897E6xyJDwcD8rHA1ZgJTdLaLQ0Z1zJP3Lzv61JMJpuNsgSSxraWf62RECXJHA4SJ5RCSv3/MHXcnKlaGzcQ4gJD/vcl8tL45j02me6lNf1TtbI81qv/GBSH9u3p5V/p7fD1j/tZ8P3kzM40FG1QxP330Sp/dvSwU6oEc5iH7+D3Zsy4GEtD3iqGdAex4200elW753eXlKli92qLlaplDxCZZIwNG0/ER51NhVzg/D+ieZLE/rUjZAl+z4a9c7AurnQDTZ1fKyzwMzjiQsb8h6rIco+IlblAuE8dmVfFxZXrpfw8tViK5KwnpbHrnR8ebLA0Zd/G5l0yjXeCEh8Y26qkGZk43MolBgQ044KNNsJbDrm1o2sYGvo/BgEronFuBB+wNw0pVFqp1nrIqfT8IsH42q4rj7ByzxH+4QVr1uQVx7c89GTp1yYyqk+q9B+f0cG063KwnUofddkx0tmot3d8kPCZGL1H88qMm2NdNeCU6AFi1qhP1Ssd3jOsyzd4O3U9JMJIUruySzf6Qx3/JI4aSKJm0To/xEszrm028s1qD8I0+Kh3GxgtiW+toCzJrAIoRkxmIgV2HbOStjerTQDK2t1MMHpHEr7NfNaJxxripR2xDlw/r1Sh2sf58AhIYBk1b/U54PCsm7tWKc0YroWgO5qSpASdkIq2UX7AgQ6nWtcZPk5d5xdfRkhIy3Yf6yushwEz/+v3aa/fshkh9lbKnz2wt4MhmbMJv7WYenHQr0RvEDQFchNHUyx8D7fBLpKwrmHVDi0meG7pl0Q9DrFzykeBZi0m22T6xF5OUBqvUZWdcqa5ZoYvPZS5Uk0d3COhAGjgFEAL7IMK9rZei24mM98+vqyfD1RRK29rQFljHxO9lJ0N3NINW2PfZulPPqn0OtEhxU829W1k1JjOUgOucJUpI9D0H1vrcqTYq0F4mj3YTqJ0CNbqXEan+XlbjB6kGKDuO1V/YkLbShJRnmKVtaCS2m4zDCJ5Rc7x8J7E/Cx6AnVK7UWM9CLnnLoaJ6sib9UnBV1uSTK2BIp1mO8b+BjP2yJ2/l1xbYUPZQa/ECRarwDP9PY9lHym6WGf35BjuWBwxT6obifw9JyYaqFZxwNbKviqKshSW8wmh5euYu3s0hY/MhCD+ZCYZiJAXADArcv8z8Wlk1x/KmZwLOAKJfgDUcs+9Q8aKGq5/jTPcd6MuM5pAVwfoFMR9QD8uKmyrPuBdJMRZFULX0uqliyna2CTmsAJ+6B47AA61q1/50Vj8OTUBLi+fhIaw3Ch1ofMYopIqc+QT81ekH8b9/+pXaUi+moA6C53Mnch9hB/uKoJELPSNDpIy1fP08Ujv/K0Foft4X43w9dImveOEhw==';
|
|
||||||
|
|
||||||
public constructor() {
|
|
||||||
this.start();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public async start() {
|
|
||||||
let voicePresent = false;
|
|
||||||
const eagleProfiler = await EagleProfilerWorker.create(
|
|
||||||
'qQG03oXEGQRfPbX7H1VTZHLy/zelmMxcWXSy14/pskqri4LTJvBWmQ==',
|
|
||||||
{publicPath: '/voice/eagle_params.pv'}
|
|
||||||
)
|
|
||||||
const bytes = base64.parse(this.profile);
|
|
||||||
|
|
||||||
const eagle = await EagleWorker.create('qQG03oXEGQRfPbX7H1VTZHLy/zelmMxcWXSy14/pskqri4LTJvBWmQ=='
|
|
||||||
, {publicPath: '/voice/eagle_params.pv'},
|
|
||||||
[{bytes: bytes}]);
|
|
||||||
let data: Int16Array = null;
|
|
||||||
const engine: PvEngine = {
|
|
||||||
onmessage: async (e: MessageEvent) => {
|
|
||||||
if (!voicePresent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (e.data.command) {
|
|
||||||
case 'process':
|
|
||||||
const inputData = e.data.inputFrame;
|
|
||||||
|
|
||||||
const validation = await eagle.process(inputData);
|
|
||||||
if (validation && validation[0] > .99) {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (data == null) {
|
|
||||||
data = inputData;
|
|
||||||
} else {
|
|
||||||
data = new Int16Array(data.length + inputData.length);
|
|
||||||
data.set(data, 0);
|
|
||||||
data.set(inputData, data.length - inputData.length);
|
|
||||||
}
|
|
||||||
if (data.length > eagleProfiler.minEnrollSamples) {
|
|
||||||
const result = await eagleProfiler.enroll(data);
|
|
||||||
if (result.percentage >= 100) {
|
|
||||||
|
|
||||||
|
|
||||||
const profile = await eagleProfiler.export();
|
|
||||||
|
|
||||||
|
|
||||||
//WebVoiceProcessor.unsubscribe(engine);
|
|
||||||
//WebVoiceProcessor.unsubscribe(engine);
|
|
||||||
//eagleProfiler.release();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
||||||
devices.forEach((device) => {
|
|
||||||
if (device.kind === 'audioinput') {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const vuCallback = (db) => {
|
|
||||||
|
|
||||||
}
|
|
||||||
WebVoiceProcessor.setOptions({deviceId: 'default'});
|
|
||||||
const vuEngine = new VuMeterEngine(vuCallback);
|
|
||||||
//WebVoiceProcessor.subscribe(vuEngine);
|
|
||||||
const cobra = await CobraWorker.create('qQG03oXEGQRfPbX7H1VTZHLy/zelmMxcWXSy14/pskqri4LTJvBWmQ==',
|
|
||||||
(isVoice) => {
|
|
||||||
voicePresent = (isVoice && isVoice > .85);
|
|
||||||
});
|
|
||||||
WebVoiceProcessor.subscribe(cobra);
|
|
||||||
WebVoiceProcessor.subscribe(engine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
24
src/vrApp.ts
24
src/vrApp.ts
@ -2,7 +2,6 @@ import {Color3, Engine, FreeCamera, Observable, Scene, Vector3, WebGPUEngine} fr
|
|||||||
import '@babylonjs/loaders';
|
import '@babylonjs/loaders';
|
||||||
import {DiagramManager} from "./diagram/diagramManager";
|
import {DiagramManager} from "./diagram/diagramManager";
|
||||||
import log, {Logger} from "loglevel";
|
import log, {Logger} from "loglevel";
|
||||||
import {GamepadManager} from "./controllers/gamepadManager";
|
|
||||||
import {CustomEnvironment} from "./util/customEnvironment";
|
import {CustomEnvironment} from "./util/customEnvironment";
|
||||||
import {Spinner} from "./objects/spinner";
|
import {Spinner} from "./objects/spinner";
|
||||||
import {PouchdbPersistenceManager} from "./integration/database/pouchdbPersistenceManager";
|
import {PouchdbPersistenceManager} from "./integration/database/pouchdbPersistenceManager";
|
||||||
@ -17,11 +16,8 @@ import {Introduction} from "./tutorial/introduction";
|
|||||||
const webGpu = false;
|
const webGpu = false;
|
||||||
|
|
||||||
log.setLevel('error', false);
|
log.setLevel('error', false);
|
||||||
log.getLogger('PouchdbPersistenceManager').setLevel('debug', false);
|
|
||||||
const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
|
const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
|
||||||
export class VrApp {
|
export class VrApp {
|
||||||
|
|
||||||
|
|
||||||
//preTasks = [havokModule];
|
//preTasks = [havokModule];
|
||||||
private logger: Logger = log.getLogger('App');
|
private logger: Logger = log.getLogger('App');
|
||||||
|
|
||||||
@ -32,7 +28,6 @@ export class VrApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async initialize(scene: Scene) {
|
public async initialize(scene: Scene) {
|
||||||
//const mesh = SceneLoader.ImportMesh(null, '/assets/models/', 'person.stl', DefaultScene.Scene);
|
|
||||||
setMainCamera(scene);
|
setMainCamera(scene);
|
||||||
const spinner = new Spinner();
|
const spinner = new Spinner();
|
||||||
spinner.show();
|
spinner.show();
|
||||||
@ -46,9 +41,7 @@ export class VrApp {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
initEnvironment(diagramManager, spinner);
|
initEnvironment(diagramManager, spinner);
|
||||||
const gamepadManager = new GamepadManager(scene);
|
|
||||||
addSceneInspector();
|
addSceneInspector();
|
||||||
//const camMenu = new CameraMenu(scene);
|
|
||||||
const el = document.querySelector('#download');
|
const el = document.querySelector('#download');
|
||||||
if (el) {
|
if (el) {
|
||||||
el.addEventListener('click', () => {
|
el.addEventListener('click', () => {
|
||||||
@ -65,35 +58,25 @@ export class VrApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async initializeEngine() {
|
private async initializeEngine() {
|
||||||
|
|
||||||
let engine: WebGPUEngine | Engine = null;
|
let engine: WebGPUEngine | Engine = null;
|
||||||
if (webGpu) {
|
if (webGpu) {
|
||||||
engine = new WebGPUEngine(canvas);
|
engine = new WebGPUEngine(canvas);
|
||||||
await (engine as WebGPUEngine).initAsync();
|
await (engine as WebGPUEngine).initAsync();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
engine = new Engine(canvas, true);
|
engine = new Engine(canvas, true);
|
||||||
}
|
}
|
||||||
engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
|
engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
|
||||||
|
|
||||||
window.onresize = () => {
|
window.onresize = () => {
|
||||||
engine.resize();
|
engine.resize();
|
||||||
}
|
}
|
||||||
const scene = new Scene(engine);
|
const scene = new Scene(engine);
|
||||||
DefaultScene.Scene = scene;
|
DefaultScene.Scene = scene;
|
||||||
//const a = new CurveObject();
|
|
||||||
scene.ambientColor = new Color3(.1, .1, .1);
|
scene.ambientColor = new Color3(.1, .1, .1);
|
||||||
|
|
||||||
//log.resetLevel();
|
|
||||||
//log.setDefaultLevel('error');
|
|
||||||
await this.initialize(scene);
|
await this.initialize(scene);
|
||||||
engine.runRenderLoop(() => {
|
engine.runRenderLoop(() => {
|
||||||
scene.render();
|
scene.render();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
const vrApp = new VrApp();
|
const vrApp = new VrApp();
|
||||||
buildQuestLink();
|
buildQuestLink();
|
||||||
@ -107,7 +90,6 @@ function setMainCamera(scene: Scene) {
|
|||||||
|
|
||||||
async function initDb(diagramManager: DiagramManager) {
|
async function initDb(diagramManager: DiagramManager) {
|
||||||
const db = new PouchdbPersistenceManager();
|
const db = new PouchdbPersistenceManager();
|
||||||
//const userManager = new UserManager(db.onUserObservable);
|
|
||||||
db.setDiagramManager(diagramManager);
|
db.setDiagramManager(diagramManager);
|
||||||
await db.initialize();
|
await db.initialize();
|
||||||
}
|
}
|
||||||
@ -120,9 +102,3 @@ function initEnvironment(diagramManager: DiagramManager, spinner: Spinner) {
|
|||||||
});
|
});
|
||||||
}, -1, false, this);
|
}, -1, false, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user