fix: minor stuff

This commit is contained in:
Dan Finch 2026-08-04 11:39:39 +02:00
parent e0585db0e0
commit f86b4ada13
5 changed files with 25 additions and 7 deletions

View file

@ -33,6 +33,8 @@ export namespace Vec3 {
export function normalize(v: Vec3): Vec3 {
const len = length(v)
return len === 0 ? v : scale(v, 1 / len)
// Fresh zero (not the input alias) to keep the namespace-wide no-aliasing
// guarantee even on the degenerate case.
return len === 0 ? { x: 0, y: 0, z: 0 } : scale(v, 1 / len)
}
}

View file

@ -9,8 +9,13 @@ export type Color = number
export namespace Color {
export function rgb(r: number, g: number, b: number, a = 255): Color {
// The shifts coerce the (possibly fractional) inputs to int32 and pack the
// channels; `>>> 0` forces an unsigned result so it stays a valid Color.
return ((a << 24) | (b << 16) | (g << 8) | r) >>> 0
// channels. Left as a *signed* int32 on purpose: an unsigned `>>> 0` would
// push opaque colors (alpha 255) past V8's Smi range, so every one would be
// heap-boxed -- and the per-pixel sky/raster loops mint millions per frame,
// enough to trigger visible GC pauses. Signed keeps them small Smis. Every
// consumer extracts channels with `&`/`>>>` and stores through ToUint32, so
// the sign is invisible to them.
return (a << 24) | (b << 16) | (g << 8) | r
}
export function r(c: Color): number {
@ -34,12 +39,16 @@ export namespace Color {
return rgb(r(c) * s, g(c) * s, b(c) * s, a(c))
}
/** Linear blend between two colors, t in 0..1. Used for fog and bilinear. */
/** Linear blend between two colors, t in 0..1. Used for fog and bilinear.
* Alpha is interpolated too: bilinear texture sampling relies on it so the
* sprite alpha cutout still sees transparent edges (opaque colors blend to
* opaque, so fog/sky are unaffected). */
export function lerp(from: Color, to: Color, t: number): Color {
return rgb(
r(from) + (r(to) - r(from)) * t,
g(from) + (g(to) - g(from)) * t,
b(from) + (b(to) - b(from)) * t,
a(from) + (a(to) - a(from)) * t,
)
}
}