@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
280 lines • 26.1 kB
JavaScript
import { tgdActionCreateCameraInterpolation, tgdEasingFunctionOutQuad, } from "./../../utils/index.js";
import { tgdCalcClamp } from "./../../utils/math.js";
import { TgdEvent } from "./../../event/index.js";
import { TgdMat3, TgdQuat, TgdVec3 } from "./../../math/index.js";
export class TgdControllerCameraOrbit {
constructor(context, { geo, minZoom = 1e-3, maxZoom = Infinity, speedZoom = 1, speedOrbit = 1, speedPanning = 1, inertiaZoom = 0, inertiaOrbit = 0, inertiaPanning = 0, fixedTarget = false, debug = false, onZoomRequest = alwaysTrue, } = {}) {
this.context = context;
this.id = `TgdControllerCameraOrbit-${TgdControllerCameraOrbit.counter++}`;
this.eventChange = new TgdEvent();
this.minZoom = 1e-3;
this.maxZoom = Infinity;
this.speedZoom = 1;
this.speedOrbit = 1;
this.speedPanning = 1;
this.inertiaZoom = 0;
this.inertiaOrbit = 0;
this.inertiaPanning = 0;
/**
* If `true`, pannig will only act on `camera.shift`,
* not on `camera.target`.
*/
this.fixedTarget = false;
/**
* The camera will only move if `enabled === true`.
*/
this._enabled = true;
this.animOrbit = null;
/**
* It can be usefull to disable to orbit controller for some time
* because an animation is going on on the camera, for instance.
*/
this.disabledUntil = 0;
this.tmpQuat = new TgdQuat();
this.handleMove = (event) => {
if (!this.enabled || this.animOrbit)
return;
this.actualMove(event);
};
this.actualMove = (event) => {
const dt = event.current.t - event.previous.t;
if (dt <= 0)
return;
const { context } = this;
const { keyboard } = context.inputs;
if (event.altKey || event.current.fingersCount === 2)
return this.handlePan(event);
if (this.geo) {
const speed = keyboard.isDown("Shift") ? 0.2 : 2;
const lngDelta = keyboard.isDown("x")
? 0
: speed * (event.previous.x - event.current.x);
const latDelta = keyboard.isDown("y")
? 0
: speed * (event.previous.y - event.current.y);
const lng = this.geo.lng + lngDelta;
const lat = this.geo.lat + latDelta;
this.orbitGeo(lat, lng);
return;
}
if (keyboard.isDown("z"))
return this.handleRotateAroundZ(event);
this.orbit(event.current.x - event.previous.x, event.current.y - event.previous.y, event.shiftKey);
};
this.handleMoveStart = () => {
if (!this.enabled)
return;
const { animOrbit, context } = this;
if (animOrbit) {
context.animCancel(animOrbit);
this.animOrbit = null;
}
};
this.handleMoveEnd = (event) => {
if (!this.enabled)
return;
const { context, inertiaOrbit } = this;
if (inertiaOrbit > 0) {
const inverseDeltaTime = 1 / (event.current.t - event.previous.t);
const speedX = inverseDeltaTime * (event.current.x - event.previous.x);
const speedY = inverseDeltaTime * (event.current.y - event.previous.y);
const currentEvent = structuredClone(event);
currentEvent.current.t = Date.now();
this.animOrbit = {
duration: inertiaOrbit * 1e-3,
action: alpha => {
currentEvent.previous.t = currentEvent.current.t;
currentEvent.previous.x = currentEvent.current.x;
currentEvent.previous.y = currentEvent.current.y;
currentEvent.previous.fingersCount =
currentEvent.current.fingersCount;
currentEvent.current.t = Date.now();
const deltaTime = currentEvent.current.t - currentEvent.previous.t;
const strength = 1 - alpha;
const factor = strength * deltaTime;
currentEvent.current.x += factor * speedX;
currentEvent.current.y += factor * speedY;
this.actualMove(currentEvent);
},
easingFunction: tgdEasingFunctionOutQuad,
};
context.animSchedule(this.animOrbit);
}
};
this.handleZoom = (event) => {
if (!this.enabled ||
this.speedZoom === 0 ||
!this.onZoomRequest({
altKey: event.altKey,
ctrlKey: event.ctrlKey,
metaKey: event.metaKey,
shiftKey: event.shiftKey,
x: event.current.x,
y: event.current.y,
}))
return;
const { context } = this;
const { camera } = context;
let speed = 0.1 * this.speedZoom;
if (this.context.inputs.keyboard.isDown("Shift"))
speed *= 0.1;
const dz = -event.direction * speed;
camera.transfo.distance = Math.max(0, camera.transfo.distance + dz);
// camera.zoom = tgdCalcClamp(
// camera.zoom * (1 + dz),
// this.minZoom,
// this.maxZoom
// )
event.preventDefault();
this.fireZoomChange();
};
this.geo = undefined;
if (geo) {
this.geo = Object.assign({ lat: 0, lng: 0, minLat: -Math.PI / 2, maxLat: +Math.PI / 2, minLng: -Number.MAX_VALUE, maxLng: +Number.MAX_VALUE }, geo);
}
this.cameraInitialState = context.camera.getCurrentState();
const { inputs } = context;
inputs.pointer.eventMoveStart.addListener(this.handleMoveStart);
inputs.pointer.eventMoveEnd.addListener(this.handleMoveEnd);
inputs.pointer.eventMove.addListener(this.handleMove);
inputs.pointer.eventZoom.addListener(this.handleZoom);
this.speedOrbit = speedOrbit;
this.speedZoom = speedZoom;
this.speedPanning = speedPanning;
this.inertiaOrbit = inertiaOrbit;
this.inertiaZoom = inertiaZoom;
this.inertiaPanning = inertiaPanning;
this.fixedTarget = fixedTarget;
this.minZoom = minZoom;
this.maxZoom = maxZoom;
this.onZoomRequest = onZoomRequest;
if (this.geo)
this.orbitGeo(this.geo.lat, this.geo.lng);
globalThis.setTimeout(() => context.paint());
if (debug) {
context.inputs.keyboard.eventKeyPress.addListener(event => {
if (event.key === "?") {
console.log(this.context.camera.toCode());
}
});
}
}
get enabled() {
return this.context.time > this.disabledUntil && this._enabled;
}
set enabled(value) {
this._enabled = value;
}
reset(animDuration, easingFunction) {
const { context } = this;
this.disableForSomeTime(animDuration);
context.animSchedule({
action: tgdActionCreateCameraInterpolation(context.camera, this.cameraInitialState),
duration: animDuration,
easingFunction,
});
}
disableForSomeTime(delayInMsec) {
this.disabledUntil = Math.max(this.disabledUntil, this.context.time + delayInMsec);
}
detach() {
const { inputs } = this.context;
inputs.pointer.eventMove.removeListener(this.handleMove);
inputs.pointer.eventZoom.removeListener(this.handleZoom);
}
orbit(deltaX, deltaY, slowDown) {
const { context } = this;
const { camera } = context;
const { keyboard } = context.inputs;
const speed = 3 * (slowDown ? 0.1 : 1) * this.speedOrbit;
const dx = deltaX * speed;
const dy = deltaY * speed;
if (!keyboard.isDown("x"))
camera.transfo.orbitAroundY(dx);
if (!keyboard.isDown("y"))
camera.transfo.orbitAroundX(-dy);
this.fireOrbitChange();
}
/**
* Set the camera orientation from latitude/longitude
* @param lat Expressed in radians
* @param lng Expressed in radians
*/
orbitGeo(lat, lng) {
const { geo } = this;
if (!geo)
return;
lat = tgdCalcClamp(lat, geo.minLat, geo.maxLat);
geo.lat = lat;
lng = tgdCalcClamp(lng, geo.minLng, geo.maxLng);
geo.lng = lng;
const { orientation } = this.cameraInitialState;
const vecZ = makeGeoVec3(lat, lng);
const vecY = makeGeoVec3(lat + Math.PI / 2, lng);
const vecX = new TgdVec3(vecY).cross(vecZ);
const mat = new TgdMat3();
orientation.toMatrix(mat);
const final = new TgdMat3(vecX, vecY, vecZ);
final.multiply(mat);
this.tmpQuat.fromMatrix(final);
this.context.camera.transfo.orientation = this.tmpQuat;
this.fireOrbitChange();
}
handlePan(event) {
const { fixedTarget, speedPanning, context } = this;
const { camera } = context;
const inverseZoom = 1 / camera.zoom;
const panSpeed = 0.5 * speedPanning * inverseZoom;
const dx = (event.current.x - event.previous.x) *
panSpeed *
camera.spaceWidthAtTarget;
const dy = (event.current.y - event.previous.y) *
panSpeed *
camera.spaceHeightAtTarget;
if (fixedTarget) {
// camera.moveShift(-dx, -dy, 0)
}
else {
camera.transfo.moveAlongAxes(-dx, -dy, 0);
}
this.fireOrbitChange();
return;
}
handleRotateAroundZ(event) {
const { camera } = this.context;
const x1 = event.previous.x;
const y1 = event.previous.y;
if (Math.abs(x1) + Math.abs(y1) === 0)
return;
const x2 = event.current.x;
const y2 = event.current.y;
if (Math.abs(x2) + Math.abs(y2) === 0)
return;
const x = x1 * x2 + y1 * y2;
const y = x1 * y2 - y1 * x2;
const ang = Math.atan2(y, x) * this.speedOrbit;
camera.transfo.orbitAroundZ(ang);
this.fireOrbitChange();
return;
}
fireOrbitChange() {
this.context.paint();
this.eventChange.dispatch(this.context.camera);
}
fireZoomChange() {
this.context.paint();
}
}
TgdControllerCameraOrbit.counter = 0;
/**
* Default function for `onZoomRequest`.
*/
const alwaysTrue = () => true;
function makeGeoVec3(lat, lng) {
const radius = Math.cos(lat);
const y = Math.sin(lat);
const z = radius * Math.cos(lng);
const x = radius * Math.sin(lng);
return new TgdVec3(x, y, z);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JiaXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29udHJvbGxlci9jYW1lcmEvb3JiaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUNILGtDQUFrQyxFQUNsQyx3QkFBd0IsR0FDM0IsTUFBTSxZQUFZLENBQUE7QUFDbkIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBTTlDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFFckMsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBZ0ZyRCxNQUFNLE9BQU8sd0JBQXdCO0lBdURqQyxZQUNxQixPQU9oQixFQUNELEVBQ0ksR0FBRyxFQUNILE9BQU8sR0FBRyxJQUFJLEVBQ2QsT0FBTyxHQUFHLFFBQVEsRUFDbEIsU0FBUyxHQUFHLENBQUMsRUFDYixVQUFVLEdBQUcsQ0FBQyxFQUNkLFlBQVksR0FBRyxDQUFDLEVBQ2hCLFdBQVcsR0FBRyxDQUFDLEVBQ2YsWUFBWSxHQUFHLENBQUMsRUFDaEIsY0FBYyxHQUFHLENBQUMsRUFDbEIsV0FBVyxHQUFHLEtBQUssRUFDbkIsS0FBSyxHQUFHLEtBQUssRUFDYixhQUFhLEdBQUcsVUFBVSxNQUNnQixFQUFFO1FBckIvQixZQUFPLEdBQVAsT0FBTyxDQU92QjtRQTVEVyxPQUFFLEdBQUcsNEJBQTRCLHdCQUF3QixDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUE7UUFDckUsZ0JBQVcsR0FBRyxJQUFJLFFBQVEsRUFBYSxDQUFBO1FBQ2hELFlBQU8sR0FBRyxJQUFJLENBQUE7UUFDZCxZQUFPLEdBQUcsUUFBUSxDQUFBO1FBQ2xCLGNBQVMsR0FBRyxDQUFDLENBQUE7UUFDYixlQUFVLEdBQUcsQ0FBQyxDQUFBO1FBQ2QsaUJBQVksR0FBRyxDQUFDLENBQUE7UUFDaEIsZ0JBQVcsR0FBRyxDQUFDLENBQUE7UUFDZixp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