immersive2/src/toolbox/toolbox.ts

211 lines
7.8 KiB
TypeScript

import {
AbstractMesh, Angle,
Color3, InstancedMesh, Mesh,
MeshBuilder,
Scene,
StandardMaterial, TransformNode,
Vector3,
WebXRExperienceHelper
} from "@babylonjs/core";
import {CameraHelper} from "../util/cameraHelper";
import {AdvancedDynamicTexture, Button3D, ColorPicker, GUI3DManager, StackPanel3D, TextBlock} from "@babylonjs/gui";
import {DiagramManager} from "../diagram/diagramManager";
import {DiagramEventType} from "../diagram/diagramEntity";
export enum ToolType {
BOX ="#box-template",
Sphere="#sphere-template",
Cylinder="#cylinder-template",
Cone ="#cone-template",
PLANE ="#plane-template",
OBJECT ="#object-template",
}
export class Toolbox {
public static getToolTypeFromString(type: string): ToolType {
return ToolType[Object.keys(ToolType).find(() => type)]
}
private index = 0;
public static instance: Toolbox;
private readonly scene: Scene;
private readonly xr: WebXRExperienceHelper;
public readonly node : TransformNode;
private readonly manager: GUI3DManager;
private readonly gridsize = 5;
private readonly addPanel: StackPanel3D;
constructor (scene:Scene, xr: WebXRExperienceHelper) {
this.scene = scene;
this.addPanel = new StackPanel3D();
this.manager = new GUI3DManager(scene);
this.manager.addControl(this.addPanel);
this.node = new TransformNode("toolbox", this.scene);
const handle = MeshBuilder.CreateCapsule("handle", { radius: .01 , orientation: Vector3.Right(), height: .3}, this.scene);
handle.id = "handle";
const handleMaterial = new StandardMaterial("handle-material", this.scene);
handleMaterial.diffuseColor = Color3.FromHexString("#EEEEFF");
handle.material = handleMaterial;
handle.position = CameraHelper.getFrontPosition(2, this.scene);
handle.position.y = 1.6;
this.node.parent = handle;
this.xr = xr;
if (!this.scene.activeCamera) {
return;
} else {
this.buildToolbox();
}
Toolbox.instance = this;
}
private buildToolbox() {
this.node.position.y = -.2;
this.node.scaling= new Vector3(0.5, 0.5, 0.5);
const color = "#7777FF";
this.buildColor(Color3.FromHexString(color));
const addButton= new Button3D("add-button");
const text = new TextBlock("add-button-text", "Add Color");
text.color="white";
text.fontSize = "48px";
text.text = "Add Color";
addButton.content = text;
this.addPanel.node.parent = this.node;
this.addPanel.addControl(addButton);
this.addPanel.node.rotation =
new Vector3(
Angle.FromDegrees(0).radians(),
Angle.FromDegrees(180).radians(),
Angle.FromDegrees(0).radians());
this.addPanel.node.scaling = new Vector3(.1, .1,.1);
this.addPanel.position = new Vector3(0, 0, .5);
addButton.onPointerClickObservable.add(() => {
this.buildColor(Color3.Random());
});
}
private calculatePosition(i: number) {
return (i/this.gridsize)-.5-(1/this.gridsize/2);
}
private static WIDGET_SIZE = .1;
private buildColor(color: Color3) {
const width = 1;
const depth = .2;
const material = new StandardMaterial("material-" + color.toHexString(), this.scene);
material.diffuseColor = color;
const mesh = MeshBuilder.CreateBox("toolbox-color-" + color.toHexString(), {width: width, height: .01, depth: depth}, this.scene);
mesh.material = material;
mesh.position.z = this.index++/4;
mesh.parent = this.node;
let i = 0;
for (const tool of enumKeys(ToolType)) {
const newItem = this.buildTool(ToolType[tool], mesh);
if (newItem) {
newItem.position = new Vector3(this.calculatePosition(++i), .1, 0);
}
}
const myPlane = MeshBuilder
.CreatePlane("myPlane",
{width: Toolbox.WIDGET_SIZE,
height: Toolbox.WIDGET_SIZE}, this.scene);
myPlane.parent=mesh;
myPlane.position= new Vector3(this.calculatePosition(++i), .1, 0);
const advancedTexture2 = AdvancedDynamicTexture.CreateForMesh(myPlane, 1024, 1024);
const colorPicker = new ColorPicker("color-picker");
colorPicker.scaleY = 5;
colorPicker.scaleX = 5;
colorPicker.value = color;
colorPicker.onValueChangedObservable.add((value) => {
const oldColor = material.diffuseColor.clone();
material.diffuseColor = value;
material.id = "material-" + value.toHexString();
material.name = "material-" + value.toHexString();
mesh.id = "toolbox-color-" + value.toHexString();
mesh.name = "toolbox-color-" + value.toHexString();
DiagramManager.onDiagramEventObservable.notifyObservers(
{
type: DiagramEventType.CHANGECOLOR,
oldColor: oldColor,
newColor: value
}
);
});
advancedTexture2.addControl(colorPicker);
this.addPanel.position.z += .25;
this.node.position.z -= .125;
}
public updateToolbox(color: string) {
if (this.scene.getMeshById("toolbox-color-" + color)) {
return;
} else {
this.buildColor(Color3.FromHexString(color));
}
}
public buildTool(tool: ToolType, parent: AbstractMesh) {
let newItem: Mesh;
const id = tool + "-" + (parent.material as StandardMaterial).diffuseColor.toHexString();
const material = parent.material;
const toolname = "tool-" + id;
switch (tool) {
case ToolType.BOX:
newItem = MeshBuilder.CreateBox(toolname, {width: 1, height: 1, depth: 1}, this.scene);
break;
case ToolType.Sphere:
newItem = MeshBuilder.CreateSphere(toolname, {diameter: 1}, this.scene);
break;
case ToolType.Cylinder:
newItem = MeshBuilder.CreateCylinder(toolname, {height: 1, diameter: 1}, this.scene);
break;
case ToolType.Cone:
newItem = MeshBuilder.CreateCylinder(toolname, {diameterTop: 0, height: 1, diameterBottom: 1}, this.scene);
break;
case ToolType.PLANE:
newItem = MeshBuilder.CreatePlane(toolname, {width: 1, height: 1}, this.scene);
break;
case ToolType.OBJECT:
break;
}
if (newItem) {
newItem.material = material;
newItem.id = "tool-" + id;
if (tool === ToolType.PLANE) {
newItem.material.backFaceCulling = false;
}
newItem.scaling = new Vector3(Toolbox.WIDGET_SIZE,
Toolbox.WIDGET_SIZE,
Toolbox.WIDGET_SIZE);
newItem.parent = parent;
if (!newItem.material) {
newItem.material = parent.material;
}
if (newItem.metadata) {
newItem.metadata.template = tool;
} else {
newItem.metadata = {template: tool};
}
const instance = new InstancedMesh("instance-"+id, newItem);
if (instance.metadata) {
instance.metadata.template = tool;
} else {
instance.metadata = {template: tool};
}
instance.parent= parent;
newItem.setEnabled(false)
return instance;
} else {
return null;
}
}
public show() {
this.buildToolbox();
}
}
function enumKeys<O extends object, K extends keyof O = keyof O>(obj: O): K[] {
return Object.keys(obj).filter(k => Number.isNaN(+k)) as K[];
}