import * as SPLAT from "gsplat"; import { InputMode } from "./InputMode"; import { Engine } from "./Engine"; import { ModeManager } from "./ModeManager"; import { SelectionManager } from "./SelectionManager"; import { UndoManager } from "./UndoManager"; import { RotateAction } from "./RotateAction"; class RotateMode implements InputMode { exit: () => void; constructor(engine: Engine) { const splat = SelectionManager.selectedSplat as SPLAT.Splat; const initialMousePosition = engine.mouseManager.currentMousePosition.clone(); const initialRotation = splat.rotation.clone(); let axis: "x" | "y" | "z" | null = null; const handleClick = () => { const action = new RotateAction(splat, initialRotation, splat.rotation); UndoManager.do(action); ModeManager.enterMode("default"); }; const handleCancel = () => { splat.rotation = initialRotation; ModeManager.enterMode("default"); }; const handleMouseMove = () => { const plane = new SPLAT.Plane(engine.camera.forward, splat.position); const initialDirection = engine.camera.screenPointToRay(initialMousePosition.x, initialMousePosition.y); const newDirection = engine.camera.screenPointToRay( engine.mouseManager.currentMousePosition.x, engine.mouseManager.currentMousePosition.y, ); const initialIntersection = plane.intersect(engine.camera.position, initialDirection); const newIntersection = plane.intersect(engine.camera.position, newDirection); if (initialIntersection && newIntersection) { const initialVector = initialIntersection.subtract(splat.position).normalize(); const newVector = newIntersection.subtract(splat.position).normalize(); const cross = initialVector.cross(newVector); const dot = initialVector.dot(newVector); const delta = Math.acos(dot); let rotationAxis = cross.normalize(); const sign = Math.sign(rotationAxis.dot(engine.camera.forward)); switch (axis) { case "x": rotationAxis = new SPLAT.Vector3(1, 0, 0).multiply(sign); break; case "y": rotationAxis = new SPLAT.Vector3(0, 1, 0).multiply(sign); break; case "z": rotationAxis = new SPLAT.Vector3(0, 0, 1).multiply(sign); break; } const rotation = SPLAT.Quaternion.FromAxisAngle(rotationAxis, delta); splat.rotation = rotation.multiply(initialRotation); } }; const handleAxisX = () => { if (axis === "x") { axis = null; } else { axis = "x"; } handleMouseMove(); }; const handleAxisY = () => { if (axis === "y") { axis = null; } else { axis = "y"; } handleMouseMove(); }; const handleAxisZ = () => { if (axis === "z") { axis = null; } else { axis = "z"; } handleMouseMove(); }; engine.mouseManager.registerMouse("click", handleClick); engine.mouseManager.registerMouse("contextmenu", handleCancel); engine.mouseManager.registerMouse("mousemove", handleMouseMove); engine.keyboardManager.registerKey("Escape", handleCancel); engine.keyboardManager.registerKey("r", handleCancel); engine.keyboardManager.registerKey("x", handleAxisX); engine.keyboardManager.registerKey("y", handleAxisY); engine.keyboardManager.registerKey("z", handleAxisZ); this.exit = () => { engine.mouseManager.unregisterMouse("click"); engine.mouseManager.unregisterMouse("contextmenu"); engine.mouseManager.unregisterMouse("mousemove"); engine.keyboardManager.unregisterKey("Escape"); engine.keyboardManager.unregisterKey("r"); engine.keyboardManager.unregisterKey("x"); engine.keyboardManager.unregisterKey("y"); engine.keyboardManager.unregisterKey("z"); }; } } export { RotateMode };