UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

189 lines 15.1 kB
/* eslint-disable unicorn/prevent-abbreviations */ import { TgdCameraPerspective } from "./../../camera/index.js"; import { TgdContext } from "./../../context/index.js"; import { TgdControllerCameraOrbit } from "./../../controller/index.js"; import { TgdEvent } from "./../../event/index.js"; import { TgdQuat, TgdMat3, TgdVec3 } from "./../../math/index.js"; import { TgdPainterClear, TgdPainterDepth, TgdPainterLogic } from "./../../painter/index.js"; import { TipsPainter } from "./painter/tips.js"; /** * The Gizmo displays the orientation of an attached camera. * You can click one of the axis to force the camera to face it. */ export class TgdCanvasGizmo { constructor(options = {}) { this.options = options; /** * The user clicked a tip, so we dispatch the target orientation. */ this.eventTipClick = new TgdEvent(); this._canvas = null; this.context = null; this.contextExternal = null; this.cameraInternal = new TgdCameraPerspective({ fovy: Math.PI / 3, near: 0.01, far: 10, transfo: { distance: 2.7 }, }); this.orbiter = null; this.tipsPainter = null; this.handleExternalPaint = () => { this.context?.paint(); }; this.handleInternalToExternal = (internalCamera) => { const { contextExternal } = this; if (contextExternal?.camera) { contextExternal.camera.transfo.orientation = internalCamera.transfo.orientation; contextExternal.paint(); } }; this.handleTap = (event) => { const camera = this.context?.camera; if (!camera) return; const { origin, direction } = camera.castRay(event.x, event.y); const maxDistance = 1; let bestDistance = maxDistance; let bestTip = TIPS[0]; for (const tip of TIPS) { const distance = tip.distanceToLineSquared(origin, direction); if (distance < bestDistance) { bestDistance = distance; bestTip = tip; } } if (bestDistance < maxDistance) { const axisX = new TgdVec3(); const axisY = new TgdVec3(); const axisZ = bestTip; axisX.from(this.findAxisX()); if (axisX.isClose(axisZ)) { axisY.from(this.findAxisY()); axisX.from(axisY).cross(axisZ); } else { axisY.from(axisZ).cross(axisX); } const quat = new TgdQuat().fromAxes(axisX, axisY, axisZ); if (quat.isEqual(camera.transfo.orientation)) { quat.rotateAroundY(Math.PI); } this.eventTipClick.dispatch({ from: camera.transfo.orientation, to: quat, }); } }; if (options.canvas) this.canvas = options.canvas; } /** * Attach the camera we want to track and control. */ attachContext(context) { this.detach(); this.contextExternal = context; this.attach(); } detach() { if (!this.contextExternal) return; this.contextExternal.eventPaint.removeListener(this.handleExternalPaint); this.contextExternal = null; } attach() { this.contextExternal?.eventPaint.addListener(this.handleExternalPaint); this.context?.paint(); } get canvas() { return this._canvas; } set canvas(canvas) { if (canvas === this._canvas) return; this._canvas = canvas; if (this.context) { this.context.inputs.pointer.eventTap.removeListener(this.handleTap); this.context.delete(); this.context = null; const { orbiter } = this; if (orbiter) { orbiter.detach(); orbiter.eventChange.removeListener(this.handleInternalToExternal); } } this.tipsPainter?.delete(); if (!canvas) return; const context = new TgdContext(canvas, { alpha: true, depth: true, antialias: true, name: "GizmoCanvas", ...this.options, }); context.inputs.pointer.eventTap.addListener(this.handleTap); this.context = context; context.camera = this.cameraInternal; this.orbiter = new TgdControllerCameraOrbit(context, { speedPanning: 0, speedZoom: 0, }); this.orbiter.eventChange.addListener(this.handleInternalToExternal); const painter = new TipsPainter(context); this.tipsPainter = painter; context.add(new TgdPainterLogic(() => { const srcTransfo = this.contextExternal?.camera.transfo; if (!srcTransfo) return; const dstTransfo = this.context?.camera.transfo; if (!dstTransfo) return; dstTransfo.orientation = srcTransfo.orientation; }), new TgdPainterClear(context, { color: [0, 0, 0, 0], depth: 1, }), new TgdPainterDepth(context, { enabled: true }), painter); context.paint(); } findAxisX() { let bestScore = 0; let bestTip = TIPS[0]; const vec = new TgdVec3(); const mat = new TgdMat3(); mat.fromQuat(this.cameraInternal.transfo.orientation).transpose(); for (const tip of TIPS) { vec.from(tip).applyMatrix(mat); if (vec.x > bestScore) { bestScore = vec.x; bestTip = tip; } } return bestTip; } findAxisY() { let bestScore = 0; let bestTip = TIPS[0]; const vec = new TgdVec3(); const mat = new TgdMat3(); mat.fromQuat(this.cameraInternal.transfo.orientation).transpose(); for (const tip of TIPS) { vec.from(tip).applyMatrix(mat); if (vec.y > bestScore) { bestScore = vec.y; bestTip = tip; } } return bestTip; } } const TIPS = [ new TgdVec3(1, 0, 0), new TgdVec3(0, 1, 0), new TgdVec3(0, 0, 1), new TgdVec3(-1, 0, 0), new TgdVec3(0, -1, 0), new TgdVec3(0, 0, -1), ]; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l6bW8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY2FudmFzL2dpem1vL2dpem1vLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGtEQUFrRDtBQUNsRCxPQUFPLEVBQWEsb0JBQW9CLEVBQUUsTUFBTSxhQUFhLENBQUE7QUFDN0QsT0FBTyxFQUFFLFVBQVUsRUFBcUIsTUFBTSxjQUFjLENBQUE7QUFDNUQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0saUJBQWlCLENBQUE7QUFDMUQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUNyQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDckQsT0FBTyxFQUFFLGVBQWUsRUFBRSxlQUFlLEVBQUUsZUFBZSxFQUFFLE1BQU0sY0FBYyxDQUFBO0FBRWhGLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQU01Qzs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sY0FBYztJQXFCdkIsWUFBNkIsVUFBaUMsRUFBRTtRQUFuQyxZQUFPLEdBQVAsT0FBTyxDQUE0QjtRQXBCaEU7O1dBRUc7UUFDSSxrQkFBYSxHQUFHLElBQUksUUFBUSxFQUcvQixDQUFBO1FBRUksWUFBTyxHQUE2QixJQUFJLENBQUE7UUFDeEMsWUFBTyxHQUFzQixJQUFJLENBQUE7UUFDakMsb0JBQWUsR0FBc0IsSUFBSSxDQUFBO1FBQ2hDLG1CQUFjLEdBQUcsSUFBSSxvQkFBb0IsQ0FBQztZQUN2RCxJQUFJLEVBQUUsSUFBSSxDQUFDLEVBQUUsR0FBRyxDQUFDO1lBQ2pCLElBQUksRUFBRSxJQUFJO1lBQ1YsR0FBRyxFQUFFLEVBQUU7WUFDUCxPQUFPLEVBQUUsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFO1NBQzdCLENBQUMsQ0FBQTtRQUNNLFlBQU8sR0FBb0MsSUFBSSxDQUFBO1FBQy9DLGdCQUFXLEdBQXVCLElB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