211 lines
7.8 KiB
TypeScript
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[];
|
|
} |