Added stl person to toolbox.
This commit is contained in:
parent
d08e86e92f
commit
e0d85a6a3d
BIN
public/assets/models/person.stl
Normal file
BIN
public/assets/models/person.stl
Normal file
Binary file not shown.
@ -96,7 +96,6 @@ async function start() {
|
||||
conn.connection.sendUTF('{ "type": "error", "netAddr": "' + hash + '" }');
|
||||
});
|
||||
logger.info((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.', connections.length);
|
||||
|
||||
});
|
||||
setInterval(() => {
|
||||
const message = `{ "count": ${connections.size} }`
|
||||
|
||||
@ -27,12 +27,12 @@ export class DiagramManager {
|
||||
private _moving: number = 10;
|
||||
private _i: number = 0;
|
||||
|
||||
constructor() {
|
||||
constructor(readyObservable: Observable<boolean>) {
|
||||
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);
|
||||
this._diagramMenuManager = new DiagramMenuManager(this.onDiagramEventObservable, this._controllers, this._config, readyObservable);
|
||||
this._diagramEntityActionManager = buildEntityActionManager(this._controllers);
|
||||
this.onDiagramEventObservable.add(this.onDiagramEvent, DiagramEventObserverMask.FROM_DB, true, this);
|
||||
|
||||
@ -97,6 +97,7 @@ export class DiagramManager {
|
||||
|
||||
});
|
||||
this._logger.debug("DiagramManager constructed");
|
||||
|
||||
}
|
||||
|
||||
public get actionManager(): AbstractActionManager {
|
||||
@ -140,7 +141,7 @@ export class DiagramManager {
|
||||
|
||||
|
||||
private onDiagramEvent(event: DiagramEvent) {
|
||||
let diagramObject = this._diagramObjects.get(event.entity.id);
|
||||
let diagramObject = this._diagramObjects.get(event?.entity?.id);
|
||||
switch (event.type) {
|
||||
case DiagramEventType.ADD:
|
||||
if (diagramObject) {
|
||||
@ -160,7 +161,7 @@ export class DiagramManager {
|
||||
if (diagramObject) {
|
||||
diagramObject.dispose();
|
||||
}
|
||||
this._diagramObjects.delete(event.entity.id);
|
||||
this._diagramObjects.delete(event?.entity?.id);
|
||||
break;
|
||||
case DiagramEventType.MODIFY:
|
||||
this._logger.debug(event);
|
||||
|
||||
@ -26,7 +26,7 @@ export class DiagramMenuManager {
|
||||
private _logger = log.getLogger('DiagramMenuManager');
|
||||
private _connectionPreview: ConnectionPreview;
|
||||
|
||||
constructor(notifier: Observable<DiagramEvent>, controllers: Controllers, config: AppConfig) {
|
||||
constructor(notifier: Observable<DiagramEvent>, controllers: Controllers, config: AppConfig, readyObservable: Observable<boolean>) {
|
||||
this._scene = DefaultScene.Scene;
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ export class DiagramMenuManager {
|
||||
const event = {type: DiagramEventType.MODIFY, entity: {id: evt.id, text: evt.text}}
|
||||
this._notifier.notifyObservers(event, DiagramEventObserverMask.FROM_DB);
|
||||
});
|
||||
this.toolbox = new Toolbox();
|
||||
this.toolbox = new Toolbox(readyObservable);
|
||||
this.scaleMenu = new ScaleMenu2(this._notifier);
|
||||
if (viewOnly()) {
|
||||
this.toolbox.handleMesh.setEnabled(false);
|
||||
|
||||
@ -62,6 +62,7 @@ function createNewInstanceIfNecessary(entity: DiagramEntity, scene: Scene): Abst
|
||||
case DiagramTemplates.CYLINDER:
|
||||
case DiagramTemplates.CONE:
|
||||
case DiagramTemplates.PLANE:
|
||||
case DiagramTemplates.PERSON:
|
||||
const toolMesh = scene.getMeshById("tool-" + entity.template + "-" + entity.color);
|
||||
if (toolMesh && !oldMesh) {
|
||||
newMesh = new InstancedMesh(entity.id, (toolMesh as Mesh));
|
||||
|
||||
@ -30,6 +30,7 @@ export enum DiagramTemplates {
|
||||
CONE = "#cone-template",
|
||||
IMAGE = "#image-template",
|
||||
PLANE = "#plane-template",
|
||||
PERSON = "#person-template"
|
||||
}
|
||||
|
||||
export type DiagramEvent = {
|
||||
|
||||
@ -28,6 +28,8 @@ export class PouchdbPersistenceManager {
|
||||
private _encryption = new Encryption();
|
||||
private _encKey = null;
|
||||
private _diagramManager: DiagramManager;
|
||||
private _salt: string;
|
||||
private _failCount: number = 0;
|
||||
|
||||
constructor() {
|
||||
document.addEventListener('passwordset', (evt) => {
|
||||
@ -37,7 +39,7 @@ export class PouchdbPersistenceManager {
|
||||
this._logger.debug('Initialized');
|
||||
});
|
||||
}
|
||||
console.log(evt);
|
||||
this._logger.debug(evt);
|
||||
});
|
||||
}
|
||||
|
||||
@ -45,6 +47,14 @@ export class PouchdbPersistenceManager {
|
||||
this._diagramManager = diagramManager;
|
||||
diagramManager.onDiagramEventObservable.add((evt) => {
|
||||
this._logger.debug(evt);
|
||||
if (!evt?.entity) {
|
||||
this._logger.warn('no entity');
|
||||
return;
|
||||
}
|
||||
if (!evt?.entity?.id) {
|
||||
this._logger.warn('no entity id');
|
||||
return;
|
||||
}
|
||||
switch (evt.type) {
|
||||
case DiagramEventType.REMOVE:
|
||||
this.remove(evt.entity.id);
|
||||
@ -105,6 +115,9 @@ export class PouchdbPersistenceManager {
|
||||
this._logger.warn('CONFLICTS!', doc._conflicts);
|
||||
}
|
||||
if (this._encKey) {
|
||||
if (!doc.encrypted) {
|
||||
this._logger.warn("current local doc is not encrypted, encrypting");
|
||||
}
|
||||
await this._encryption.encryptObject(entity);
|
||||
const newDoc = {
|
||||
_id: doc._id,
|
||||
@ -114,6 +127,9 @@ export class PouchdbPersistenceManager {
|
||||
this.db.put(newDoc)
|
||||
} else {
|
||||
if (doc) {
|
||||
if (doc.encrypted) {
|
||||
this._logger.error("current local doc is encrypted, but encryption key is missing... saving in plaintext");
|
||||
}
|
||||
const newDoc = {_id: doc._id, _rev: doc._rev, ...entity};
|
||||
this.db.put(newDoc);
|
||||
} else {
|
||||
@ -125,6 +141,10 @@ export class PouchdbPersistenceManager {
|
||||
if (err.status == 404) {
|
||||
try {
|
||||
if (this._encKey) {
|
||||
if (!this._encryption.ready) {
|
||||
this._logger.error('Encryption not ready, there is a potential problem when this happens, we will generate a new salt which may cause data loss and/or slowness');
|
||||
await this._encryption.setPassword(this._encKey);
|
||||
}
|
||||
await this._encryption.encryptObject(entity);
|
||||
const newDoc = {
|
||||
_id: entity.id,
|
||||
@ -132,13 +152,16 @@ export class PouchdbPersistenceManager {
|
||||
}
|
||||
this.db.put(newDoc);
|
||||
} else {
|
||||
this._logger.info('no encryption key, saving in plaintext');
|
||||
const newEntity = {_id: entity.id, ...entity};
|
||||
this.db.put(newEntity);
|
||||
}
|
||||
} catch (err2) {
|
||||
this._logger.error("Unable to save document");
|
||||
this._logger.error(err2);
|
||||
}
|
||||
} else {
|
||||
this._logger.error("Unknown error with document get from db");
|
||||
this._logger.error(err);
|
||||
}
|
||||
}
|
||||
@ -155,20 +178,27 @@ export class PouchdbPersistenceManager {
|
||||
try {
|
||||
const doc = await this.db.get('metadata');
|
||||
if (doc.encrypted) {
|
||||
if (!this._salt && doc.encrypted.salt) {
|
||||
this._logger.warn('Missing Salt');
|
||||
this._salt = doc.encrypted.salt;
|
||||
}
|
||||
if (!this._encKey) {
|
||||
const promptPassword = new CustomEvent('promptpassword', {detail: 'Please enter password'});
|
||||
document.dispatchEvent(promptPassword);
|
||||
return false;
|
||||
}
|
||||
if (!this._encryption.ready) {
|
||||
this._logger.warn("Encryption not ready, setting password");
|
||||
await this._encryption.setPassword(this._encKey, doc.encrypted.salt);
|
||||
}
|
||||
const decrypted = await this._encryption.decryptToObject(doc.encrypted.encrypted, doc.encrypted.iv);
|
||||
if (decrypted.friendly) {
|
||||
this._logger.info("Storing Document friendly name in local storage, decrypted");
|
||||
localStorage.setItem(current, decrypted.friendly);
|
||||
}
|
||||
} else {
|
||||
if (doc && doc.friendly) {
|
||||
this._logger.info("Storing Document friendly name in local storage");
|
||||
localStorage.setItem(current, doc.friendly);
|
||||
}
|
||||
if (doc && doc.camera) {
|
||||
@ -192,7 +222,7 @@ export class PouchdbPersistenceManager {
|
||||
await this.db.put(newDoc);
|
||||
}
|
||||
} else {
|
||||
this._logger.debug('no friendly name found');
|
||||
this._logger.warn('no friendly name found');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,12 +255,9 @@ export class PouchdbPersistenceManager {
|
||||
}
|
||||
|
||||
private async sendLocalDataToScene() {
|
||||
|
||||
let salt = null;
|
||||
|
||||
const clear = localStorage.getItem('clearLocal');
|
||||
try {
|
||||
|
||||
const all = await this.db.allDocs({include_docs: true});
|
||||
for (const dbEntity of all.rows) {
|
||||
this._logger.debug(dbEntity.doc);
|
||||
@ -265,8 +292,14 @@ export class PouchdbPersistenceManager {
|
||||
switch (err.message) {
|
||||
case 'WebCrypto_DecryptionFailure: ':
|
||||
case 'Invalid data type!':
|
||||
this._failCount++;
|
||||
if (this._failCount < 5) {
|
||||
const promptPassword = new CustomEvent('promptpassword', {detail: 'Please enter password'});
|
||||
document.dispatchEvent(promptPassword);
|
||||
} else {
|
||||
this._logger.error('Too many decryption failures, Ignoring... This may compromise your data security');
|
||||
window.alert('Too many decryption failures, Ignoring... This may compromise your data security');
|
||||
}
|
||||
}
|
||||
this._logger.error(err);
|
||||
}
|
||||
|
||||
@ -94,15 +94,15 @@ export class Presence {
|
||||
this._logger.warn('user not found', data.user);
|
||||
const newUser = MeshBuilder.CreateDisc(data.user.id, {radius: 0.3}, scene);
|
||||
const node = new TransformNode(data.netAddr, scene);
|
||||
|
||||
const material = new StandardMaterial(data.user.id + 'mat', scene);
|
||||
material.diffuseColor = new Color3(0, 0, 1);
|
||||
material.backFaceCulling = false;
|
||||
|
||||
newUser.material = material;
|
||||
newUser.parent = node;
|
||||
newUser.rotation.x = Math.PI / 2;
|
||||
newUser.position.y = 0.01;
|
||||
node.position = xyztovec(data.user.base.position);
|
||||
node.rotation = xyztovec(data.user.base.rotation);
|
||||
}
|
||||
}
|
||||
this._logger.debug('user update', data.user);
|
||||
|
||||
@ -12,7 +12,7 @@ import {enumKeys} from "../../util/functions/enumKeys";
|
||||
import {ToolType} from "../types/toolType";
|
||||
import {buildTool} from "./buildTool";
|
||||
|
||||
export function buildColor(color: Color3, scene: Scene, parent: TransformNode, index: number, toolMap: Map<string, AbstractMesh>): Node {
|
||||
export async function buildColor(color: Color3, scene: Scene, parent: TransformNode, index: number, toolMap: Map<string, AbstractMesh>): Promise<Node> {
|
||||
const width = .1;
|
||||
const height = .1;
|
||||
const material = new StandardMaterial("material-" + color.toHexString(), scene);
|
||||
@ -38,7 +38,7 @@ export function buildColor(color: Color3, scene: Scene, parent: TransformNode, i
|
||||
let i = 0;
|
||||
const tools = [];
|
||||
for (const tool of enumKeys(ToolType)) {
|
||||
const newItem = buildTool(ToolType[tool], colorBoxMesh, material);
|
||||
const newItem = await buildTool(ToolType[tool], colorBoxMesh, material);
|
||||
if (newItem) {
|
||||
//buildColorPicker(scene, color, newItem, material, i, colorChangeObservable);
|
||||
newItem.position = new Vector3(calculatePosition(++i), .1, 0);
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import {ToolType} from "../types/toolType";
|
||||
import {Mesh, MeshBuilder, Scene} from "@babylonjs/core";
|
||||
import {Mesh, MeshBuilder, Scene, SceneLoader} from "@babylonjs/core";
|
||||
import {DefaultScene} from "../../defaultScene";
|
||||
|
||||
const detail = {
|
||||
tesselation: 16,
|
||||
subdivisions: 5
|
||||
}
|
||||
export function buildMesh(type: ToolType, toolname: string, scene: Scene): Mesh {
|
||||
|
||||
export async function buildMesh(type: ToolType, toolname: string, scene: Scene): Promise<Mesh> {
|
||||
switch (type) {
|
||||
case ToolType.BOX:
|
||||
return MeshBuilder.CreateBox(toolname, {width: 1, height: 1, depth: 1}, scene);
|
||||
@ -34,7 +36,11 @@ export function buildMesh(type: ToolType, toolname: string, scene: Scene): Mesh
|
||||
diameterBottom: 1,
|
||||
tessellation: detail.tesselation
|
||||
}, scene);
|
||||
|
||||
case ToolType.PERSON:
|
||||
const result = await SceneLoader.ImportMeshAsync(null, '/assets/models/', 'person.stl', DefaultScene.Scene);
|
||||
result.meshes[0].id = toolname;
|
||||
result.meshes[0].name = toolname;
|
||||
return result.meshes[0] as Mesh;
|
||||
case ToolType.PLANE:
|
||||
return MeshBuilder.CreatePlane(toolname, {width: 1, height: 1}, scene);
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import {buildMesh} from "./buildMesh";
|
||||
|
||||
const WIDGET_SIZE = .1;
|
||||
|
||||
export function buildTool(tool: ToolType, colorParent: AbstractMesh, material: Material) {
|
||||
export async function buildTool(tool: ToolType, colorParent: AbstractMesh, material: Material) {
|
||||
let id = "ID";
|
||||
let color = "#000000";
|
||||
switch (material.getClassName()) {
|
||||
@ -21,7 +21,7 @@ export function buildTool(tool: ToolType, colorParent: AbstractMesh, material: M
|
||||
}
|
||||
|
||||
|
||||
const newItem = buildMesh(tool, `tool-${id}`, colorParent.getScene());
|
||||
const newItem = await buildMesh(tool, `tool-${id}`, colorParent.getScene());
|
||||
if (!newItem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {AbstractMesh, Color3, InstancedMesh, Node, Scene, TransformNode, Vector3} from "@babylonjs/core";
|
||||
import {AbstractMesh, Color3, InstancedMesh, Node, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core";
|
||||
import {buildColor} from "./functions/buildColor";
|
||||
import log from "loglevel";
|
||||
import {Handle} from "../objects/handle";
|
||||
@ -19,13 +19,16 @@ export class Toolbox {
|
||||
private readonly _handle: Handle;
|
||||
private readonly _scene: Scene;
|
||||
|
||||
constructor() {
|
||||
constructor(readyObservable: Observable<boolean>) {
|
||||
this._scene = DefaultScene.Scene;
|
||||
this._toolboxBaseNode = new TransformNode("toolbox", this._scene);
|
||||
this._handle = new Handle(this._toolboxBaseNode, 'Toolbox');
|
||||
this._toolboxBaseNode.position.y = .2;
|
||||
this._toolboxBaseNode.scaling = new Vector3(0.6, 0.6, 0.6);
|
||||
this.buildToolbox();
|
||||
this.buildToolbox().then(() => {
|
||||
readyObservable.notifyObservers(true);
|
||||
this._logger.info('Toolbox built');
|
||||
});
|
||||
Toolbox._instance = this;
|
||||
}
|
||||
private index = 0;
|
||||
@ -46,9 +49,9 @@ export class Toolbox {
|
||||
return this._tools.has(mesh.id);
|
||||
}
|
||||
|
||||
private buildToolbox() {
|
||||
private async buildToolbox() {
|
||||
this.setupPointerObservable();
|
||||
this.buildColorPicker();
|
||||
await this.buildColorPicker();
|
||||
if (this._toolboxBaseNode.parent) {
|
||||
const platform = this._scene.getMeshById("platform");
|
||||
if (platform) {
|
||||
@ -94,10 +97,10 @@ export class Toolbox {
|
||||
node.isEnabled(false) == true
|
||||
};
|
||||
|
||||
private buildColorPicker() {
|
||||
private async buildColorPicker() {
|
||||
let initial = true;
|
||||
for (const c of colors) {
|
||||
const cnode = buildColor(Color3.FromHexString(c), this._scene, this._toolboxBaseNode, this.index++, this._tools);
|
||||
const cnode = await buildColor(Color3.FromHexString(c), this._scene, this._toolboxBaseNode, this.index++, this._tools);
|
||||
if (initial) {
|
||||
initial = false;
|
||||
for (const id of cnode.metadata.tools) {
|
||||
|
||||
@ -5,4 +5,5 @@ export enum ToolType {
|
||||
CONE = "#cone-template",
|
||||
PLANE = "#plane-template",
|
||||
OBJECT = "#object-template",
|
||||
PERSON = "#person-template"
|
||||
}
|
||||
61
src/vrApp.ts
61
src/vrApp.ts
@ -1,4 +1,4 @@
|
||||
import {Color3, Engine, FreeCamera, Scene, Vector3, WebGPUEngine} from "@babylonjs/core";
|
||||
import {Color3, Engine, FreeCamera, Observable, Scene, Vector3, WebGPUEngine} from "@babylonjs/core";
|
||||
import '@babylonjs/loaders';
|
||||
import {DiagramManager} from "./diagram/diagramManager";
|
||||
import log, {Logger} from "loglevel";
|
||||
@ -16,7 +16,7 @@ import {Introduction} from "./tutorial/introduction";
|
||||
|
||||
const webGpu = false;
|
||||
|
||||
log.setLevel('error', false);
|
||||
log.setLevel('debug', false);
|
||||
const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
|
||||
export class VrApp {
|
||||
|
||||
@ -30,7 +30,39 @@ 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();
|
||||
const diagramReadyObservable = new Observable<boolean>();
|
||||
const diagramManager = new DiagramManager(diagramReadyObservable);
|
||||
diagramReadyObservable.add((ready) => {
|
||||
if (ready) {
|
||||
initDb(diagramManager);
|
||||
} else {
|
||||
this.logger.error('DiagramManager not ready');
|
||||
}
|
||||
});
|
||||
initEnvironment(diagramManager, spinner);
|
||||
const gamepadManager = new GamepadManager(scene);
|
||||
addSceneInspector();
|
||||
//const camMenu = new CameraMenu(scene);
|
||||
const el = document.querySelector('#download');
|
||||
if (el) {
|
||||
el.addEventListener('click', () => {
|
||||
exportGltf();
|
||||
})
|
||||
}
|
||||
if (!localStorage.getItem('tutorialCompleted')) {
|
||||
this.logger.info('Starting tutorial');
|
||||
const intro = new Introduction();
|
||||
}
|
||||
this.logger.info('Render loop started');
|
||||
}
|
||||
|
||||
private async initializeEngine() {
|
||||
|
||||
let engine: WebGPUEngine | Engine = null;
|
||||
if (webGpu) {
|
||||
engine = new WebGPUEngine(canvas);
|
||||
@ -56,28 +88,6 @@ export class VrApp {
|
||||
});
|
||||
|
||||
}
|
||||
public async initialize(scene: Scene) {
|
||||
setMainCamera(scene);
|
||||
const spinner = new Spinner();
|
||||
spinner.show();
|
||||
const diagramManager = new DiagramManager();
|
||||
await initDb(diagramManager);
|
||||
initEnvironment(diagramManager, spinner);
|
||||
const gamepadManager = new GamepadManager(scene);
|
||||
addSceneInspector();
|
||||
//const camMenu = new CameraMenu(scene);
|
||||
const el = document.querySelector('#download');
|
||||
if (el) {
|
||||
el.addEventListener('click', () => {
|
||||
exportGltf();
|
||||
})
|
||||
}
|
||||
if (!localStorage.getItem('tutorialCompleted')) {
|
||||
this.logger.info('Starting tutorial');
|
||||
const intro = new Introduction();
|
||||
}
|
||||
this.logger.info('Render loop started');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -95,10 +105,7 @@ async function initDb(diagramManager: DiagramManager) {
|
||||
const db = new PouchdbPersistenceManager();
|
||||
//const userManager = new UserManager(db.onUserObservable);
|
||||
db.setDiagramManager(diagramManager);
|
||||
|
||||
await db.initialize();
|
||||
|
||||
|
||||
}
|
||||
|
||||
function initEnvironment(diagramManager: DiagramManager, spinner: Spinner) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user