ground_candidate answers (layer, chunk, band, cell) -> keep, x, z, scale, yaw, seed, wind from pure gf_* steps and the density read between them; ground_fill draws its answers with the same operations in the same order. A solid layer fills at step0 and band 0 whatever the camera, a far band drawing a stable subset (draw 7 under (step0/step_b)^2), each thing an int id from (layer, chunk, cell), listed per chunk into a caller's GroundSolids or answered by id. r3d_ground_clearing hands the trample over as discs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
65 lines
3.6 KiB
Text
65 lines
3.6 KiB
Text
# ground_solid.ludic — a solid layer (rocks, trees): its candidates at step0 and band 0 whatever the camera, so
|
|
# a thing stands in one place for physics, the nav bake, a save and the draw alike. Its id is (layer, chunk,
|
|
# cell), stable while the painting under it is; a far band draws a subset of the same things, never others.
|
|
|
|
const GS_SPAN: int = 256 # chunks a side an id holds: -128 .. 127 about the stream's corner
|
|
const GS_CELLS: int = 512 # cells a chunk an id holds: a solid layer's step is at least the chunk's side / 22
|
|
|
|
# the id of cell (i, j) of chunk (cx, cz) in `layer`, where a chunk is cells x cells; -1 past what an id holds
|
|
export function ground_solid_id(layer: int, cx: int, cz: int, i: int, j: int, cells: int) -> int {
|
|
if layer < 0 or layer >= GD_LAYERS or cells * cells > GS_CELLS { return -1 }
|
|
if cx < -128 or cx > 127 or cz < -128 or cz > 127 { return -1 }
|
|
return ((layer * GS_SPAN + (cz + 128)) * GS_SPAN + (cx + 128)) * GS_CELLS + i * cells + j
|
|
}
|
|
|
|
export function ground_solid_layer(id: int) -> int { return id / (GS_CELLS * GS_SPAN * GS_SPAN) }
|
|
export function ground_solid_cx(id: int) -> int { return (id / GS_CELLS) % GS_SPAN - 128 }
|
|
export function ground_solid_cz(id: int) -> int { return (id / (GS_CELLS * GS_SPAN)) % GS_SPAN - 128 }
|
|
|
|
# a solid layer's cells a chunk side
|
|
export function gs_cells(g: GroundFill, size: float) -> int { return int(Math.ceil(size / g.step0)) }
|
|
|
|
# the share of a solid layer drawn at `band`: as much fewer as a cover layer's wider step would make it
|
|
export function gs_thin(g: GroundFill, band: int) -> float {
|
|
if band <= 0 { return 1.0 }
|
|
let r = g.step0 / gf_step(g, band)
|
|
return Math.min(r * r, 1.0)
|
|
}
|
|
|
|
# cell (i, j) of chunk (cx, cz) of solid layer g into `out`, its id with it: true when one stands there
|
|
export function ground_solid_candidate(render3d_st: mut Render3dState, g: GroundFill, ox: float, oz: float, size: float, cx: int, cz: int, i: int, j: int, out: GroundCand) -> bool {
|
|
if g.step0 <= 0.0 { return false }
|
|
let id = ground_solid_id(g.layer, cx, cz, i, j, gs_cells(g, size))
|
|
if id < 0 { return false }
|
|
let x0 = ox + float(cx) * size
|
|
let z0 = oz + float(cz) * size
|
|
if not ground_candidate(render3d_st, g, cx, cz, 0, i, j, x0, z0, size, out) { return false }
|
|
out.id = id
|
|
return true
|
|
}
|
|
|
|
# the draw: every candidate at band 0, a stable subset of them farther out (draw 7 under gs_thin)
|
|
function ground_fill_solid(render3d_st: mut Render3dState, s: Stream, cx: int, cz: int, band: int, g: GroundFill) -> void {
|
|
if g.step0 <= 0.0 or render3d_st.gd_file == null { return }
|
|
let cells = gs_cells(g, s.size)
|
|
let thin = gs_thin(g, band)
|
|
let c = render3d_st.gd_cand
|
|
for j in 0 .. cells {
|
|
for i in 0 .. cells {
|
|
if not ground_solid_candidate(render3d_st, g, s.ox, s.oz, s.size, cx, cz, i, j, c) { continue }
|
|
if band > 0 and not (gf_hash(g.layer, cx, cz, 0, c.cell, 7) < thin) { 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)
|
|
}
|
|
}
|
|
}
|
|
|
|
# the candidate `id` names in solid layer g (the stream's corner and chunk side): false when the painting
|
|
# under it keeps nothing there now, or the id is not this layer's
|
|
export function ground_solid_at(render3d_st: mut Render3dState, g: GroundFill, ox: float, oz: float, size: float, id: int, out: GroundCand) -> bool {
|
|
if id < 0 or g.step0 <= 0.0 or ground_solid_layer(id) != g.layer { return false }
|
|
let cells = gs_cells(g, size)
|
|
let cell = id % GS_CELLS
|
|
if cells <= 0 or cell >= cells * cells { return false }
|
|
return ground_solid_candidate(render3d_st, g, ox, oz, size, ground_solid_cx(id), ground_solid_cz(id), cell / cells, cell % cells, out)
|
|
}
|