@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
80 lines • 3.45 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { Box3 } from 'three';
import { HTMLMesh } from 'three/examples/jsm/interactive/HTMLMesh.js';
import { InteractiveGroup } from 'three/examples/jsm/interactive/InteractiveGroup.js';
import { serializable } from '../../engine/engine_serialization.js';
import { getWorldRotation, setWorldRotationXYZ } from '../../engine/engine_three_utils.js';
import { Behaviour } from '../Component.js';
export class SpatialHtml extends Behaviour {
id = null;
keepAspect = false;
_object = null;
onEnable() {
if (this._object) {
this.gameObject.add(this._object);
return;
}
if (!this.id || !this.context.mainCamera)
return;
const div = document.getElementById(this.id);
if (!div) {
console.warn("Could not find element with id \"" + this.id + "\"");
return;
}
div.style.display = "block";
div.style.visibility = "hidden";
const group = new InteractiveGroup();
group.listenToPointerEvents(this.context.renderer, this.context.mainCamera);
// TODO listen to controller events?
this.gameObject.add(group);
const mesh = new HTMLMesh(div);
group.add(mesh);
mesh.visible = false;
const mat = mesh.material;
mat.transparent = true;
// need to wait one frame for it to render to get bounds
setTimeout(() => {
mesh.visible = true;
// align box to get bounding box
const rot = getWorldRotation(this.gameObject).clone();
setWorldRotationXYZ(this.gameObject, 0, 0, 0);
this.gameObject.updateMatrixWorld();
const aabb = new Box3();
aabb.setFromObject(group);
this.setWorldRotation(rot.x, rot.y, rot.z);
// apply bounds
const width = aabb.max.x - aabb.min.x;
const height = aabb.max.y - aabb.min.y;
if (this.keepAspect) {
const aspect = width / height;
if (width > height) {
mesh.scale.set(1 / width, 1 / height / aspect, 1);
}
else {
mesh.scale.set(1 / width * aspect, 1 / height, 1);
}
}
else {
mesh.scale.set(1 / width, 1 / height, 1);
}
// TODO: replace with world scale once we have that
const factor = this.gameObject.scale;
mesh.scale.multiply(factor);
}, 1);
}
onDisable() {
this._object?.removeFromParent();
}
}
__decorate([
serializable()
], SpatialHtml.prototype, "id", void 0);
__decorate([
serializable()
], SpatialHtml.prototype, "keepAspect", void 0);
//# sourceMappingURL=SpatialHtml.js.map