diff --git a/package-lock.json b/package-lock.json
index 9c1c818..4f9ac40 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -27,7 +27,7 @@
"@types/react": "^18.2.72",
"@types/react-dom": "^18.2.22",
"axios": "^1.6.8",
- "babylon-html": "0.0.3",
+ "canvas-hypertxt": "1.0.3",
"dom-to-image-more": "^3.3.0",
"earcut": "^2.2.4",
"events": "^3.3.0",
@@ -1127,15 +1127,6 @@
"proxy-from-env": "^1.1.0"
}
},
- "node_modules/babylon-html": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/babylon-html/-/babylon-html-0.0.3.tgz",
- "integrity": "sha512-QBIDVM6wbKOl94lFa0kJ3TxSBBvlGS6hzgtOaZ6QSAHgjkwsHtTBxliCRehaf2sh5IGmHuQNF8GlHHMOOXvqZg==",
- "dependencies": {
- "@babylonjs/core": "^7.1.0",
- "dom-to-image-more": "^3.3.0"
- }
- },
"node_modules/babylonjs-gltf2interface": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.5.0.tgz",
@@ -1215,6 +1206,11 @@
"node": ">=8"
}
},
+ "node_modules/canvas-hypertxt": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/canvas-hypertxt/-/canvas-hypertxt-1.0.3.tgz",
+ "integrity": "sha512-+VsMpRr64jYgKq2IeFUNel3vCZH/IzS+iXSHxmUV3IUH5dXlC9xHz4AwtPZisDxZ5MWcuK0V+TXgPKFPiZnxzg=="
+ },
"node_modules/chai": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
diff --git a/package.json b/package.json
index 74fe262..9fe94e8 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,7 @@
"@types/react": "^18.2.72",
"@types/react-dom": "^18.2.22",
"axios": "^1.6.8",
- "babylon-html": "0.0.3",
+ "canvas-hypertxt": "1.0.3",
"dom-to-image-more": "^3.3.0",
"earcut": "^2.2.4",
"events": "^3.3.0",
diff --git a/src/diagram/diagramMenuManager.ts b/src/diagram/diagramMenuManager.ts
index d212e4d..c845cda 100644
--- a/src/diagram/diagramMenuManager.ts
+++ b/src/diagram/diagramMenuManager.ts
@@ -38,8 +38,7 @@ export class DiagramMenuManager {
});
this.toolbox = new Toolbox();
this.scaleMenu = new ScaleMenu2(this._notifier);
- const clickMenu = this.createClickMenu(this.toolbox.handleMesh, null);
- clickMenu.dispose();
+
controllers.controllerObservable.add((event: ControllerEvent) => {
if (event.type == ControllerEventType.B_BUTTON) {
if (event.value > .8) {
diff --git a/src/menus/clickMenu.ts b/src/menus/clickMenu.ts
index 69da67f..d89a70b 100644
--- a/src/menus/clickMenu.ts
+++ b/src/menus/clickMenu.ts
@@ -1,5 +1,5 @@
import {AbstractMesh, ActionEvent, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core";
-import {HtmlButton} from "babylon-html";
+import {Button} from "../objects/Button";
const POINTER_UP = "pointerup";
@@ -74,11 +74,13 @@ export class ClickMenu {
this._transformNode.dispose(false, true);
}
- private makeNewButton(name: string, id: string, scene: Scene, x: number): HtmlButton {
- const button = new HtmlButton(name, id, scene, null, {html: null, image: {width: 268, height: 268}});
+ private makeNewButton(name: string, id: string, scene: Scene, x: number): Button {
+ const button = new Button(name, id, scene)
+ button.transform.scaling = new Vector3(.2, .2, .2);
+ button.transform.rotate(Vector3.Up(), Math.PI);
const transform = button.transform;
transform.parent = this._transformNode;
- transform.rotation.y = Math.PI;
+ //transform.rotation.y = Math.PI;
transform.position.x = x;
return button;
}
diff --git a/src/menus/scaleMenu.ts b/src/menus/scaleMenu.ts
index 39fc47e..9662843 100644
--- a/src/menus/scaleMenu.ts
+++ b/src/menus/scaleMenu.ts
@@ -1,6 +1,6 @@
import {DefaultScene} from "../defaultScene";
-import {HtmlButton, HtmlMeshBuilder} from "babylon-html";
import {AbstractMesh, Observable, TransformNode, Vector3} from "@babylonjs/core";
+import {Button} from "../objects/Button";
export class ScaleMenu {
@@ -17,21 +17,6 @@ export class ScaleMenu {
this.build();
}
- public changePosition(position: Vector3) {
- this.transform.position = position.clone();
- }
-
- public show(mesh: AbstractMesh) {
- this.transform.position = mesh.absolutePosition.clone();
- this.transform.position.y = mesh.getBoundingInfo().boundingBox.maximumWorld.y + .1;
- this.transform.setEnabled(true);
- this._mesh = mesh;
- }
-
- public hide() {
- this.transform.setEnabled(false);
- this._mesh = null;
- }
private async build() {
let x = .12;
@@ -78,7 +63,7 @@ export class ScaleMenu {
}
private makeButton(name: string, x: number, y: number, parent: TransformNode = null) {
- const button = new HtmlButton(name, name, DefaultScene.Scene);
+ const button = new Button(name, name, DefaultScene.Scene);
button.transform.parent = parent;
button.transform.position.x = x;
//button.transform.position.y = y;
@@ -113,18 +98,4 @@ export class ScaleMenu {
this.onScaleChangeObservable.notifyObservers(this._mesh);
}
}
-
- private async createLabel(name: string, y: number) {
- const label = await HtmlMeshBuilder.CreatePlane(`${name}-label`,
- {
- html: `
${name}
`,
- height: .1, image: {width: 128, height: 128}
- },
- DefaultScene.Scene);
-
- label.parent = this.transform;
- label.position.y = y;
- label.position.x = -.42;
- return label;
- }
}
diff --git a/src/objects/Button.ts b/src/objects/Button.ts
new file mode 100644
index 0000000..36a0afd
--- /dev/null
+++ b/src/objects/Button.ts
@@ -0,0 +1,186 @@
+import {
+ AbstractMesh,
+ ActionEvent,
+ ActionManager,
+ Color3,
+ DynamicTexture,
+ ExecuteCodeAction,
+ ICanvasRenderingContext,
+ MeshBuilder,
+ Observable,
+ Scene,
+ StandardMaterial,
+ TransformNode,
+ Vector3
+} from "@babylonjs/core";
+import {split} from "canvas-hypertxt";
+
+export type ButtonOptions = {
+ width?: number,
+ height?: number,
+ background?: Color3,
+ color?: Color3,
+ hoverBackground?: Color3,
+ hoverColor?: Color3,
+ clickBackground?: Color3,
+ clickColor?: Color3,
+ fontSize?: number
+}
+
+enum states {
+ NORMAL,
+ HOVER,
+ CLICK
+}
+
+export class Button {
+ public onPointerObservable: Observable = new Observable();
+ private _scene: Scene;
+ private _mesh: AbstractMesh;
+ private _width: number;
+ private _height: number;
+ private _background: Color3;
+ private _color: Color3;
+ private _hoverBackground: Color3;
+ private _hoverColor: Color3;
+ private _clickBackground?: Color3;
+ private _clickColor?: Color3;
+ private _textures: Map = new Map();
+ private _fontSize: number;
+ private readonly _density: number = 512;
+
+ constructor(name: string, id: string, scene: Scene, options?: ButtonOptions) {
+ this._scene = scene;
+ const opts = defaultOptions(options);
+ this.mapColors(options);
+ this._width = opts.width;
+ this._height = opts.height;
+ this._mesh = MeshBuilder.CreatePlane(name, opts, scene);
+ this._mesh.id = id;
+ this._transform = new TransformNode(id, scene);
+ this._mesh.parent = this._transform;
+ this._mesh.rotate(Vector3.Up(), Math.PI);
+ this._mesh.material = this.buildMaterial();
+ this.registerActions();
+
+ }
+
+ private _transform: TransformNode;
+
+ public get transform(): TransformNode {
+ return this._transform;
+ }
+
+ static CreateButton(name: string, id: string, scene: Scene, options?: ButtonOptions): Button {
+ const button = new Button(name, id, scene, options);
+ return button;
+ }
+
+ public dispose() {
+ this._mesh.dispose(false, true);
+ this._transform.dispose(false, true);
+ this.onPointerObservable.clear();
+ this.onPointerObservable = null;
+ this._transform = null;
+ this._scene = null;
+ this._mesh = null;
+ this._textures.forEach((value) => {
+ value.dispose();
+ });
+ this._textures.clear();
+ }
+
+ private mapColors(options?: ButtonOptions) {
+ this._background = options?.background || Color3.Black();
+ this._color = options?.color || Color3.White();
+ this._hoverBackground = options?.hoverBackground || Color3.Gray();
+ this._hoverColor = options?.hoverColor || Color3.White();
+ this._clickBackground = options?.clickBackground || Color3.White();
+ this._clickColor = options?.clickColor || Color3.Black();
+ this._fontSize = options?.fontSize || 512;
+
+ }
+
+ private buildMaterial(): StandardMaterial {
+ const mat = new StandardMaterial('buttonMat', this._scene);
+ //mat.diffuseColor.set(.5, .5, .5);
+ mat.backFaceCulling = false;
+ this._textures.set(states.NORMAL, this.drawText(this._mesh.name, this._color, this._background));
+ this._textures.set(states.HOVER, this.drawText(this._mesh.name, this._hoverColor, this._hoverBackground));
+ this._textures.set(states.CLICK, this.drawText(this._mesh.name, this._clickColor, this._clickBackground));
+ mat.emissiveTexture = this._textures.get(states.NORMAL);
+ mat.disableLighting = true;
+ return mat;
+ }
+
+ private drawText(name: string, foreground: Color3, background: Color3): DynamicTexture {
+ const opts = {width: this._width * this._density, height: this._height * this._density};
+ const texture = new DynamicTexture('buttonTexture', opts, this._scene);
+
+ const ctx: ICanvasRenderingContext = texture.getContext();
+ const ctx2d: CanvasRenderingContext2D = (ctx.canvas.getContext('2d') as CanvasRenderingContext2D);
+ const font = `900 ${this._fontSize / 10}px Arial`;
+ ctx2d.font = font;
+ ctx2d.textBaseline = 'middle';
+ ctx2d.textAlign = 'center';
+ ctx2d.fillStyle = background.toHexString();
+ ctx2d.fillRect(0, 0, this._width * this._density, this._height * this._density);
+ ctx2d.fillStyle = foreground.toHexString();
+ const lines = split(ctx2d, name, font, this._width * this._density, true);
+ const x = this._width * this._density / 2;
+ let y = this._height * this._density / 2 - (lines.length - 1) * 50 / 2;
+ for (const line of lines) {
+ ctx2d.fillText(line, x, y);
+ y += 50;
+ }
+ texture.update();
+ return texture;
+ }
+
+ private registerActions() {
+ const button = this._mesh;
+ button.actionManager = new ActionManager(this._scene);
+ button.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnPointerOverTrigger, (evt) => {
+ this.setMaterial(states.HOVER);
+ this.onPointerObservable.notifyObservers(evt);
+ }));
+ button.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnPointerOutTrigger, (evt) => {
+ this.setMaterial(states.NORMAL);
+ this.onPointerObservable.notifyObservers(evt);
+ }));
+ button.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnPickDownTrigger, (evt) => {
+ this.setMaterial(states.CLICK);
+ this.onPointerObservable.notifyObservers(evt);
+ }));
+ button.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnPickUpTrigger, (evt) => {
+ this.setMaterial(states.HOVER);
+ this.onPointerObservable.notifyObservers(evt);
+ }));
+ button.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnPointerOutTrigger, (evt) => {
+ this.setMaterial(states.NORMAL);
+ this.onPointerObservable.notifyObservers(evt);
+ }));
+ button.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnPickTrigger, (evt) => {
+ this.onPointerObservable.notifyObservers(evt);
+ }));
+ }
+
+ private setMaterial(state: states) {
+ if (this._mesh && this._mesh.material && this._textures.has(state)) {
+ (this._mesh.material as StandardMaterial).emissiveTexture = this._textures.get(state);
+ }
+ }
+}
+
+function defaultOptions(options: ButtonOptions): ButtonOptions {
+ if (!options) {
+ options = {width: .5, height: .5};
+ }
+ if (!options.width) {
+ options.width = .5;
+ }
+ if (!options.height) {
+ options.height = .5;
+ }
+ return options;
+}
\ No newline at end of file
diff --git a/src/objects/handle.ts b/src/objects/handle.ts
index 1b8c370..be905a1 100644
--- a/src/objects/handle.ts
+++ b/src/objects/handle.ts
@@ -1,9 +1,18 @@
-import {AbstractMesh, Scene, TransformNode, Vector3} from "@babylonjs/core";
-import {HtmlMeshBuilder} from "babylon-html";
+import {
+ Color3,
+ DynamicTexture,
+ ICanvasRenderingContext,
+ MeshBuilder,
+ Scene,
+ StandardMaterial,
+ TransformNode,
+ Vector3
+} from "@babylonjs/core";
import log, {Logger} from "loglevel";
+import {split} from "canvas-hypertxt";
export class Handle {
- public mesh: AbstractMesh;
+ public mesh: TransformNode;
private readonly _menuItem: TransformNode;
private _isStored: boolean = false;
private _offset: Vector3;
@@ -30,15 +39,21 @@ export class Handle {
private buildHandle() {
const scene: Scene = this._menuItem.getScene();
- const handle = HtmlMeshBuilder.CreatePlaneSync('handle-' + this._menuItem.id, {
- html:
- `${this._label}
- `, width: .5, height: .1, image: {width: 256, height: 51}
- }, scene);
+
+
+ const handle = MeshBuilder.CreatePlane('handle-' + this._menuItem.id, {width: .4, height: .4 / 8}, scene);
+ //button.transform.scaling.set(.1,.1,.1);
+ const texture = this.drawText(this._label, Color3.White(), Color3.Black());
+ const material = new StandardMaterial('handleMaterial', scene);
+ material.emissiveTexture = texture;
+ material.disableLighting = true;
+ handle.material = material;
+ //handle.rotate(Vector3.Up(), Math.PI);
handle.id = 'handle-' + this._menuItem.id;
if (this._menuItem) {
this._menuItem.setParent(handle);
}
+
const stored = localStorage.getItem(handle.id);
if (stored) {
this._logger.debug('Stored location found for ' + handle.id);
@@ -60,6 +75,30 @@ export class Handle {
}
handle.metadata = {handle: true};
this.mesh = handle;
+
}
+ private drawText(name: string, foreground: Color3, background: Color3): DynamicTexture {
+ const texture = new DynamicTexture('handleTexture', {width: 512, height: 64}, this._menuItem.getScene());
+ const ctx: ICanvasRenderingContext = texture.getContext();
+ const ctx2d: CanvasRenderingContext2D = (ctx.canvas.getContext('2d') as CanvasRenderingContext2D);
+ const font = `900 24px Arial`;
+ ctx2d.font = font;
+ ctx2d.textBaseline = 'middle';
+ ctx2d.textAlign = 'center';
+ ctx2d.fillStyle = background.toHexString();
+ ctx2d.fillRect(0, 0, 512, 64);
+ ctx2d.fillStyle = foreground.toHexString();
+ const lines = split(ctx2d, name, font, 512, true);
+ const x = 256;
+ let y = 32;
+ for (const line of lines) {
+ ctx2d.fillText(line, x, y);
+ y += 50;
+ }
+ texture.update();
+ return texture;
+ }
+
+
}
\ No newline at end of file
diff --git a/src/tutorial/introduction.ts b/src/tutorial/introduction.ts
index 8dca068..9ca6dbe 100644
--- a/src/tutorial/introduction.ts
+++ b/src/tutorial/introduction.ts
@@ -10,8 +10,8 @@ import {
VideoTexture
} from "@babylonjs/core";
import {DefaultScene} from "../defaultScene";
-import {HtmlButton} from "babylon-html";
import Hls from "hls.js";
+import {Button} from "../objects/Button";
type Step = {
name: string;
@@ -82,9 +82,13 @@ export class Introduction {
hls.attachMedia(vid);
hls.on(Hls.Events.MANIFEST_PARSED, function () {
vid.loop = false;
+
vid.play().then(() => {
- this.logger.debug("Video Playing");
+ //this.logger.debug("Video Playing");
+ }).catch((err) => {
+ console.error(err);
});
+
});
} else if (vid.canPlayType('application/vnd.apple.mpegurl')) {
vid.src = src;
@@ -92,6 +96,8 @@ export class Introduction {
vid.addEventListener('loadedmetadata', function () {
vid.play().then(() => {
+ }).catch((err) => {
+ console.error(err);
});
});
}
@@ -109,15 +115,14 @@ export class Introduction {
}, -1, true, this, false);
}
- private buildButton(name: string): HtmlButton {
- const button = new HtmlButton(name, name, this._scene, null,
- {html: null, image: {width: 512, height: 512}, width: .5, height: .5});
+ private buildButton(name: string): Button {
+ const button = new Button(name, name, this._scene, {width: .5, height: .5, fontSize: 400});
button.transform.position.y = .4;
return button;
}
- private step(index: number, prev?: HtmlButton, prevVideo?: AbstractMesh) {
+ private step(index: number, prev?: Button, prevVideo?: AbstractMesh) {
if (prevVideo && prevVideo?.metadata) {
prevVideo.metadata.video.pause();
prevVideo.metadata.video.remove();
diff --git a/src/util/displayDebug.ts b/src/util/displayDebug.ts
index 7a70d9c..88add5d 100644
--- a/src/util/displayDebug.ts
+++ b/src/util/displayDebug.ts
@@ -1,5 +1,5 @@
import {TransformNode} from "@babylonjs/core";
-import {HtmlMeshBuilder} from "babylon-html";
+
const debug = true;
@@ -15,14 +15,8 @@ function drawDebugText(text: string[]) {
transform.getScene().onActiveCameraChanged.add(() => {
transform.parent = transform.getScene().activeCamera;
});
-
+ console.log(text);
transform.position.z = 1;
transform.position.y = .2;
- const plane = HtmlMeshBuilder.CreatePlaneSync('debugMesh', {
- html:
- `${text.join('
')}
- `, width: .3, height: .05 * text.length, image: {width: 256, height: 32 * text.length}
- }, transform.getScene());
- plane.parent = transform;
}
\ No newline at end of file