UNPKG

@shopware-ag/dive

Version:

Shopware Spatial Framework

582 lines (581 loc) 18.6 kB
var S = Object.defineProperty; var w = (n, t, e) => t in n ? S(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e; var o = (n, t, e) => w(n, typeof t != "symbol" ? t + "" : t, e); import { EventDispatcher as T, Vector3 as l, Raycaster as P, Vector2 as f, Layers as m } from "three/webgpu"; import "../../chunks/FileTypes-Ck6z0LqE.mjs"; import { P as _, U as d } from "../../chunks/PerspectiveCamera-35cBnxwG.mjs"; import "three/examples/jsm/loaders/HDRLoader.js"; import "three/tsl"; import { f as g, i as h } from "../../chunks/findInterface-DbJ5qzbc.mjs"; import { TransformControls as E } from "three/examples/jsm/controls/TransformControls.js"; import { A as b, a as D, b as y } from "../../chunks/AxisHelperColors-JLBHYQDi.mjs"; class z { constructor() { o(this, "_selected", null); o(this, "_listeners", /* @__PURE__ */ new Set()); } /** * Currently selected object, or null if nothing is selected. */ get selected() { return this._selected; } /** * Select an object. Deselects any previously selected object. * Calls onSelect on the new object and onDeselect on the previous. */ select(t) { var e, s, i; this._selected !== t && (this._selected && ((s = (e = this._selected).onDeselect) == null || s.call(e)), this._selected = t, (i = t.onSelect) == null || i.call(t), this.notifyListeners()); } /** * Deselect the currently selected object. * Calls onDeselect on the object. */ deselect() { var t, e; this._selected && ((e = (t = this._selected).onDeselect) == null || e.call(t), this._selected = null, this.notifyListeners()); } /** * Register a callback to be notified when selection changes. */ onChange(t) { this._listeners.add(t); } /** * Unregister a previously registered callback. */ offChange(t) { this._listeners.delete(t); } /** * Dispose of the selection state and clear all listeners. */ dispose() { this._selected = null, this._listeners.clear(); } notifyListeners() { for (const t of this._listeners) t(this._selected); } } class C { constructor() { o(this, "name", "hover"); o(this, "priority", 20); o(this, "_hovered", null); } /** * Currently hovered object, or null if nothing is hovered. */ get hovered() { return this._hovered; } onActivate() { this._hovered = null; } onDeactivate() { var t, e; this._hovered && ((e = (t = this._hovered).onPointerLeave) == null || e.call(t), this._hovered = null); } onPointerMove(t) { var i, r, a, c, u, p, v; const e = t.modelIntersects[0], s = g( e == null ? void 0 : e.object, "isHoverable" ); if (e && s) { if (!this._hovered) { (i = s.onPointerEnter) == null || i.call(s, e), this._hovered = s; return; } if (this._hovered.uuid !== s.uuid) { (a = (r = this._hovered).onPointerLeave) == null || a.call(r), (c = s.onPointerEnter) == null || c.call(s, e), this._hovered = s; return; } (u = s.onPointerOver) == null || u.call(s, e); return; } this._hovered && ((v = (p = this._hovered).onPointerLeave) == null || v.call(p), this._hovered = null); } } const B = (n) => n.name === "select"; class M { constructor(t) { o(this, "name", "select"); o(this, "priority", 30); o(this, "_selectionState"); this._selectionState = t; } /** * Get the currently selected object. */ get selected() { return this._selectionState.selected; } onActivate() { } onDeactivate() { } onClick(t) { const e = t.modelIntersects[0], s = g( e == null ? void 0 : e.object, "isSelectable" ); if (!e || !s) { this._selectionState.deselect(); return; } const i = this._selectionState.selected; i && i.uuid === s.uuid || this._selectionState.select(s); } /** * Programmatically select an object. */ select(t) { this._selectionState.select(t); } /** * Programmatically deselect the current selection. */ deselect() { this._selectionState.deselect(); } } const Y = (n) => n.name === "transform"; class L extends T { constructor(e, s, i) { super(); o(this, "name", "transform"); o(this, "priority", 5); o(this, "_scene"); o(this, "_controller"); o(this, "_selectionState"); o(this, "_gizmo"); o(this, "_gizmoHelper"); o(this, "_scaleLinked", !1); o(this, "_gizmoVisible", !0); o(this, "_selectionChangeHandler"); this._scene = e, this._controller = s, this._selectionState = i, this._gizmo = this.initGizmo(), this._gizmoHelper = this._gizmo.getHelper(), this._scene.add(this._gizmoHelper), this._selectionChangeHandler = this.onSelectionChange.bind(this); } /** * Get the TransformControls gizmo. */ get gizmo() { return this._gizmo; } /** * Whether a drag operation is currently in progress. */ get isDragging() { return this._gizmo.dragging; } onActivate() { this._selectionState.onChange(this._selectionChangeHandler); const e = this._selectionState.selected; e && this.attachGizmo(e); } onDeactivate() { this._selectionState.offChange(this._selectionChangeHandler), this._gizmo.detach(); } onPointerMove(e) { if (this._gizmo.dragging || e.uiIntersects.length > 0 && e.uiIntersects.some( (i) => this.isGizmoChild(i.object) )) return !0; } /** * Set the gizmo transformation mode. */ setGizmoMode(e) { this._gizmo.mode = e; } /** * Set whether the gizmo is visible. */ setGizmoVisible(e) { this._gizmoVisible = e; const s = this._scene.children.includes(this._gizmoHelper); e && !s ? (this._scene.add(this._gizmoHelper), this._gizmo.getRaycaster().layers.enableAll()) : !e && s && (this._scene.remove(this._gizmoHelper), this._gizmo.getRaycaster().layers.disableAll()); } /** * Set whether scale operations are linked (uniform scaling). */ setGizmoScaleLinked(e) { this._scaleLinked = e; } /** * Dispose of the tool and clean up resources. */ dispose() { this._selectionState.offChange(this._selectionChangeHandler), this._gizmo.detach(), this._scene.remove(this._gizmoHelper), this._gizmo.dispose(); } // ============ Private Methods ============ onSelectionChange(e) { e && h(e, "isMovable") ? this.attachGizmo(e) : this._gizmo.detach(); } attachGizmo(e) { h(e, "isMovable") && (this._gizmo.attach(e), this.setGizmoVisible(e.visible && this._gizmoVisible)); } isGizmoChild(e) { let s = e; for (; s; ) { if (s === this._gizmoHelper) return !0; s = s.parent; } return !1; } initGizmo() { const e = new E( this._controller.object, this._controller.domElement ); return e.mode = "translate", e.getHelper().traverse((i) => { if (!("isMesh" in i)) return; const r = i.material; i.name === "X" && r.color.set(b), i.name === "Y" && r.color.set(D), i.name === "Z" && r.color.set(y), i.name === "XY" && r.color.set(y), i.name === "YZ" && r.color.set(b), i.name === "XZ" && r.color.set(D); }), e.addEventListener("mouseDown", () => { var i, r; this._controller.enabled = !1, h(e.object, "isMovable") && ((r = (i = e.object).onMoveStart) == null || r.call(i)); }), e.addEventListener("objectChange", () => { var i, r; if (h(e.object, "isMovable")) { if ((r = (i = e.object).onMove) == null || r.call(i), this._scaleLinked && e.object) { const a = e.object.scale, c = (a.x + a.y + a.z) / 3; e.object.scale.set(c, c, c); } switch (this.dispatchEvent({ type: "object-change", object: e.object }), e.mode) { case "translate": this.dispatchEvent({ type: "object-position-change", object: e.object }); break; case "rotate": this.dispatchEvent({ type: "object-rotation-change", object: e.object }); break; case "scale": this.dispatchEvent({ type: "object-scale-change", object: e.object }); break; } } }), e.addEventListener("mouseUp", () => { var i, r; this._controller.enabled = !0, h(e.object, "isMovable") && ((r = (i = e.object).onMoveEnd) == null || r.call(i)); }), e; } } const A = 1e-3; class j { constructor(t) { o(this, "name", "drag"); o(this, "priority", 10); o(this, "_controller"); o(this, "_raycaster"); // Drag state o(this, "_dragging", !1); o(this, "_draggable", null); o(this, "_dragStart", new l()); o(this, "_dragCurrent", new l()); o(this, "_dragEnd", new l()); o(this, "_dragDelta", new l()); // Custom raycast targets for drag plane o(this, "_dragRaycastTargets", null); this._controller = t, this._raycaster = new P(); } /** * Whether a drag operation is currently in progress. */ get isDragging() { return this._dragging; } /** * The object currently being dragged, or null. */ get draggable() { return this._draggable; } onActivate() { this.resetDragState(); } onDeactivate() { this._dragging && this._draggable && this.endDrag(), this.resetDragState(); } onPointerDown(t) { var e; t.pointerPrimaryDown && (this._draggable = g( (e = t.intersects[0]) == null ? void 0 : e.object, "isDraggable" ) || null); } onPointerMove(t) { if (t.pointerPrimaryDown && this._draggable && (this._raycaster.setFromCamera(t.pointer, this._controller.object), this._dragging || t.lastPointerDown.distanceTo(t.pointer) > A && this.startDrag(t), this._dragging)) return this.updateDrag(t), !0; } onPointerUp(t) { this._dragging && (this._raycaster.setFromCamera(t.pointer, this._controller.object), this.endDrag()), this._draggable = null; } /** * Set custom objects to raycast against during drag. * Useful for constraining drag to a floor plane. * * @param targets Objects to raycast against, or null to use scene objects */ setDragRaycastTargets(t) { this._dragRaycastTargets = t; } // ============ Private Methods ============ startDrag(t) { var s, i; const e = this.getDragIntersect(t); e && (this._dragStart.copy(e.point), this._dragCurrent.copy(e.point), this._dragEnd.copy(e.point), this._dragDelta.set(0, 0, 0), (i = (s = this._draggable) == null ? void 0 : s.onDragStart) == null || i.call(s, this.createDragEvent()), this._dragging = !0, this._controller.enabled = !1); } updateDrag(t) { var s, i; const e = this.getDragIntersect(t); e && (this._dragCurrent.copy(e.point), this._dragEnd.copy(e.point), this._dragDelta.subVectors(this._dragCurrent, this._dragStart), (i = (s = this._draggable) == null ? void 0 : s.onDrag) == null || i.call(s, this.createDragEvent())); } endDrag() { var e, s; const t = this.createDragEvent(); (s = (e = this._draggable) == null ? void 0 : e.onDragEnd) == null || s.call(e, t), this._dragging = !1, this._controller.enabled = !0, this.resetDragState(); } getDragIntersect(t) { return this._dragRaycastTargets ? this._raycaster.intersectObjects( this._dragRaycastTargets, !0 )[0] || null : t.intersects[0] || null; } createDragEvent() { return { dragStart: this._dragStart.clone(), dragCurrent: this._dragCurrent.clone(), dragEnd: this._dragEnd.clone(), dragDelta: this._dragDelta.clone() }; } resetDragState() { this._dragStart.set(0, 0, 0), this._dragCurrent.set(0, 0, 0), this._dragEnd.set(0, 0, 0), this._dragDelta.set(0, 0, 0); } } const k = 1e-3; class X { constructor(t, e) { o(this, "_scene"); o(this, "_controller"); o(this, "_canvas"); // Tool management o(this, "_tools"); o(this, "_activeTools", /* @__PURE__ */ new Map()); o(this, "_sortedActiveTools", []); // Shared selection state o(this, "_selectionState"); // Raycasting (shared, computed once per event) o(this, "_raycaster"); o(this, "_pointer"); o(this, "_productLayerMask"); o(this, "_uiLayerMask"); // Pointer state o(this, "_pointerPrimaryDown", !1); o(this, "_pointerMiddleDown", !1); o(this, "_pointerSecondaryDown", !1); o(this, "_lastPointerDown"); // Bound event handlers (for cleanup) o(this, "_boundPointerMove"); o(this, "_boundPointerDown"); o(this, "_boundPointerUp"); o(this, "_boundWheel"); this._scene = t, this._controller = e, this._canvas = e.domElement, this._selectionState = new z(), this._raycaster = new P(), this._pointer = new f(), this._lastPointerDown = new f(), this._productLayerMask = new m(), this._productLayerMask.set(Math.log2(_)), this._uiLayerMask = new m(), this._uiLayerMask.set(Math.log2(d)), this._tools = /* @__PURE__ */ new Map([ [ "hover", new C() ], [ "select", new M(this._selectionState) ], [ "transform", new L(t, e, this._selectionState) ], [ "drag", new j(e) ] ]), this._boundPointerMove = this.onPointerMove.bind(this), this._boundPointerDown = this.onPointerDown.bind(this), this._boundPointerUp = this.onPointerUp.bind(this), this._boundWheel = this.onWheel.bind(this), this._canvas.addEventListener("pointermove", this._boundPointerMove), this._canvas.addEventListener("pointerdown", this._boundPointerDown), this._canvas.addEventListener("pointerup", this._boundPointerUp), this._canvas.addEventListener("wheel", this._boundWheel); } get selectionState() { return this._selectionState; } /** * Enable a tool by type. */ enableTool(t) { var s; const e = this._tools.get(t); e && (this._activeTools.has(t) || (this._activeTools.set(t, e), this.updateSortedTools(), (s = e.onActivate) == null || s.call(e))); } /** * Disable an active tool by type. */ disableTool(t) { var s; const e = this._activeTools.get(t); e && ((s = e.onDeactivate) == null || s.call(e), this._activeTools.delete(t), this.updateSortedTools()); } /** * Check if a tool is currently enabled. */ isToolEnabled(t) { return this._activeTools.has(t); } /** * Get a tool by type. */ getTool(t) { return this._tools.get(t); } /** * Get all currently active tools. */ getActiveTools() { return [...this._sortedActiveTools]; } /** * Dispose of the toolbox and clean up resources. */ dispose() { var t; for (const e of this._activeTools.values()) (t = e.onDeactivate) == null || t.call(e); this._activeTools.clear(), this._tools.clear(), this._sortedActiveTools = [], this._canvas.removeEventListener("pointermove", this._boundPointerMove), this._canvas.removeEventListener("pointerdown", this._boundPointerDown), this._canvas.removeEventListener("pointerup", this._boundPointerUp), this._canvas.removeEventListener("wheel", this._boundWheel), this._selectionState.dispose(); } // ============ Event Handlers ============ onPointerMove(t) { var s; this.updatePointer(t); const e = this.createPointerContext(t); for (const i of this._sortedActiveTools) if ((s = i.onPointerMove) == null ? void 0 : s.call(i, e)) break; } onPointerDown(t) { var s; this.updatePointerState(t, !0), this.updatePointer(t), this._lastPointerDown.copy(this._pointer); const e = this.createPointerContext(t); for (const i of this._sortedActiveTools) if ((s = i.onPointerDown) == null ? void 0 : s.call(i, e)) break; } onPointerUp(t) { var i, r; this.updatePointer(t); const e = this.createPointerContext(t), s = !this.pointerWasDragged(); for (const a of this._sortedActiveTools) if ((i = a.onPointerUp) == null ? void 0 : i.call(a, e)) break; if (s) { for (const a of this._sortedActiveTools) if ((r = a.onClick) == null ? void 0 : r.call(a, e)) break; } this.updatePointerState(t, !1); } onWheel(t) { var s; const e = this.createWheelContext(t); for (const i of this._sortedActiveTools) if ((s = i.onWheel) == null ? void 0 : s.call(i, e)) break; } // ============ Context Creation ============ createPointerContext(t) { const e = this.raycast(); return { event: t, pointer: this._pointer.clone(), intersects: e, modelIntersects: this.filterIntersectsByLayer( e, _ ), uiIntersects: this.filterIntersectsByLayer( e, d ), pointerPrimaryDown: this._pointerPrimaryDown, pointerMiddleDown: this._pointerMiddleDown, pointerSecondaryDown: this._pointerSecondaryDown, lastPointerDown: this._lastPointerDown.clone() }; } createWheelContext(t) { const e = this.raycast(); return { event: t, pointer: this._pointer.clone(), intersects: e, modelIntersects: this.filterIntersectsByLayer( e, _ ), uiIntersects: this.filterIntersectsByLayer( e, d ) }; } // ============ Helper Methods ============ updatePointer(t) { this._pointer.x = t.offsetX / this._canvas.clientWidth * 2 - 1, this._pointer.y = -(t.offsetY / this._canvas.clientHeight) * 2 + 1, this._raycaster.setFromCamera(this._pointer, this._controller.object); } updatePointerState(t, e) { switch (t.button) { case 0: this._pointerPrimaryDown = e; break; case 1: this._pointerMiddleDown = e; break; case 2: this._pointerSecondaryDown = e; break; } } raycast() { this._raycaster.layers.mask = _ | d; const t = this._scene.children.filter( (e) => e.visible && "isMesh" in e && e.isMesh ); return this._raycaster.intersectObjects(t, !0); } filterIntersectsByLayer(t, e) { return t.filter( (s) => (s.object.layers.mask & e) !== 0 ); } updateSortedTools() { this._sortedActiveTools = [...this._activeTools.values()].sort( (t, e) => t.priority - e.priority ); } pointerWasDragged() { return this._lastPointerDown.distanceTo(this._pointer) > k; } } export { M as DIVESelectTool, L as DIVETransformTool, j as DragTool, C as HoverTool, M as SelectTool, z as SelectionState, X as Toolbox, L as TransformTool, B as isSelectTool, Y as isTransformTool };