Removed dead code.
This commit is contained in:
parent
53ca47d63e
commit
60758ed84d
@ -9,7 +9,7 @@ import {
|
||||
import {DiagramManager} from "../diagram/diagramManager";
|
||||
import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity";
|
||||
import log from "loglevel";
|
||||
import {ControllerEventType, Controllers} from "./controllers";
|
||||
|
||||
import {grabAndClone} from "./functions/grabAndClone";
|
||||
import {ClickMenu} from "../menus/clickMenu";
|
||||
import {motionControllerObserver} from "./functions/motionControllerObserver";
|
||||
@ -21,10 +21,13 @@ import {MeshTypeEnum} from "../diagram/types/meshTypeEnum";
|
||||
import {getMeshType} from "./functions/getMeshType";
|
||||
import {viewOnly} from "../util/functions/getPath";
|
||||
|
||||
import {ControllerEventType} from "./types/controllerEventType";
|
||||
import {controllerObservable} from "./controllers";
|
||||
|
||||
const CLICK_TIME = 300;
|
||||
|
||||
|
||||
export class Base {
|
||||
export abstract class AbstractController {
|
||||
static stickVector = Vector3.Zero();
|
||||
protected readonly scene: Scene;
|
||||
protected readonly xr: WebXRDefaultExperience;
|
||||
@ -34,7 +37,7 @@ export class Base {
|
||||
protected grabbedObject: DiagramObject = null;
|
||||
protected grabbedMesh: AbstractMesh = null;
|
||||
protected grabbedMeshType: MeshTypeEnum = null;
|
||||
protected controllers: Controllers;
|
||||
|
||||
|
||||
private readonly _logger = log.getLogger('Base');
|
||||
private _clickStart: number = 0;
|
||||
@ -48,7 +51,6 @@ export class Base {
|
||||
diagramManager: DiagramManager) {
|
||||
this._logger.debug('Base Controller Constructor called');
|
||||
this.xrInputSource = controller;
|
||||
this.controllers = diagramManager.controllers;
|
||||
this.scene = DefaultScene.Scene;
|
||||
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
|
||||
this.xrInputSource.onMotionControllerInitObservable.add(motionControllerObserver, -1, false, this);
|
||||
this.controllers.controllerObservable.add((event) => {
|
||||
controllerObservable.add((event) => {
|
||||
this._logger.debug(event);
|
||||
switch (event.type) {
|
||||
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 {
|
||||
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',
|
||||
}
|
||||
|
||||
export class Controllers {
|
||||
public movable: TransformNode | AbstractMesh;
|
||||
public readonly controllerObservable: Observable<ControllerEvent> = new Observable();
|
||||
}
|
||||
export var movable: TransformNode | AbstractMesh;
|
||||
export const 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);
|
||||
diagramManager.addObject(obj);
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,7 +8,6 @@ export function handleWasGrabbed(mesh: AbstractMesh): boolean {
|
||||
logger.debug("handleWasGrabbed: mesh is a diagram entity");
|
||||
return false;
|
||||
} else {
|
||||
|
||||
const result = (mesh?.metadata?.handle == true);
|
||||
logger.debug("handleWasGrabbed: mesh ", 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 {Base} from "./base";
|
||||
import {ControllerEventType} from "./controllers";
|
||||
import {AbstractController} from "./abstractController";
|
||||
import log from "loglevel";
|
||||
import {DiagramManager} from "../diagram/diagramManager";
|
||||
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');
|
||||
constructor(controller:
|
||||
WebXRInputSource, xr: WebXRDefaultExperience, diagramManager: DiagramManager) {
|
||||
@ -17,7 +18,7 @@ export class Left extends Base {
|
||||
init.components['xr-standard-thumbstick']
|
||||
.onAxisValueChangedObservable.add((value) => {
|
||||
this.leftLogger.trace(`thumbstick moved ${value.x}, ${value.y}`);
|
||||
if (!this.controllers.movable) {
|
||||
if (!movable) {
|
||||
this.moveRig(value);
|
||||
} else {
|
||||
this.moveMovable(value);
|
||||
@ -29,7 +30,7 @@ export class Left extends Base {
|
||||
init.components['xr-standard-thumbstick'].onButtonStateChangedObservable.add((value) => {
|
||||
if (value.pressed) {
|
||||
this.leftLogger.trace('Left', 'thumbstick changed');
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.DECREASE_VELOCITY,
|
||||
value: value.value
|
||||
});
|
||||
@ -46,7 +47,7 @@ export class Left extends Base {
|
||||
.onButtonStateChangedObservable
|
||||
.add((button) => {
|
||||
this.leftLogger.trace('trigger pressed');
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.TRIGGER,
|
||||
value: button.value,
|
||||
controller: this.xrInputSource
|
||||
@ -60,7 +61,7 @@ export class Left extends Base {
|
||||
xbutton.onButtonStateChangedObservable.add((button) => {
|
||||
if (button.pressed) {
|
||||
this.leftLogger.trace('X button pressed');
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.X_BUTTON,
|
||||
value: button.value
|
||||
});
|
||||
@ -74,7 +75,7 @@ export class Left extends Base {
|
||||
ybutton.onButtonStateChangedObservable.add((button) => {
|
||||
if (button.pressed) {
|
||||
this.leftLogger.trace('Y button pressed');
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.Y_BUTTON,
|
||||
value: button.value
|
||||
});
|
||||
@ -85,12 +86,12 @@ export class Left extends Base {
|
||||
|
||||
private moveMovable(value: { x: number, y: number }) {
|
||||
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 {
|
||||
|
||||
}
|
||||
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 {
|
||||
|
||||
}
|
||||
@ -98,27 +99,27 @@ export class Left extends Base {
|
||||
|
||||
private moveRig(value: { x: number, y: number }) {
|
||||
if (Math.abs(value.x) > .1) {
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.LEFT_RIGHT,
|
||||
value: value.x * this.speedFactor
|
||||
});
|
||||
Base.stickVector.x = 1;
|
||||
AbstractController.stickVector.x = 1;
|
||||
} else {
|
||||
Base.stickVector.x = 0;
|
||||
AbstractController.stickVector.x = 0;
|
||||
}
|
||||
if (Math.abs(value.y) > .1) {
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.FORWARD_BACK,
|
||||
value: value.y * this.speedFactor
|
||||
});
|
||||
Base.stickVector.y = 1;
|
||||
AbstractController.stickVector.y = 1;
|
||||
} else {
|
||||
Base.stickVector.y = 0;
|
||||
AbstractController.stickVector.y = 0;
|
||||
}
|
||||
|
||||
if (Base.stickVector.equals(Vector3.Zero())) {
|
||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.LEFT_RIGHT, value: 0});
|
||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.FORWARD_BACK, value: 0});
|
||||
if (AbstractController.stickVector.equals(Vector3.Zero())) {
|
||||
controllerObservable.notifyObservers({type: ControllerEventType.LEFT_RIGHT, value: 0});
|
||||
controllerObservable.notifyObservers({type: ControllerEventType.FORWARD_BACK, value: 0});
|
||||
} else {
|
||||
|
||||
}
|
||||
@ -1,19 +1,21 @@
|
||||
import {Base} from "./base";
|
||||
import {AbstractController} from "./abstractController";
|
||||
import {Vector3, WebXRControllerComponent, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core";
|
||||
import {ControllerEventType} from "./controllers";
|
||||
|
||||
|
||||
import {DiagramManager} from "../diagram/diagramManager";
|
||||
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 initBButton(bbutton: WebXRControllerComponent) {
|
||||
if (bbutton) {
|
||||
bbutton.onButtonStateChangedObservable.add((button) => {
|
||||
if (button.pressed) {
|
||||
this.rightLogger.debug('B Button Pressed');
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.B_BUTTON,
|
||||
value: button.value
|
||||
});
|
||||
@ -41,7 +43,7 @@ export class Right extends Base {
|
||||
.onButtonStateChangedObservable
|
||||
.add((button) => {
|
||||
this.rightLogger.debug("right trigger pressed");
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.TRIGGER,
|
||||
value: button.value,
|
||||
controller: this.xrInputSource
|
||||
@ -55,7 +57,7 @@ export class Right extends Base {
|
||||
abutton.onButtonStateChangedObservable.add((value) => {
|
||||
if (value.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) => {
|
||||
if (value.pressed) {
|
||||
this.rightLogger.trace('Right', `thumbstick changed ${value.value}`);
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.INCREASE_VELOCITY,
|
||||
value: value.value
|
||||
});
|
||||
@ -81,22 +83,22 @@ export class Right extends Base {
|
||||
|
||||
private moveRig(value) {
|
||||
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 {
|
||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.TURN, value: 0});
|
||||
controllerObservable.notifyObservers({type: ControllerEventType.TURN, value: 0});
|
||||
}
|
||||
if (Math.abs(value.y) > .1) {
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.UP_DOWN,
|
||||
value: value.y * this.speedFactor
|
||||
});
|
||||
Base.stickVector.z = 1;
|
||||
AbstractController.stickVector.z = 1;
|
||||
} else {
|
||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.UP_DOWN, value: 0});
|
||||
Base.stickVector.z = 0;
|
||||
controllerObservable.notifyObservers({type: ControllerEventType.UP_DOWN, value: 0});
|
||||
AbstractController.stickVector.z = 0;
|
||||
}
|
||||
if (Base.stickVector.equals(Vector3.Zero())) {
|
||||
this.controllers.controllerObservable.notifyObservers({type: ControllerEventType.UP_DOWN, value: 0});
|
||||
if (AbstractController.stickVector.equals(Vector3.Zero())) {
|
||||
controllerObservable.notifyObservers({type: ControllerEventType.UP_DOWN, value: 0});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,18 @@
|
||||
import {Angle, Mesh, Quaternion, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
|
||||
import {Right} from "./right";
|
||||
import {Left} from "./left";
|
||||
import {ControllerEvent, ControllerEventType, Controllers} from "./controllers";
|
||||
import {RightController} from "./rightController";
|
||||
import {LeftController} from "./leftController";
|
||||
import log from "loglevel";
|
||||
import {DiagramManager} from "../diagram/diagramManager";
|
||||
import {buildRig} from "./functions/buildRig";
|
||||
import {DefaultScene} from "../defaultScene";
|
||||
import {ControllerEvent} from "./types/controllerEvent";
|
||||
import {ControllerEventType} from "./types/controllerEventType";
|
||||
import {controllerObservable} from "./controllers";
|
||||
|
||||
const RIGHT = "right";
|
||||
const LEFT = "left";
|
||||
|
||||
|
||||
|
||||
export class Rigplatform {
|
||||
public static instance: Rigplatform;
|
||||
|
||||
@ -19,14 +20,14 @@ export class Rigplatform {
|
||||
public rigMesh: Mesh;
|
||||
|
||||
private _logger = log.getLogger('Rigplatform');
|
||||
private readonly _controllers: Controllers;
|
||||
|
||||
private readonly _diagramManager: DiagramManager;
|
||||
private readonly _scene: Scene;
|
||||
private readonly _velocityArray = [0.01, 0.1, 1, 2, 5];
|
||||
private readonly _xr: WebXRDefaultExperience;
|
||||
|
||||
private _rightController: Right;
|
||||
private _leftController: Left;
|
||||
private _rightController: RightController;
|
||||
private _leftController: LeftController;
|
||||
private _turning: boolean = false;
|
||||
private _velocity: Vector3 = Vector3.Zero();
|
||||
private _velocityIndex: number = 2;
|
||||
@ -40,7 +41,7 @@ export class Rigplatform {
|
||||
) {
|
||||
this._scene = DefaultScene.Scene;
|
||||
this._diagramManager = diagramManager;
|
||||
this._controllers = diagramManager.controllers;
|
||||
|
||||
this._xr = xr;
|
||||
this.rigMesh = buildRig(xr);
|
||||
this._fixRotation();
|
||||
@ -112,12 +113,12 @@ export class Rigplatform {
|
||||
private _registerObserver() {
|
||||
if (this._registered) {
|
||||
this._logger.warn('observer already registered, clearing and re registering');
|
||||
this._controllers.controllerObservable.clear();
|
||||
controllerObservable.clear();
|
||||
this._registered = false;
|
||||
}
|
||||
if (!this._registered) {
|
||||
this._registered = true;
|
||||
this._controllers.controllerObservable.add((event: ControllerEvent) => {
|
||||
controllerObservable.add((event: ControllerEvent) => {
|
||||
this._logger.debug(event);
|
||||
switch (event.type) {
|
||||
case ControllerEventType.INCREASE_VELOCITY:
|
||||
@ -165,12 +166,12 @@ export class Rigplatform {
|
||||
switch (source.inputSource.handedness) {
|
||||
case RIGHT:
|
||||
if (!this._rightController) {
|
||||
this._rightController = new Right(source, this._xr, this._diagramManager);
|
||||
this._rightController = new RightController(source, this._xr, this._diagramManager);
|
||||
}
|
||||
break;
|
||||
case LEFT:
|
||||
if (!this._leftController) {
|
||||
this._leftController = new Left(source, this._xr, this._diagramManager);
|
||||
this._leftController = new LeftController(source, this._xr, this._diagramManager);
|
||||
}
|
||||
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 {Rigplatform} from "./rigplatform";
|
||||
import {Controllers} from "./controllers";
|
||||
|
||||
import {DiagramManager} from "../diagram/diagramManager";
|
||||
import {wheelHandler} from "./functions/wheelHandler";
|
||||
import log, {Logger} from "loglevel";
|
||||
@ -12,7 +12,7 @@ export class WebController {
|
||||
private rig: Rigplatform;
|
||||
private diagramManager: DiagramManager;
|
||||
private mouseDown: boolean = false;
|
||||
private readonly controllers: Controllers;
|
||||
|
||||
private upDownWheel: boolean = false;
|
||||
private fowardBackWheel: boolean = false;
|
||||
private canvas: HTMLCanvasElement;
|
||||
@ -20,11 +20,11 @@ export class WebController {
|
||||
constructor(scene: Scene,
|
||||
rig: Rigplatform,
|
||||
diagramManager: DiagramManager,
|
||||
controllers: Controllers) {
|
||||
) {
|
||||
this.scene = scene;
|
||||
this.rig = rig;
|
||||
this.diagramManager = diagramManager;
|
||||
this.controllers = controllers;
|
||||
|
||||
this.canvas = document.querySelector('#gameCanvas');
|
||||
//this.referencePlane = MeshBuilder.CreatePlane('referencePlane', {size: 10}, this.scene);
|
||||
//this.referencePlane.setEnabled(false);
|
||||
@ -160,7 +160,7 @@ export class WebController {
|
||||
|
||||
|
||||
});
|
||||
this.scene.onPointerDown = (evt, state) => {
|
||||
this.scene.onPointerDown = (evt) => {
|
||||
if (evt.pointerType == "mouse") {
|
||||
this.mouseDown = true;
|
||||
/*if (evt.shiftKey) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {AbstractActionManager, AbstractMesh, ActionManager, Observable, Scene} from "@babylonjs/core";
|
||||
import {DiagramEntity, DiagramEvent, DiagramEventType} from "./types/diagramEntity";
|
||||
import log from "loglevel";
|
||||
import {Controllers} from "../controllers/controllers";
|
||||
|
||||
import {AppConfig} from "../util/appConfig";
|
||||
import {buildEntityActionManager} from "./functions/buildEntityActionManager";
|
||||
import {DefaultScene} from "../defaultScene";
|
||||
@ -11,12 +11,14 @@ import {DiagramObject} from "./diagramObject";
|
||||
import {getMe} from "../util/me";
|
||||
import {UserModelType} from "../users/userTypes";
|
||||
import {vectoxys} from "./functions/vectorConversion";
|
||||
import {controllerObservable} from "../controllers/controllers";
|
||||
import {ControllerEvent} from "../controllers/types/controllerEvent";
|
||||
|
||||
|
||||
export class DiagramManager {
|
||||
private readonly _logger = log.getLogger('DiagramManager');
|
||||
public readonly _config: AppConfig;
|
||||
private readonly _controllers: Controllers;
|
||||
private readonly _controllerObservable: Observable<ControllerEvent>;
|
||||
private readonly _diagramEntityActionManager: ActionManager;
|
||||
public readonly onDiagramEventObservable: Observable<DiagramEvent> = new Observable();
|
||||
public readonly onUserEventObservable: Observable<UserModelType> = new Observable();
|
||||
@ -31,9 +33,9 @@ export class DiagramManager {
|
||||
this._me = getMe();
|
||||
this._scene = DefaultScene.Scene;
|
||||
this._config = new AppConfig();
|
||||
this._controllers = new Controllers();
|
||||
this._diagramMenuManager = new DiagramMenuManager(this.onDiagramEventObservable, this._controllers, this._config, readyObservable);
|
||||
this._diagramEntityActionManager = buildEntityActionManager(this._controllers);
|
||||
|
||||
this._diagramMenuManager = new DiagramMenuManager(this.onDiagramEventObservable, controllerObservable, this._config, readyObservable);
|
||||
this._diagramEntityActionManager = buildEntityActionManager(controllerObservable);
|
||||
this.onDiagramEventObservable.add(this.onDiagramEvent, DiagramEventObserverMask.FROM_DB, true, this);
|
||||
|
||||
|
||||
@ -116,11 +118,6 @@ export class DiagramManager {
|
||||
return this._diagramObjects.has(mesh?.id)
|
||||
}
|
||||
|
||||
|
||||
public get controllers(): Controllers {
|
||||
return this._controllers;
|
||||
}
|
||||
|
||||
public createCopy(id: string): DiagramObject {
|
||||
const diagramObject = this._diagramObjects.get(id);
|
||||
if (!diagramObject) {
|
||||
|
||||
@ -2,7 +2,6 @@ import {DiagramEvent, DiagramEventType} from "./types/diagramEntity";
|
||||
import {AbstractMesh, ActionEvent, Observable, Scene, Vector3, WebXRInputSource} from "@babylonjs/core";
|
||||
import {InputTextView} from "../information/inputTextView";
|
||||
import {DefaultScene} from "../defaultScene";
|
||||
import {ControllerEvent, ControllerEventType, Controllers} from "../controllers/controllers";
|
||||
import log from "loglevel";
|
||||
import {Toolbox} from "../toolbox/toolbox";
|
||||
import {ClickMenu} from "../menus/clickMenu";
|
||||
@ -13,6 +12,8 @@ import {ConnectionPreview} from "../menus/connectionPreview";
|
||||
import {ScaleMenu2} from "../menus/ScaleMenu2";
|
||||
import {viewOnly} from "../util/functions/getPath";
|
||||
import {GroupMenu} from "../menus/groupMenu";
|
||||
import {ControllerEvent} from "../controllers/types/controllerEvent";
|
||||
import {ControllerEventType} from "../controllers/types/controllerEventType";
|
||||
|
||||
|
||||
export class DiagramMenuManager {
|
||||
@ -26,10 +27,10 @@ export class DiagramMenuManager {
|
||||
private _logger = log.getLogger('DiagramMenuManager');
|
||||
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._notifier = notifier;
|
||||
this._inputTextView = new InputTextView(controllers);
|
||||
this._inputTextView = new InputTextView(controllerObservable);
|
||||
this.configMenu = new ConfigMenu(config);
|
||||
|
||||
this._inputTextView.onTextObservable.add((evt) => {
|
||||
@ -43,7 +44,7 @@ export class DiagramMenuManager {
|
||||
//this.scaleMenu.handleMesh.setEnabled(false)
|
||||
this.configMenu.handleTransformNode.setEnabled(false);
|
||||
}
|
||||
controllers.controllerObservable.add((event: ControllerEvent) => {
|
||||
controllerObservable.add((event: ControllerEvent) => {
|
||||
if (event.type == ControllerEventType.B_BUTTON) {
|
||||
if (event.value > .8) {
|
||||
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 {ControllerEventType, Controllers} from "../../controllers/controllers";
|
||||
import {
|
||||
ActionManager,
|
||||
ExecuteCodeAction,
|
||||
HighlightLayer,
|
||||
InstancedMesh,
|
||||
Observable,
|
||||
StandardMaterial,
|
||||
} from "@babylonjs/core";
|
||||
import log from "loglevel";
|
||||
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);
|
||||
highlightLayer.innerGlow = false;
|
||||
highlightLayer.outerGlow = true;
|
||||
@ -37,10 +45,10 @@ export function buildEntityActionManager(controllers: Controllers) {
|
||||
logger.error(e);
|
||||
}
|
||||
}
|
||||
controllers.controllerObservable.notifyObservers({
|
||||
controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.PULSE,
|
||||
gripId: evt?.additionalData?.pickResult?.gripTransform?.id
|
||||
})
|
||||
});
|
||||
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 log, {Logger} from "loglevel";
|
||||
import {AdvancedDynamicTexture, Control, InputText, VirtualKeyboard} from "@babylonjs/gui";
|
||||
import {ControllerEventType, Controllers} from "../controllers/controllers";
|
||||
import {Handle} from "../objects/handle";
|
||||
import {DefaultScene} from "../defaultScene";
|
||||
import {ControllerEvent} from "../controllers/types/controllerEvent";
|
||||
import {ControllerEventType} from "../controllers/types/controllerEventType";
|
||||
|
||||
export type TextEvent = {
|
||||
id: string;
|
||||
@ -16,15 +17,15 @@ export class InputTextView {
|
||||
private readonly scene: Scene;
|
||||
private readonly inputMesh: AbstractMesh;
|
||||
|
||||
private readonly controllers: Controllers;
|
||||
private readonly controllerObservable: Observable<ControllerEvent>;
|
||||
|
||||
private readonly handle: Handle;
|
||||
private inputText: InputText;
|
||||
private diagramMesh: AbstractMesh;
|
||||
private keyboard: VirtualKeyboard;
|
||||
|
||||
constructor(controllers: Controllers) {
|
||||
this.controllers = controllers;
|
||||
constructor(controllerObservable: Observable<ControllerEvent>) {
|
||||
this.controllerObservable = controllerObservable;
|
||||
this.scene = DefaultScene.Scene;
|
||||
this.inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene);
|
||||
this.handle = new Handle(this.inputMesh, 'Input');
|
||||
@ -113,7 +114,7 @@ export class InputTextView {
|
||||
this.logger.debug(eventData);
|
||||
const gripId = eventState?.userInfo?.pickInfo?.gripTransform?.id;
|
||||
if (gripId) {
|
||||
this.controllers.controllerObservable.notifyObservers({
|
||||
this.controllerObservable.notifyObservers({
|
||||
type: ControllerEventType.PULSE,
|
||||
gripId: gripId
|
||||
});
|
||||
|
||||
@ -45,7 +45,7 @@ export class PouchdbPersistenceManager {
|
||||
}
|
||||
this._logger.debug(evt);
|
||||
});
|
||||
document.addEventListener('dbcreated', (evt) => {
|
||||
document.addEventListener('dbcreated', (evt: CustomEvent) => {
|
||||
const detail = ((evt.detail as unknown) as PasswordEvent2);
|
||||
const password = detail.password;
|
||||
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 {Controllers} from "../controllers/controllers";
|
||||
import {Handle} from "../objects/handle";
|
||||
import {DefaultScene} from "../defaultScene";
|
||||
|
||||
@ -7,12 +6,11 @@ export abstract class AbstractMenu {
|
||||
protected handle: Handle;
|
||||
protected scene: Scene;
|
||||
protected xr: WebXRDefaultExperience;
|
||||
protected controllers: Controllers;
|
||||
|
||||
protected constructor(xr: WebXRDefaultExperience, controllers: Controllers) {
|
||||
|
||||
protected constructor(xr: WebXRDefaultExperience) {
|
||||
this.scene = DefaultScene.Scene;
|
||||
this.xr = xr;
|
||||
this.controllers = controllers;
|
||||
}
|
||||
|
||||
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 {
|
||||
return (
|
||||
<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>
|
||||
<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() {
|
||||
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.wrapU = RawTexture.WRAP_ADDRESSMODE
|
||||
this._texture.name = 'blue-white-texture';
|
||||
this._texture.name = 'connection-texture';
|
||||
this._texture.uScale = 30;
|
||||
DefaultScene.Scene.onBeforeRenderObservable.add(() => {
|
||||
this._texture.uOffset -= 0.01 * DefaultScene.Scene.getAnimationRatio()
|
||||
});
|
||||
|
||||
}
|
||||
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;
|
||||
}, -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";
|
||||
|
||||
|
||||
export function addSceneInspector() {
|
||||
const scene = DefaultScene.Scene;
|
||||
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) {
|
||||
|
||||
const web = document.querySelector('#webApp');
|
||||
(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 {DiagramManager} from "./diagram/diagramManager";
|
||||
import log, {Logger} from "loglevel";
|
||||
import {GamepadManager} from "./controllers/gamepadManager";
|
||||
import {CustomEnvironment} from "./util/customEnvironment";
|
||||
import {Spinner} from "./objects/spinner";
|
||||
import {PouchdbPersistenceManager} from "./integration/database/pouchdbPersistenceManager";
|
||||
@ -17,11 +16,8 @@ import {Introduction} from "./tutorial/introduction";
|
||||
const webGpu = false;
|
||||
|
||||
log.setLevel('error', false);
|
||||
log.getLogger('PouchdbPersistenceManager').setLevel('debug', false);
|
||||
const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
|
||||
export class VrApp {
|
||||
|
||||
|
||||
//preTasks = [havokModule];
|
||||
private logger: Logger = log.getLogger('App');
|
||||
|
||||
@ -32,7 +28,6 @@ export class VrApp {
|
||||
}
|
||||
|
||||
public async initialize(scene: Scene) {
|
||||
//const mesh = SceneLoader.ImportMesh(null, '/assets/models/', 'person.stl', DefaultScene.Scene);
|
||||
setMainCamera(scene);
|
||||
const spinner = new Spinner();
|
||||
spinner.show();
|
||||
@ -46,9 +41,7 @@ export class VrApp {
|
||||
}
|
||||
});
|
||||
initEnvironment(diagramManager, spinner);
|
||||
const gamepadManager = new GamepadManager(scene);
|
||||
addSceneInspector();
|
||||
//const camMenu = new CameraMenu(scene);
|
||||
const el = document.querySelector('#download');
|
||||
if (el) {
|
||||
el.addEventListener('click', () => {
|
||||
@ -65,35 +58,25 @@ export class VrApp {
|
||||
}
|
||||
|
||||
private async initializeEngine() {
|
||||
|
||||
let engine: WebGPUEngine | Engine = null;
|
||||
if (webGpu) {
|
||||
engine = new WebGPUEngine(canvas);
|
||||
await (engine as WebGPUEngine).initAsync();
|
||||
|
||||
} else {
|
||||
engine = new Engine(canvas, true);
|
||||
}
|
||||
engine.setHardwareScalingLevel(1 / window.devicePixelRatio);
|
||||
|
||||
window.onresize = () => {
|
||||
engine.resize();
|
||||
}
|
||||
const scene = new Scene(engine);
|
||||
DefaultScene.Scene = scene;
|
||||
//const a = new CurveObject();
|
||||
scene.ambientColor = new Color3(.1, .1, .1);
|
||||
|
||||
//log.resetLevel();
|
||||
//log.setDefaultLevel('error');
|
||||
await this.initialize(scene);
|
||||
engine.runRenderLoop(() => {
|
||||
scene.render();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
const vrApp = new VrApp();
|
||||
buildQuestLink();
|
||||
@ -107,7 +90,6 @@ function setMainCamera(scene: Scene) {
|
||||
|
||||
async function initDb(diagramManager: DiagramManager) {
|
||||
const db = new PouchdbPersistenceManager();
|
||||
//const userManager = new UserManager(db.onUserObservable);
|
||||
db.setDiagramManager(diagramManager);
|
||||
await db.initialize();
|
||||
}
|
||||
@ -120,9 +102,3 @@ function initEnvironment(diagramManager: DiagramManager, spinner: Spinner) {
|
||||
});
|
||||
}, -1, false, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user