render3d: ground_fill's candidate is a function of its own; solid layers with stable ids; the trample as clearing discs
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>
This commit is contained in:
parent
740ac2a879
commit
e535879262
7 changed files with 259 additions and 19 deletions
|
|
@ -860,6 +860,9 @@ export state Render3dState {
|
||||||
gd_zbuf: []byte = null # one tile's deflated bytes as read
|
gd_zbuf: []byte = null # one tile's deflated bytes as read
|
||||||
gd_hand: int = 0
|
gd_hand: int = 0
|
||||||
gd_trample_cb: fn(float, float) -> float = null
|
gd_trample_cb: fn(float, float) -> float = null
|
||||||
|
gd_clear: floats = floats(GD_CLEAR_MAX * 5) # the clearings as data: (x, z, r_in, r_out, floor) each (ground_clear.ludic)
|
||||||
|
gd_clear_n: int = 0
|
||||||
|
gd_cand: GroundCand = new GroundCand # ground_fill's candidate, filled and reused
|
||||||
gb_layer: int = -1 # the densities' layer the blades grow by; -1: the rules (grass_density.ludic)
|
gb_layer: int = -1 # the densities' layer the blades grow by; -1: the rules (grass_density.ludic)
|
||||||
gb_buf: int = 0 # its window round the camera, on the GPU
|
gb_buf: int = 0 # its window round the camera, on the GPU
|
||||||
gb_win: words = null # ... and the window's bytes, four texels a word, made once
|
gb_win: words = null # ... and the window's bytes, four texels a word, made once
|
||||||
|
|
|
||||||
68
packages/ludic.render3d/ground_cand.ludic
Normal file
68
packages/ludic.render3d/ground_cand.ludic
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
# ground_cand.ludic — one candidate of a ground layer: (layer, chunk, band, cell) to where it stands and what it
|
||||||
|
# draws with. The gf_* steps are pure (numbers in, a number out); ground_candidate reads the densities between
|
||||||
|
# them, and nothing but the densities' tile cache changes. The studio's groundFill.ts is these steps.
|
||||||
|
|
||||||
|
# a candidate, filled by the caller's own record (made once, reused)
|
||||||
|
export property GroundCand {
|
||||||
|
x: float = 0.0,
|
||||||
|
z: float = 0.0,
|
||||||
|
scale: float = 1.0,
|
||||||
|
yaw: float = 0.0,
|
||||||
|
seed: float = 0.0,
|
||||||
|
wind: float = 0.0,
|
||||||
|
cell: int = 0, # i * 65536 + j: the hashes' fifth input
|
||||||
|
id: int = -1 # a solid layer's stable id (ground_solid.ludic); -1 for cover
|
||||||
|
}
|
||||||
|
|
||||||
|
export function gf_cell(i: int, j: int) -> int { return i * 65536 + j }
|
||||||
|
|
||||||
|
# a cell's corner o, moved by the jitter's draw h (k 0 for x, 1 for z)
|
||||||
|
export function gf_along(o: float, i: int, h: float, jitter: float, step: float) -> float { return o + (float(i) + 0.5 + (h - 0.5) * jitter) * step }
|
||||||
|
|
||||||
|
# kept when draw 2 falls under the chance (the density, times the trample)
|
||||||
|
export function gf_keeps(g: GroundFill, cx: int, cz: int, band: int, e: int, keep: float) -> bool { return not (gf_hash(g.layer, cx, cz, band, e, 2) >= keep) }
|
||||||
|
|
||||||
|
# its size from the density's G at its place, and its own draw 6
|
||||||
|
export function gf_scale(g: GroundFill, cx: int, cz: int, band: int, e: int, gs: float) -> float {
|
||||||
|
var sc = Math.lerp(g.scale_lo, g.scale_hi, gs)
|
||||||
|
sc = sc * (1.0 + (gf_hash(g.layer, cx, cz, band, e, 6) * 2.0 - 1.0) * g.scale_var) * (1.0 + g.band_grow * float(band))
|
||||||
|
return sc
|
||||||
|
}
|
||||||
|
|
||||||
|
export function gf_yaw(g: GroundFill, cx: int, cz: int, band: int, e: int) -> float { return gf_hash(g.layer, cx, cz, band, e, 3) * 2.0 * PI }
|
||||||
|
|
||||||
|
export function gf_seed(g: GroundFill, cx: int, cz: int, band: int, e: int) -> float { return gf_hash(g.layer, cx, cz, band, e, 4) }
|
||||||
|
|
||||||
|
export function gf_wind(g: GroundFill, cx: int, cz: int, band: int, e: int) -> float { return Math.lerp(g.wind_lo, g.wind_hi, gf_hash(g.layer, cx, cz, band, e, 5)) }
|
||||||
|
|
||||||
|
# the chance at (x, z) after the trample: the game's callback, then the clearings it handed over as data
|
||||||
|
function gf_trampled(render3d_st: mut Render3dState, keep: float, x: float, z: float) -> float {
|
||||||
|
var k = keep
|
||||||
|
if render3d_st.gd_trample_cb != null { k = k * render3d_st.gd_trample_cb(x, z) }
|
||||||
|
if render3d_st.gd_clear_n > 0 { k = k * ground_clear_at(render3d_st, x, z) }
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
# cell (i, j) of chunk (cx, cz) at `band` - the chunk's corner (x0, z0), its side `size` - into `out`: true when
|
||||||
|
# one stands there
|
||||||
|
export function ground_candidate(render3d_st: mut Render3dState, g: GroundFill, cx: int, cz: int, band: int, i: int, j: int, x0: float, z0: float, size: float, out: GroundCand) -> bool {
|
||||||
|
let step = gf_step(g, band)
|
||||||
|
if step <= 0.0 { return false }
|
||||||
|
let e = gf_cell(i, j)
|
||||||
|
let px = gf_along(x0, i, gf_hash(g.layer, cx, cz, band, e, 0), g.jitter, step)
|
||||||
|
let pz = gf_along(z0, j, gf_hash(g.layer, cx, cz, band, e, 1), g.jitter, step)
|
||||||
|
if px < x0 or px >= x0 + size or pz < z0 or pz >= z0 + size { return false }
|
||||||
|
var keep = ground_density_at(render3d_st, g.layer, px, pz, 0)
|
||||||
|
if keep <= 0.0 { return false }
|
||||||
|
if g.trample { keep = gf_trampled(render3d_st, keep, px, pz) }
|
||||||
|
if not gf_keeps(g, cx, cz, band, e, keep) { return false }
|
||||||
|
out.x = px
|
||||||
|
out.z = pz
|
||||||
|
out.cell = e
|
||||||
|
out.id = -1
|
||||||
|
out.scale = gf_scale(g, cx, cz, band, e, ground_density_at(render3d_st, g.layer, px, pz, 1))
|
||||||
|
out.yaw = gf_yaw(g, cx, cz, band, e)
|
||||||
|
out.seed = gf_seed(g, cx, cz, band, e)
|
||||||
|
out.wind = gf_wind(g, cx, cz, band, e)
|
||||||
|
return true
|
||||||
|
}
|
||||||
44
packages/ludic.render3d/ground_clear.ludic
Normal file
44
packages/ludic.render3d/ground_clear.ludic
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
# ground_clear.ludic — the trample as data: clearings the game hands over (a camp's ring, a town's yard), each a
|
||||||
|
# disc trodden to `floor` inside r_in and back to full at r_out on a smoothstep. A layer with `trample` multiplies
|
||||||
|
# its chance by every clearing's; the editor draws the same discs, where it cannot see a callback.
|
||||||
|
|
||||||
|
const GD_CLEAR_MAX: int = 32
|
||||||
|
|
||||||
|
# no clearings (a map being opened, before the game hands its own)
|
||||||
|
export function r3d_ground_clearings_reset(render3d_st: mut Render3dState) -> void { render3d_st.gd_clear_n = 0 }
|
||||||
|
|
||||||
|
# a clearing at (x, z): false when GD_CLEAR_MAX are already held, or the disc is not r_in < r_out
|
||||||
|
export function r3d_ground_clearing(render3d_st: mut Render3dState, x: float, z: float, r_in: float, r_out: float, floor: float) -> bool {
|
||||||
|
if render3d_st.gd_clear_n >= GD_CLEAR_MAX or not (r_in < r_out) { return false }
|
||||||
|
let o = render3d_st.gd_clear_n * 5
|
||||||
|
render3d_st.gd_clear[o] = x
|
||||||
|
render3d_st.gd_clear[o + 1] = z
|
||||||
|
render3d_st.gd_clear[o + 2] = r_in
|
||||||
|
render3d_st.gd_clear[o + 3] = r_out
|
||||||
|
render3d_st.gd_clear[o + 4] = Math.clamp(floor, 0.0, 1.0)
|
||||||
|
render3d_st.gd_clear_n += 1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
# one clearing's share at (x, z), 0..1: `floor` inside r_in, 1 past r_out
|
||||||
|
export function gf_clear_one(cx: float, cz: float, r_in: float, r_out: float, floor: float, x: float, z: float) -> float {
|
||||||
|
let dx = x - cx
|
||||||
|
let dz = z - cz
|
||||||
|
let d2 = dx * dx + dz * dz
|
||||||
|
if d2 > r_out * r_out { return 1.0 }
|
||||||
|
let d = Math.sqrt(d2)
|
||||||
|
var t = Math.clamp((d - r_in) / (r_out - r_in), 0.0, 1.0)
|
||||||
|
t = t * t * (3.0 - 2.0 * t)
|
||||||
|
return floor + (1.0 - floor) * t
|
||||||
|
}
|
||||||
|
|
||||||
|
# every clearing's share at (x, z), multiplied in the order they were handed over
|
||||||
|
export function ground_clear_at(render3d_st: Render3dState, x: float, z: float) -> float {
|
||||||
|
var k = 1.0
|
||||||
|
for c in 0 .. render3d_st.gd_clear_n {
|
||||||
|
let o = c * 5
|
||||||
|
let cl = render3d_st.gd_clear
|
||||||
|
k = k * gf_clear_one(cl[o], cl[o + 1], cl[o + 2], cl[o + 3], cl[o + 4], x, z)
|
||||||
|
}
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
# ground_fill.ludic — a ground layer's instances in one chunk of its stream, placed from its painted density
|
# ground_fill.ludic — a ground layer's instances in one chunk of its stream, from its painted density and
|
||||||
# and nothing else: a candidate in each cell of the band's step, moved by the jitter, kept when a hash of
|
# nothing else: each cell's candidate (ground_cand.ludic), the same on every machine and in the editor. The
|
||||||
# (layer, chunk, band, cell) falls under the density there (times the game's trample, where it asks). The
|
# camera picks only the chunks and their band; for a solid layer (ground_solid.ludic) not where things stand.
|
||||||
# same numbers on every machine and in the editor's preview; the camera decides only which chunks.
|
|
||||||
|
|
||||||
# a ground layer's numbers, as the game's row (GroundLayers) gives them; `layer` is its index in the densities
|
# a ground layer's numbers, as the game's row (GroundLayers) gives them; `layer` is its index in the densities
|
||||||
export property GroundFill {
|
export property GroundFill {
|
||||||
|
|
@ -18,13 +17,14 @@ export property GroundFill {
|
||||||
sink: float = 0.03,
|
sink: float = 0.03,
|
||||||
trample: bool = true,
|
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)
|
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
|
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
|
# 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 r3d_on_ground_trample(render3d_st: mut Render3dState, f: fn(float, float) -> float) -> void { render3d_st.gd_trample_cb = f }
|
||||||
|
|
||||||
function gf_step(g: GroundFill, band: int) -> float {
|
export function gf_step(g: GroundFill, band: int) -> float {
|
||||||
if band == 0 { return g.step0 }
|
if band == 0 { return g.step0 }
|
||||||
if band == 1 { return g.step1 }
|
if band == 1 { return g.step1 }
|
||||||
if band == 2 { return g.step2 }
|
if band == 2 { return g.step2 }
|
||||||
|
|
@ -32,7 +32,7 @@ function gf_step(g: GroundFill, band: int) -> float {
|
||||||
}
|
}
|
||||||
|
|
||||||
# a hash of the candidate and one of its draws, 0..1 (a 32-bit mix: the same on every machine)
|
# a hash of the candidate and one of its draws, 0..1 (a 32-bit mix: the same on every machine)
|
||||||
function gf_hash(a: int, b: int, c: int, d: int, e: int, k: int) -> float {
|
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)
|
var h = (a * 73856093) ^ (b * 19349663) ^ (c * 83492791) ^ (d * 2654435761) ^ (e * 1597334677) ^ (k * 3812015801)
|
||||||
h = h & 0xFFFFFFFF
|
h = h & 0xFFFFFFFF
|
||||||
h = ((h ^ (h >> 16)) * 0x7feb352d) & 0xFFFFFFFF
|
h = ((h ^ (h >> 16)) * 0x7feb352d) & 0xFFFFFFFF
|
||||||
|
|
@ -43,25 +43,21 @@ function gf_hash(a: int, b: int, c: int, d: int, e: int, k: int) -> float {
|
||||||
|
|
||||||
# chunk (cx, cz) of stream s at `band`, from layer g (call it inside the game's r3d_stream_fill)
|
# 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 {
|
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)
|
let step = gf_step(g, band)
|
||||||
if step <= 0.0 or render3d_st.gd_file == null { return }
|
if step <= 0.0 or render3d_st.gd_file == null { return }
|
||||||
let x0 = s.ox + float(cx) * s.size
|
let x0 = s.ox + float(cx) * s.size
|
||||||
let z0 = s.oz + float(cz) * s.size
|
let z0 = s.oz + float(cz) * s.size
|
||||||
let cells = int(Math.ceil(s.size / step))
|
let cells = int(Math.ceil(s.size / step))
|
||||||
|
let c = render3d_st.gd_cand
|
||||||
for j in 0 .. cells {
|
for j in 0 .. cells {
|
||||||
for i in 0 .. cells {
|
for i in 0 .. cells {
|
||||||
let px = x0 + (float(i) + 0.5 + (gf_hash(g.layer, cx, cz, band, i * 65536 + j, 0) - 0.5) * g.jitter) * step
|
if not ground_candidate(render3d_st, g, cx, cz, band, i, j, x0, z0, s.size, c) { continue }
|
||||||
let pz = z0 + (float(j) + 0.5 + (gf_hash(g.layer, cx, cz, band, i * 65536 + j, 1) - 0.5) * g.jitter) * step
|
let h = terrain_height(render3d_st, c.x, c.z) - g.sink
|
||||||
if px < x0 or px >= x0 + s.size or pz < z0 or pz >= z0 + s.size { continue }
|
stream_emit(render3d_st, s, c.x, h, c.z, c.scale, c.yaw, c.seed, c.wind)
|
||||||
var keep = ground_density_at(render3d_st, g.layer, px, pz, 0)
|
|
||||||
if keep <= 0.0 { continue }
|
|
||||||
if g.trample and render3d_st.gd_trample_cb != null { keep = keep * render3d_st.gd_trample_cb(px, pz) }
|
|
||||||
let e = i * 65536 + j
|
|
||||||
if gf_hash(g.layer, cx, cz, band, e, 2) >= keep { continue }
|
|
||||||
var sc = Math.lerp(g.scale_lo, g.scale_hi, ground_density_at(render3d_st, g.layer, px, pz, 1))
|
|
||||||
sc = sc * (1.0 + (gf_hash(g.layer, cx, cz, band, e, 6) * 2.0 - 1.0) * g.scale_var) * (1.0 + g.band_grow * float(band))
|
|
||||||
let h = terrain_height(render3d_st, px, pz) - g.sink
|
|
||||||
stream_emit(render3d_st, s, px, h, pz, sc, gf_hash(g.layer, cx, cz, band, e, 3) * 2.0 * PI, gf_hash(g.layer, cx, cz, band, e, 4), Math.lerp(g.wind_lo, g.wind_hi, gf_hash(g.layer, cx, cz, band, e, 5)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
65
packages/ludic.render3d/ground_solid.ludic
Normal file
65
packages/ludic.render3d/ground_solid.ludic
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# 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)
|
||||||
|
}
|
||||||
60
packages/ludic.render3d/ground_solid_list.ludic
Normal file
60
packages/ludic.render3d/ground_solid_list.ludic
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
# ground_solid_list.ludic — a solid layer's things in one chunk, into a list the caller made once: what physics,
|
||||||
|
# the nav bake and a save ask, the same candidates the draw grows at band 0 (ground_solid.ludic).
|
||||||
|
|
||||||
|
export property GroundSolids {
|
||||||
|
cap: int = 0,
|
||||||
|
n: int = 0, # how many were written, never over cap
|
||||||
|
found: int = 0, # how many stand in the chunk: over cap, the list was too short for it
|
||||||
|
ids: words = null,
|
||||||
|
xs: floats = null,
|
||||||
|
zs: floats = null,
|
||||||
|
scales: floats = null,
|
||||||
|
yaws: floats = null,
|
||||||
|
seeds: floats = null,
|
||||||
|
winds: floats = null,
|
||||||
|
cand: GroundCand = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@alloc_ok("a caller's list of solid things, made once and reused")
|
||||||
|
export function ground_solids_new(cap: int) -> GroundSolids {
|
||||||
|
let l = new GroundSolids
|
||||||
|
l.cap = max(cap, 1)
|
||||||
|
l.ids = words(l.cap)
|
||||||
|
l.xs = floats(l.cap)
|
||||||
|
l.zs = floats(l.cap)
|
||||||
|
l.scales = floats(l.cap)
|
||||||
|
l.yaws = floats(l.cap)
|
||||||
|
l.seeds = floats(l.cap)
|
||||||
|
l.winds = floats(l.cap)
|
||||||
|
l.cand = new GroundCand
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
function gs_put(l: GroundSolids, c: GroundCand) -> void {
|
||||||
|
l.found += 1
|
||||||
|
if l.n >= l.cap { return }
|
||||||
|
let k = l.n
|
||||||
|
l.ids[k] = c.id
|
||||||
|
l.xs[k] = c.x
|
||||||
|
l.zs[k] = c.z
|
||||||
|
l.scales[k] = c.scale
|
||||||
|
l.yaws[k] = c.yaw
|
||||||
|
l.seeds[k] = c.seed
|
||||||
|
l.winds[k] = c.wind
|
||||||
|
l.n += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# chunk (cx, cz) of solid layer g - the stream's corner (ox, oz) and chunk side `size` - into `out`, emptied
|
||||||
|
# first, in cell order (j, then i); answers how many stand there
|
||||||
|
export function ground_solid_list(render3d_st: mut Render3dState, g: GroundFill, ox: float, oz: float, size: float, cx: int, cz: int, out: GroundSolids) -> int {
|
||||||
|
out.n = 0
|
||||||
|
out.found = 0
|
||||||
|
if g.step0 <= 0.0 or render3d_st.gd_file == null { return 0 }
|
||||||
|
let cells = gs_cells(g, size)
|
||||||
|
for j in 0 .. cells {
|
||||||
|
for i in 0 .. cells {
|
||||||
|
if ground_solid_candidate(render3d_st, g, ox, oz, size, cx, cz, i, j, out.cand) { gs_put(out, out.cand) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out.found
|
||||||
|
}
|
||||||
|
|
@ -60,6 +60,10 @@ import "stream_baked.ludic"
|
||||||
import "ground_density_write.ludic"
|
import "ground_density_write.ludic"
|
||||||
import "ground_density.ludic"
|
import "ground_density.ludic"
|
||||||
import "ground_fill.ludic"
|
import "ground_fill.ludic"
|
||||||
|
import "ground_cand.ludic"
|
||||||
|
import "ground_clear.ludic"
|
||||||
|
import "ground_solid.ludic"
|
||||||
|
import "ground_solid_list.ludic"
|
||||||
import "fog_streams.ludic"
|
import "fog_streams.ludic"
|
||||||
import "grass_kind.ludic"
|
import "grass_kind.ludic"
|
||||||
import "grass_bind.ludic"
|
import "grass_bind.ludic"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue