ludic/packages/ludic.render3d/ground_fill.ludic

64 lines
2.9 KiB
Text

# ground_fill.ludic — a ground layer's instances in one chunk of its stream, from its painted density and
# nothing else: each cell's candidate (ground_cand.ludic), the same on every machine and in the editor. The
# camera picks only the chunks and their band; for a solid layer (ground_solid.ludic) not where things stand.
# a ground layer's numbers, as the game's row (GroundLayers) gives them; `layer` is its index in the densities
export property GroundFill {
layer: int = 0,
step0: float = 1.4,
step1: float = 1.4,
step2: float = 1.4,
step3: float = 1.4,
jitter: float = 1.0,
scale_lo: float = 1.0,
scale_hi: float = 1.0,
wind_lo: float = 0.6,
wind_hi: float = 1.0,
sink: float = 0.03,
trample: bool = true,
scale_var: float = 0.0, # each instance's own size: x (1 +- var), from its hash (a flower is not its neighbour)
band_grow: float = 0.0, # a far band's instances larger by this a band, to keep the cover as the step widens
solid: bool = false # things to touch: one step (step0) at every band, a stable id each, distance only thins
}
# how much of a candidate at (x, z) the game lets stand (the camp, the town): 0..1, asked only when the row says
export function r3d_on_ground_trample(render3d_st: mut Render3dState, f: fn(float, float) -> float) -> void { render3d_st.gd_trample_cb = f }
export function gf_step(g: GroundFill, band: int) -> float {
if band == 0 { return g.step0 }
if band == 1 { return g.step1 }
if band == 2 { return g.step2 }
return g.step3
}
# a hash of the candidate and one of its draws, 0..1: a 64-bit mix (the big constants are longs, `& 0xFFFFFFFF`
# is & -1, a no-op) - deterministic everywhere; narrowing it moves every painted thing, as the golden shows
export function gf_hash(a: int, b: int, c: int, d: int, e: int, k: int) -> float {
var h = (a * 73856093) ^ (b * 19349663) ^ (c * 83492791) ^ (d * 2654435761) ^ (e * 1597334677) ^ (k * 3812015801)
h = h & 0xFFFFFFFF
h = ((h ^ (h >> 16)) * 0x7feb352d) & 0xFFFFFFFF
h = ((h ^ (h >> 15)) * 0x846ca68b) & 0xFFFFFFFF
h = h ^ (h >> 16)
return float(h & 0xFFFFFF) / 16777216.0
}
# chunk (cx, cz) of stream s at `band`, from layer g (call it inside the game's r3d_stream_fill)
export function ground_fill(render3d_st: mut Render3dState, s: Stream, cx: int, cz: int, band: int, g: GroundFill) -> void {
if g.solid {
ground_fill_solid(render3d_st, s, cx, cz, band, g)
return
}
let step = gf_step(g, band)
if step <= 0.0 or render3d_st.gd_file == null { return }
let x0 = s.ox + float(cx) * s.size
let z0 = s.oz + float(cz) * s.size
let cells = int(Math.ceil(s.size / step))
let c = render3d_st.gd_cand
for j in 0 .. cells {
for i in 0 .. cells {
if not ground_candidate(render3d_st, g, cx, cz, band, i, j, x0, z0, s.size, c) { continue }
let h = terrain_height(render3d_st, c.x, c.z) - g.sink
stream_emit(render3d_st, s, c.x, h, c.z, c.scale, c.yaw, c.seed, c.wind)
}
}
}