fix: minor stuff
This commit is contained in:
parent
e0585db0e0
commit
f86b4ada13
5 changed files with 25 additions and 7 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -3,3 +3,5 @@ node_modules
|
|||
dist
|
||||
.opencode
|
||||
builds
|
||||
tmp
|
||||
out
|
||||
|
|
@ -99,7 +99,7 @@ export function buildLevel(): Level {
|
|||
sun: Color.rgb(255, 246, 214),
|
||||
sunDir: { x: 0.3, y: 0.5, z: -0.8 },
|
||||
sunSize: 0.04,
|
||||
clouds: fancyCumulus,
|
||||
clouds: basicCumulus,
|
||||
}
|
||||
|
||||
return { floor, walls, crate, colliders, npcPosition: { x: 2, y: 0, z: -1 }, sky }
|
||||
|
|
|
|||
|
|
@ -67,6 +67,11 @@ async function main(): Promise<void> {
|
|||
globalThis.addEventListener("keyup", (e) => {
|
||||
keys.delete(e.code)
|
||||
})
|
||||
// Losing focus (alt-tab, pointer-lock exit) drops keyup events, so clear held
|
||||
// keys or movement sticks on.
|
||||
globalThis.addEventListener("blur", () => {
|
||||
keys.clear()
|
||||
})
|
||||
screen.addEventListener("click", () => {
|
||||
screen.requestPointerLock()
|
||||
})
|
||||
|
|
@ -108,7 +113,7 @@ async function main(): Promise<void> {
|
|||
Rasterizer.draw(fb, level.floor, textures.floor, viewProj, config)
|
||||
Rasterizer.draw(fb, level.walls, textures.wall, viewProj, config)
|
||||
Rasterizer.draw(fb, level.crate, textures.crate, viewProj, config)
|
||||
Rasterizer.draw(fb, Sprite.billboard(npc, camera), textures.npc, viewProj, config)
|
||||
Rasterizer.draw(fb, Sprite.billboard(npc, camera), npc.texture, viewProj, config)
|
||||
Framebuffer.quantize(fb, config)
|
||||
present()
|
||||
requestAnimationFrame(frame)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue