@tomorrowevening/hermes
Version:
An extendable set of Web Tools controlled via a separate window for non-intereference with content.
453 lines (452 loc) • 14 kB
JavaScript
import { Color as l, ColorManagement as p, WebGPURenderer as g, RenderTarget as v, WebGLRenderTarget as f } from "three/webgpu";
import E from "./BaseRemote.js";
import { clamp as S } from "../../utils/math.js";
import { dispose as u } from "../../utils/threeDispose.js";
import { hierarchyUUID as o, ExportTexture as h, resetThreeObjects as c } from "../../utils/threeEditorDebug.js";
var b = /* @__PURE__ */ ((a) => (a.CUSTOM = "ToolEvents::custom", a.SELECT_DROPDOWN = "ToolEvents::selectDropdown", a.DRAG_UPDATE = "ToolEvents::dragUpdate", a.ADD_SCENE = "ToolEvents::addScene", a.REFRESH_SCENE = "ToolEvents::refreshScene", a.REMOVE_SCENE = "ToolEvents::removeScene", a.SET_SCENE = "ToolEvents::setScene", a.SET_OBJECT = "ToolEvents::setObject", a.CLEAR_OBJECT = "ToolEvents::clearObject", a.ADD_CAMERA = "ToolEvents::addCamera", a.REMOVE_CAMERA = "ToolEvents::removeCamera", a.ADD_GROUP = "ToolEvents::addGroup", a.REMOVE_GROUP = "ToolEvents::removeGroup", a.ADD_SPLINE = "ToolEvents::addSpline", a.ADD_RENDERER = "ToolEvents::addRenderer", a.UPDATE_RENDERER = "ToolEvents::updateRenderer", a))(b || {});
class y extends E {
name;
canvas = null;
// Canvas or OffscreenCanvas
inputElement = null;
// reference this to receive events
scene = void 0;
scenes = /* @__PURE__ */ new Map();
// scene instances
renderer = void 0;
renderTargets = /* @__PURE__ */ new Map();
renderTargetsResize = /* @__PURE__ */ new Map();
groups = /* @__PURE__ */ new Map();
_listeners = {};
editorUtils;
constructor(e, t = !1, r = !1) {
super("RemoteThree", t, r), this.name = e;
}
setEditorUtils(e) {
this.editorUtils = e;
}
dispose() {
this.scenes.forEach((e) => {
u(e);
}), this.scenes.clear(), this.scene && u(this.scene), this.renderTargets.forEach((e) => {
e.dispose();
}), this.renderTargets.clear(), this.renderer?.dispose();
}
// Event Dispatching (used for editor only)
addEventListener(e, t) {
this._listeners === void 0 && (this._listeners = {});
const r = this._listeners;
r[e] === void 0 && (r[e] = []), r[e].indexOf(t) === -1 && r[e].push(t);
}
hasEventListener(e, t) {
const r = this._listeners;
return r === void 0 ? !1 : r[e] !== void 0 && r[e].indexOf(t) !== -1;
}
removeEventListener(e, t) {
const r = this._listeners;
if (r === void 0) return;
const s = r[e];
if (s !== void 0) {
const d = s.indexOf(t);
d !== -1 && s.splice(d, 1);
}
}
dispatchEvent(e) {
const t = this._listeners;
if (t === void 0) return;
const r = t[e.type];
if (r !== void 0) {
const s = { ...e, target: this }, d = r.slice(0);
for (let i = 0, n = d.length; i < n; i++)
d[i].call(this, s);
}
}
// Objects
/**
* Searches ALL active scenes
*/
getObjectByUUID(e) {
const t = e.split(".")[0], r = this.scenes.get(t);
if (r !== void 0)
return r.getObjectByProperty("uuid", e);
}
getObject(e) {
if (!this.debug) return;
this.renderer !== void 0 && (h.renderer = this.renderer);
const t = this.getObjectByUUID(e);
t && this.setObject(t);
}
setObject(e) {
if (!this.editorUtils) return;
this.renderer !== void 0 && (h.renderer = this.renderer);
const t = this.editorUtils.stripObject(e);
this.dispatchEvent({ type: "ToolEvents::setObject", value: t });
}
requestMethod(e, t, r, s) {
const d = this.getObjectByUUID(e);
if (d)
try {
if (s !== void 0) {
const i = this.editorUtils?.getSubItem(d, s);
i !== void 0 && i[t](r);
} else
d[t](r);
} catch (i) {
console.log("Hermes - Error requesting method:", e, t, r), console.log(i);
}
}
updateObject(e, t, r) {
this.send({
event: "updateObject",
target: "app",
// used by both
data: {
uuid: e,
key: t,
value: r
}
});
}
createTexture(e, t, r) {
this.send({
event: "createTexture",
target: "app",
// used by both
data: {
uuid: e,
key: t,
value: r
}
});
}
onUpdateObject(e, t, r) {
const s = this.getObjectByUUID(e);
s && this.editorUtils?.setItemProps(s, t, r);
}
onCreateTexture(e, t, r) {
if (!this.editorUtils) return;
const s = this.getObjectByUUID(e);
if (s) {
const d = (i) => {
const n = t.split(".");
switch (n.length) {
case 1:
s[n[0]] = i;
break;
case 2:
s[n[0]][n[1]] = i;
break;
case 3:
s[n[0]][n[1]][n[2]] = i;
break;
case 4:
s[n[0]][n[1]][n[2]][n[3]] = i;
break;
case 5:
s[n[0]][n[1]][n[2]][n[3]][n[4]] = i;
break;
}
s.material.needsUpdate = !0;
};
r.src.length > 0 ? this.editorUtils.textureFromSrc(r.src).then((i) => {
i.offset.set(r.offset[0], r.offset[1]), i.repeat.set(r.repeat[0], r.repeat[1]), d(i);
}) : d(null);
}
}
// Groups
addGroup(e) {
this.groups.get(e.title) === void 0 && (this.groups.set(e.title, {
title: e.title,
onUpdate: e.onUpdate
}), this.send({
event: "addGroup",
target: "editor",
data: JSON.stringify(e)
}));
}
removeGroup(e) {
this.groups.get(e) !== void 0 && (this.groups.delete(e), this.send({
event: "removeGroup",
target: "editor",
data: e
}));
}
updateGroup(e, t, r) {
this.send({
event: "updateGroup",
target: "app",
data: JSON.stringify({ group: e, prop: t, value: r })
});
}
addSplineCurve(e) {
setTimeout(() => {
this.send({
event: "addSpline",
target: "editor",
data: JSON.stringify(e.toJSON())
});
}, 1);
}
addSplineObject(e) {
setTimeout(() => {
this.send({
event: "addSpline",
target: "editor",
data: JSON.stringify(e)
});
}, 1);
}
// Renderer
setRenderer(e, t = null) {
if (this.renderer = e, this.canvas = e.domElement, this.inputElement = t !== null ? t : this.canvas, !this.debug) return;
const r = `#${e.getClearColor(new l()).getHexString()}`;
this.send({
event: "addRenderer",
target: "editor",
data: {
autoClearColor: e.autoClearColor,
outputColorSpace: e.outputColorSpace,
clearColor: r,
clearAlpha: e.getClearAlpha(),
colorManagement: p.enabled,
toneMapping: e.toneMapping,
toneMappingExposure: e.toneMappingExposure,
type: e.isWebGLRenderer ? "WebGLRenderer" : "WebGPURenderer"
}
});
}
updateRenderer(e) {
this.send({
event: "updateRenderer",
target: "app",
data: e
});
}
// Scenes
addScene(e) {
if (e === void 0 || (this.scenes.set(e.name, e), !this.debug || !this.editorUtils)) return;
c(), o(e);
const t = this.editorUtils.stripScene(e);
this.send({
event: "addScene",
target: "editor",
data: t
});
}
refreshScene(e) {
if (!this.debug || !this.editorUtils) return;
const t = this.scenes.get(e);
if (t !== void 0) {
const r = this.editorUtils.stripScene(t);
this.send({
event: "refreshScene",
target: "app",
data: r
});
}
}
removeScene(e) {
if (e === void 0 || (this.scenes.delete(e.name), !this.debug || !this.editorUtils)) return;
const t = this.editorUtils.stripScene(e);
this.send({
event: "removeScene",
target: "editor",
data: t
});
}
removeAllScenes() {
this.scenes.forEach((e) => this.removeScene(e));
}
getScene(e) {
let t = null;
return this.scene !== void 0 && this.scene.uuid.search(e) > -1 ? this.scene : (this.scenes.forEach((r, s) => {
e.search(s) > -1 && (t = r);
}), t);
}
setScene(e) {
if (e === void 0 || (this.scene = e, !this.debug || !this.editorUtils)) return;
this.renderer !== void 0 && (h.renderer = this.renderer), c(), o(e);
const t = this.editorUtils.stripScene(e);
this.send({
event: "setScene",
target: "editor",
data: t
});
}
requestSize() {
this.send({
event: "requestSize",
target: "app"
});
}
requestRenderer() {
this.send({
event: "requestRenderer",
target: "app"
});
}
requestScene() {
this.send({
event: "requestScene",
target: "app"
});
}
// Cameras
addCamera(e) {
if (!this.debug || !this.editorUtils) return;
const t = this.editorUtils.stripObject(e);
this.send({
event: "addCamera",
target: "editor",
data: t
});
}
removeCamera(e) {
if (!this.debug || !this.editorUtils) return;
const t = this.editorUtils.stripObject(e);
this.send({
event: "removeCamera",
target: "editor",
data: t
});
}
handleApp(e) {
switch (e.event) {
case "refreshScene":
this.editorUtils && this.send({
event: "refreshScene",
target: "editor",
data: this.editorUtils.stripScene(this.scenes.get(e.data.name))
});
break;
case "updateRenderer":
this.renderer && (this.renderer.autoClearColor = e.data.autoClearColor, this.renderer.outputColorSpace = e.data.outputColorSpace, this.renderer.setClearColor(e.data.clearColor, e.data.clearAlpha), this.renderer.toneMapping = e.data.toneMapping, this.renderer.toneMappingExposure = e.data.toneMappingExposure, p.enabled = e.data.colorManagement);
break;
case "requestRenderer":
if (this.renderer !== void 0) {
const t = `#${this.renderer.getClearColor(new l()).getHexString()}`;
this.send({
event: "addRenderer",
target: "editor",
data: {
autoClearColor: this.renderer.autoClearColor,
outputColorSpace: this.renderer.outputColorSpace,
clearColor: t,
clearAlpha: this.renderer.getClearAlpha(),
colorManagement: p.enabled,
toneMapping: this.renderer.toneMapping,
toneMappingExposure: this.renderer.toneMappingExposure,
type: this.renderer.isWebGLRenderer ? "WebGLRenderer" : "WebGPURenderer"
}
});
}
break;
case "requestScene":
this.editorUtils && (this.scenes.forEach((t) => {
c(), o(t), this.send({
event: "addScene",
target: "editor",
data: this.editorUtils.stripScene(t)
});
}), this.scene !== void 0 && (this.renderer !== void 0 && (h.renderer = this.renderer), c(), o(this.scene), this.send({
event: "setScene",
target: "editor",
data: this.editorUtils.stripScene(this.scene)
})));
break;
}
if (e.event === "updateGroup") {
const t = JSON.parse(e.data);
this.groups.get(t.group)?.onUpdate(t.prop, t.value);
}
}
handleEditor(e) {
switch (e.event) {
case "addScene":
this.dispatchEvent({ type: "ToolEvents::addScene", value: e.data });
break;
case "refreshScene":
this.dispatchEvent({ type: "ToolEvents::refreshScene", value: e.data });
break;
case "removeScene":
this.dispatchEvent({ type: "ToolEvents::removeScene", value: e.data });
break;
case "setScene":
this.dispatchEvent({ type: "ToolEvents::setScene", value: e.data });
break;
case "addCamera":
this.dispatchEvent({ type: "ToolEvents::addCamera", value: e.data });
break;
case "removeCamera":
this.dispatchEvent({ type: "ToolEvents::removeCamera", value: e.data });
break;
case "addGroup":
this.dispatchEvent({ type: "ToolEvents::addGroup", value: e.data });
break;
case "removeGroup":
this.dispatchEvent({ type: "ToolEvents::removeGroup", value: e.data });
break;
case "addSpline":
this.dispatchEvent({ type: "ToolEvents::addSpline", value: e.data });
break;
case "addRenderer":
this.dispatchEvent({ type: "ToolEvents::addRenderer", value: e.data });
}
}
messageHandler(e) {
const t = e.data;
if (t.event === "updateObject") {
this.onUpdateObject(t.data.uuid, t.data.key, t.data.value);
return;
} else if (t.event === "createTexture") {
this.onCreateTexture(t.data.uuid, t.data.key, t.data.value);
return;
} else if (t.event === "requestSize") {
t.target === "app" ? this.send({
event: "requestSize",
target: "editor",
data: {
width: this.width,
height: this.height
}
}) : this.scenes.forEach((r) => {
r.resize !== void 0 && r.resize(t.data.width, t.data.height);
});
return;
}
t.target === "app" ? this.handleApp(t) : this.handleEditor(t);
}
// Renderer
addRT(e, t = !0, r) {
if (!this.renderer) return;
let s;
this.renderer instanceof g ? s = new v(32, 32, r) : s = new f(32, 32, r), s.texture.name = e, this.renderTargets.set(e, s), this.renderTargetsResize.set(e, t);
}
removeRT(e) {
this.renderTargets.delete(e), this.renderTargetsResize.delete(e);
}
resize(e, t) {
const r = this.dpr;
this.renderTargets.forEach((d, i) => {
this.renderTargetsResize.get(i) && d.setSize(e * r, t * r);
});
const s = !(this.renderer?.domElement instanceof OffscreenCanvas);
this.renderer?.setSize(e, t, s);
}
set dpr(e) {
this.renderer?.setPixelRatio(S(1, 2, e));
}
get dpr() {
return this.renderer !== void 0 ? this.renderer?.getPixelRatio() : 1;
}
get width() {
return this.renderer !== void 0 ? this.renderer.domElement.width / this.dpr : 0;
}
get height() {
return this.renderer !== void 0 ? this.renderer.domElement.height / this.dpr : 0;
}
}
export {
b as ToolEvents,
y as default
};