Spaces:
Running
Running
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 }; | |