34 lines
1.4 KiB
TypeScript
34 lines
1.4 KiB
TypeScript
import type { ScreenRect } from "./types";
|
|
|
|
export type ScreenPoint = { x: number; y: number };
|
|
|
|
/** Returns corners in northwest, northeast, southwest, southeast order. */
|
|
export function rotatedRectCorners(rect: ScreenRect, rotation: number): [ScreenPoint, ScreenPoint, ScreenPoint, ScreenPoint] {
|
|
if (!Number.isFinite(rotation)) rotation = 0;
|
|
const center = { x: rect.x + rect.w / 2, y: rect.y + rect.h / 2 };
|
|
const cosine = Math.cos(rotation);
|
|
const sine = Math.sin(rotation);
|
|
const rotate = (point: ScreenPoint): ScreenPoint => {
|
|
const x = point.x - center.x;
|
|
const y = point.y - center.y;
|
|
return { x: center.x + x * cosine - y * sine, y: center.y + x * sine + y * cosine };
|
|
};
|
|
return [
|
|
rotate({ x: rect.x, y: rect.y }),
|
|
rotate({ x: rect.x + rect.w, y: rect.y }),
|
|
rotate({ x: rect.x, y: rect.y + rect.h }),
|
|
rotate({ x: rect.x + rect.w, y: rect.y + rect.h }),
|
|
];
|
|
}
|
|
|
|
/** Axis-aligned screen bounds used to constrain WebGL scissoring around a rotated quad. */
|
|
export function rotatedRectBounds(rect: ScreenRect, rotation: number): ScreenRect {
|
|
if (rotation === 0) return rect;
|
|
const points = rotatedRectCorners(rect, rotation);
|
|
const xs = points.map((point) => point.x);
|
|
const ys = points.map((point) => point.y);
|
|
const x = Math.min(...xs);
|
|
const y = Math.min(...ys);
|
|
return { x, y, w: Math.max(...xs) - x, h: Math.max(...ys) - y };
|
|
}
|