feat(lang): strict numbers in float files; render3d on float
A numbers float file adapts decimal literals to a fixed operand or slot, and refuses to promote a computed int to a float implicitly: there it is almost always float bits. Explicit float(x) is always allowed. render3d's numbers are float, converted by tools/migrate/floatbits.py - a whole-program inference of which ints carried IEEE bits (union-find over flows, calls, returns, buffers, nested buffers and lexical scopes) and a rewriter to operators, Math.* and float literals, with float_bits / float_from_bits left only where bits really cross (runtime scratch buffers, mixed buffers). Seed regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3ac0d8d5cb
commit
cc89fc37a4
35 changed files with 57282 additions and 54382 deletions
|
|
@ -19,14 +19,14 @@ property Chunk {
|
|||
used: int = 0, # the walk that last wanted it (for eviction)
|
||||
data: words, # INST_FLOATS per instance
|
||||
count: int = 0,
|
||||
ymin: int = 0, # height range of its instances (float bits), for the frustum test
|
||||
ymax: int = 0
|
||||
ymin: float = 0.0, # height range of its instances (float bits), for the frustum test
|
||||
ymax: float = 0.0
|
||||
}
|
||||
property Stream {
|
||||
layer: Layer,
|
||||
size: int = 0, # chunk size (metres, float bits)
|
||||
reach: int = 0, # radius (metres, float bits)
|
||||
bands: words, # band outer radii (float bits), ascending; 4 of them
|
||||
size: float = 0.0, # chunk size (metres, float bits)
|
||||
reach: float = 0.0, # radius (metres, float bits)
|
||||
bands: floats, # band outer radii (float bits), ascending; 4 of them
|
||||
chunks: []Chunk,
|
||||
keys: words, # parallel to chunks for lookup
|
||||
n: int = 0,
|
||||
|
|
@ -51,7 +51,7 @@ var stream_us_gather: long = 0 # copying cached chunks into the layer buffer
|
|||
var stream_us_walk: long = 0 # the ring walk itself
|
||||
var stream_walks: int = 0 # streams that walked their whole ring this frame
|
||||
|
||||
function stream_new(layer: Layer, size: int, reach: int, b0: int, b1: int, b2: int, b3: int) -> Stream {
|
||||
function stream_new(layer: Layer, size: float, reach: float, b0: float, b1: float, b2: float, b3: float) -> Stream {
|
||||
if not stream_cap_read {
|
||||
stream_cap_read = true
|
||||
if r3d_env_has("R3D_STREAM_CAP") { STREAM_MAX_CHUNKS = Text.to_int(r3d_env("R3D_STREAM_CAP")) }
|
||||
|
|
@ -61,7 +61,7 @@ function stream_new(layer: Layer, size: int, reach: int, b0: int, b1: int, b2: i
|
|||
s.layer = layer; s.size = size; s.reach = reach
|
||||
layer.streamed = true
|
||||
layer.grounded = true
|
||||
s.bands = words(4)
|
||||
s.bands = floats(4)
|
||||
s.bands[0] = b0; s.bands[1] = b1; s.bands[2] = b2; s.bands[3] = b3
|
||||
s.chunks = new []Chunk
|
||||
s.keys = words(STREAM_MAX_CHUNKS)
|
||||
|
|
@ -108,23 +108,23 @@ function stream_remember(s: Stream, key: int, idx: int) -> void {
|
|||
# chunk gets an exactly-sized copy when the fill ends)
|
||||
const STREAM_CHUNK_MAX: int = 262144
|
||||
var stream_debug_n: int = 0
|
||||
var stream_scratch: words = null
|
||||
function stream_emit(s: Stream, x: int, y: int, z: int, scale: int, yaw: int, seed: int, wind: int) -> void {
|
||||
var stream_scratch: floats = null
|
||||
function stream_emit(s: Stream, x: float, y: float, z: float, scale: float, yaw: float, seed: float, wind: float) -> void {
|
||||
let c = s.cur
|
||||
if c.count >= STREAM_CHUNK_MAX { return }
|
||||
if stream_scratch == null { stream_scratch = words(STREAM_CHUNK_MAX * INST_FLOATS) }
|
||||
if c.count == 0 { c.ymin = y; c.ymax = y } else { c.ymin = f_min(c.ymin, y); c.ymax = f_max(c.ymax, y) }
|
||||
if stream_scratch == null { stream_scratch = floats(STREAM_CHUNK_MAX * INST_FLOATS) }
|
||||
if c.count == 0 { c.ymin = y; c.ymax = y } else { c.ymin = Math.min(c.ymin, y); c.ymax = Math.max(c.ymax, y) }
|
||||
let o = c.count * INST_FLOATS
|
||||
stream_scratch[o] = x; stream_scratch[o + 1] = y; stream_scratch[o + 2] = z; stream_scratch[o + 3] = scale
|
||||
stream_scratch[o + 4] = f_sin(yaw); stream_scratch[o + 5] = f_cos(yaw); stream_scratch[o + 6] = seed; stream_scratch[o + 7] = wind
|
||||
stream_scratch[o + 4] = Math.sin(yaw); stream_scratch[o + 5] = Math.cos(yaw); stream_scratch[o + 6] = seed; stream_scratch[o + 7] = wind
|
||||
c.count += 1
|
||||
}
|
||||
|
||||
function stream_band(s: Stream, d: int) -> int {
|
||||
if f_ls(d, s.bands[0]) { return 0 }
|
||||
if f_ls(d, s.bands[1]) { return 1 }
|
||||
if f_ls(d, s.bands[2]) { return 2 }
|
||||
if f_ls(d, s.bands[3]) { return 3 }
|
||||
function stream_band(s: Stream, d: float) -> int {
|
||||
if d < s.bands[0] { return 0 }
|
||||
if d < s.bands[1] { return 1 }
|
||||
if d < s.bands[2] { return 2 }
|
||||
if d < s.bands[3] { return 3 }
|
||||
return 4
|
||||
}
|
||||
|
||||
|
|
@ -193,9 +193,9 @@ function stream_evict(s: Stream) -> void {
|
|||
stream_evictions += 1
|
||||
}
|
||||
|
||||
function stream_update(s: Stream, cam_x: int, cam_z: int) -> void {
|
||||
let ccx = f_to_int(f_floor(f_div(cam_x, s.size)))
|
||||
let ccz = f_to_int(f_floor(f_div(cam_z, s.size)))
|
||||
function stream_update(s: Stream, cam_x: float, cam_z: float) -> void {
|
||||
let ccx = int(Math.floor(cam_x / s.size))
|
||||
let ccz = int(Math.floor(cam_z / s.size))
|
||||
if ccx == s.last_cx and ccz == s.last_cz and not s.pending and s.view_gen == sc_view_gen { return }
|
||||
let first = s.last_cx == 999999
|
||||
s.view_gen = sc_view_gen
|
||||
|
|
@ -206,7 +206,7 @@ function stream_update(s: Stream, cam_x: int, cam_z: int) -> void {
|
|||
stream_walks += 1
|
||||
stream_walk_no += 1
|
||||
let tw = gl_now_us()
|
||||
let r = f_to_int(f_div(s.reach, s.size)) + 1
|
||||
let r = int(s.reach / s.size) + 1
|
||||
# rings outward from the camera's cell: the nearest chunks are generated first
|
||||
var ring = 0
|
||||
while ring <= r {
|
||||
|
|
@ -216,12 +216,12 @@ function stream_update(s: Stream, cam_x: int, cam_z: int) -> void {
|
|||
while cx <= ccx + ring {
|
||||
let edge = (cz == ccz - ring) or (cz == ccz + ring) or (cx == ccx - ring) or (cx == ccx + ring)
|
||||
if edge {
|
||||
let wx = f_mul(f_add(fi(cx), F_HALF), s.size)
|
||||
let wz = f_mul(f_add(fi(cz), F_HALF), s.size)
|
||||
let dx = f_sub(wx, cam_x); let dz = f_sub(wz, cam_z)
|
||||
let d = f_sqrt(f_add(f_mul(dx, dx), f_mul(dz, dz)))
|
||||
let wx = (float(cx) + 0.5) * s.size
|
||||
let wz = (float(cz) + 0.5) * s.size
|
||||
let dx = wx - cam_x; let dz = wz - cam_z
|
||||
let d = Math.sqrt(dx * dx + dz * dz)
|
||||
let band = stream_band(s, d)
|
||||
if band < 4 and band >= s.min_band and f_ls(d, f_add(s.reach, s.size)) {
|
||||
if band < 4 and band >= s.min_band and d < s.reach + s.size {
|
||||
let key = stream_key(cx, cz, band)
|
||||
var c = stream_find(s, key)
|
||||
if c != null { c.used = stream_walk_no }
|
||||
|
|
@ -283,12 +283,12 @@ function stream_update(s: Stream, cam_x: int, cam_z: int) -> void {
|
|||
# height range, padded for the tallest cover and for casters just outside the frame
|
||||
# whose short shadows still fall inside it.
|
||||
function stream_chunk_visible(s: Stream, cx: int, cz: int, c: Chunk) -> bool {
|
||||
let half = f_mul(s.size, F_HALF)
|
||||
let wx = f_add(f_mul(fi(cx), s.size), half)
|
||||
let wz = f_add(f_mul(fi(cz), s.size), half)
|
||||
let hy = f_mul(f_sub(c.ymax, c.ymin), F_HALF)
|
||||
let cy = f_add(c.ymin, hy)
|
||||
let r = f_add(f_sqrt(f_add(f_mul(f_mul(half, half), F_TWO), f_mul(hy, hy))), fi(8))
|
||||
let half = s.size * 0.5
|
||||
let wx = float(cx) * s.size + half
|
||||
let wz = float(cz) * s.size + half
|
||||
let hy = (c.ymax - c.ymin) * 0.5
|
||||
let cy = c.ymin + hy
|
||||
let r = Math.sqrt(half * half * 2.0 + hy * hy) + 8.0
|
||||
return cam_sphere_visible(wx, cy, wz, r)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue