render3d: place_rec.ludic, the one encoder and decoder of a baked placement
prec_put / prec_get / prec_size (Physics' spec): PREC_FULL, 12 bytes, for trees, boulders and stones (u16 x, z in 1/65536 of the chunk; u16 y in cm above y_base; u8 scale over the kind's lo..hi, yaw, seed, wind), and PREC_PACKED, 7 bytes, for the stream kinds (56 bits, least significant first: x 12, z 12, y 12 in cm, scale 6, yaw 6, seed 4, wind 4). An encode takes the cell a value falls in, a decode its centre, so a round trip is stable; a record is read from a []byte at an offset, never a pointer. stream_emit_baked and layer_chunk_put take (recs, at, fmt) and decode through it; the earlier sb7_* pair is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3f0bb07c16
commit
8589a5a7b4
6 changed files with 86 additions and 58 deletions
|
|
@ -1,7 +1,7 @@
|
|||
# stream_baked.ludic — a stream filled from baked chunks instead of generated ones (plan 26 of
|
||||
# maroon-lake). The bake stores every instance of a kind once per 64 m chunk, at full density and in a
|
||||
# shuffled order, so a distance band draws a PREFIX of it: a nearer band holds everything a farther one
|
||||
# does. The stream kinds' records are 7 bytes (below); the fixed layers' 12 (layer_chunks.ludic).
|
||||
# does. A record's layout is place_rec.ludic's.
|
||||
|
||||
# the stream's cells laid on the baked chunks' grid: `size` metres from the corner (ox, oz)
|
||||
export function stream_set_grid(s: Stream, ox: float, oz: float) -> void {
|
||||
|
|
@ -9,46 +9,13 @@ export function stream_set_grid(s: Stream, ox: float, oz: float) -> void {
|
|||
s.oz = oz
|
||||
}
|
||||
|
||||
# ---- the stream kinds' 7-byte record (the one pack and unpack both the bake and the game use) ----
|
||||
# 56 bits, least significant first, bytes little-endian: x 12 (1/4096 of the chunk), z 12, y 12 (over
|
||||
# the chunk's y span: y_base + v / 4095 * y_span), scale 6 (lo + v / 63 * (hi - lo)), yaw 6 (v / 64 of a
|
||||
# turn), seed 4 (v / 15), wind 4 (v / 15). Read as a low word (bytes 0-3) and a high one (4-6), so no
|
||||
# field needs a 64-bit int.
|
||||
const SB7_REC: int = 7
|
||||
|
||||
# one record's fields (already quantized) written at `at` in `out`
|
||||
export function sb7_pack(out: []byte, at: int, x: int, z: int, y: int, scale: int, yaw: int, seed: int, wind: int) -> void {
|
||||
let lo = (x & 4095) | ((z & 4095) << 12) | ((y & 255) << 24)
|
||||
let hi = ((y >> 8) & 15) | ((scale & 63) << 4) | ((yaw & 63) << 10) | ((seed & 15) << 16) | ((wind & 15) << 20)
|
||||
out[at] = lo & 255; out[at + 1] = (lo >> 8) & 255; out[at + 2] = (lo >> 16) & 255; out[at + 3] = (lo >> 24) & 255
|
||||
out[at + 4] = hi & 255; out[at + 5] = (hi >> 8) & 255; out[at + 6] = (hi >> 16) & 255
|
||||
}
|
||||
|
||||
# field k of the record at `at` (0 x, 1 z, 2 y, 3 scale, 4 yaw, 5 seed, 6 wind), as its integer
|
||||
export function sb7_field(recs: pointer, at: int, k: int) -> int {
|
||||
let lo = recs[at] | (recs[at + 1] << 8) | (recs[at + 2] << 16) | ((recs[at + 3] & 255) << 24)
|
||||
let hi = recs[at + 4] | (recs[at + 5] << 8) | (recs[at + 6] << 16)
|
||||
if k == 0 { return lo & 4095 }
|
||||
if k == 1 { return (lo >> 12) & 4095 }
|
||||
if k == 2 { return ((lo >> 24) & 255) | ((hi & 15) << 8) }
|
||||
if k == 3 { return (hi >> 4) & 63 }
|
||||
if k == 4 { return (hi >> 10) & 63 }
|
||||
if k == 5 { return (hi >> 16) & 15 }
|
||||
return (hi >> 20) & 15
|
||||
}
|
||||
|
||||
# the first `keep` 7-byte records of a stream kind's chunk emitted into the chunk being filled
|
||||
export function stream_emit_baked(render3d_st: mut Render3dState, s: Stream, recs: pointer, count: int, keep: int, x0: float, z0: float, y_base: float, y_span: float, lo: float, hi: float) -> void {
|
||||
let n = min(keep, count)
|
||||
let span = s.size / 4096.0
|
||||
for i in 0 .. n {
|
||||
let o = i * SB7_REC
|
||||
let x = x0 + float(sb7_field(recs, o, 0)) * span
|
||||
let z = z0 + float(sb7_field(recs, o, 1)) * span
|
||||
let y = y_base + float(sb7_field(recs, o, 2)) / 4095.0 * y_span
|
||||
let scale = lo + float(sb7_field(recs, o, 3)) / 63.0 * (hi - lo)
|
||||
let yaw = float(sb7_field(recs, o, 4)) * (2.0 * PI / 64.0)
|
||||
stream_emit(render3d_st, s, x, y, z, scale, yaw, float(sb7_field(recs, o, 5)) / 15.0, float(sb7_field(recs, o, 6)) / 15.0)
|
||||
# the first `keep` of a chunk's `count` records (format fmt, place_rec.ludic) at byte `at` of recs
|
||||
# emitted into the chunk being filled
|
||||
export function stream_emit_baked(render3d_st: mut Render3dState, s: Stream, recs: []byte, at: int, fmt: int, count: int, keep: int, x0: float, z0: float, y_base: float, lo: float, hi: float) -> void {
|
||||
let v = render3d_st.sb_rec
|
||||
for i in 0 .. min(keep, count) {
|
||||
prec_get(fmt, recs, at, i, x0, z0, s.size, y_base, lo, hi, v)
|
||||
stream_emit(render3d_st, s, v[0], v[1], v[2], v[3], Math.atan2(v[4], v[5]), v[6], v[7])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue