# state.ludic - the kinds of walker, what a mesh is built for, and what the package holds: a mesh # per kind, and the last path's corners and nearest point, read back through the verbs export const NAV_PERSON: int = 0 # 0.35 m wide, steps what a hiker steps (CHAR_STEP) export const NAV_LARGE: int = 1 # an elk, a bear, a horse export const NAV_SMALL: int = 2 # a hare, a marmot export const NAV_KINDS: int = 3 export const NAV_FILTERS: int = 8 # costs per kind of ground, one set per taste (nav_area_cost) export const NAV_CORNERS: int = 256 # a path's corners at most; a longer one is cut there # what a mesh is built for: its voxels (cell across, cell high) and its walker (height, radius, # the step it takes whatever its gradient, the steepest ground it walks, degrees). A tile must be a # whole number of cells across, or its seams never join: 0.25 m is 256 to a 64 m tile export property NavConfig { cell: float = 0.25 cell_h: float = 0.2 height: float = 1.8 radius: float = 0.35 climb: float = 0.55 slope: float = 45.0 detail: float = 1.5 # the detail mesh's samples, metres apart (at least 0.9: 0 took one small test to 3.5 GB) } # what a mesh is built from: v holds nv points (x, y, z) and t nt triangles (three indices each); # area a byte per triangle, 0 not walkable and 1..62 a kind of ground; cyl nc cylinders (x, y, z, # r, h) and foot nf floats of convex footprints (n, n points x z, ymin, ymax) nothing stands in export property NavGround { v: []float = null nv: int = 0 t: []int = null nt: int = 0 area: []byte = null cyl: []float = null nc: int = 0 foot: []float = null nf: int = 0 } export state NavState { nv_meshes: []pointer = nv_none() nv_out: []float = floats(NAV_CORNERS * 3) nv_count: int = 0 nv_near: []float = floats(3) nv_cfg: []float = floats(7) # the configuration handed to the shim, filled in place per build nv_empty: []float = floats(1) # what the shim is handed for no cylinders or no footprints nv_asked: int = 0 # paths asked for, found (two corners or more), and cut short nv_found: int = 0 nv_short: int = 0 nv_crowds: []pointer = nv_none() # a crowd per kind, on that kind's mesh (crowd.ludic) nv_agent: []float = floats(6) # the last walker read: position, velocity nv_files: []pointer = nv_none() # a file-backed mesh's file, kept open for its tiles (resident.ludic) nv_tile: []float = floats(4) # the last tile asked about: centre x, z, in, bytes } function nv_none() -> []pointer { let m = new []pointer for k in 0 .. NAV_KINDS { push(m, null) } return m } function nv_mesh(nav_st: NavState, kind: int) -> pointer { if kind < 0 or kind >= NAV_KINDS { return null } return nav_st.nv_meshes[kind] } function nv_set(nav_st: mut NavState, kind: int, h: pointer) -> bool { if kind < 0 or kind >= NAV_KINDS { return false } nv_crowd_drop(nav_st, kind) if nav_st.nv_files[kind] != null { file_close(nav_st.nv_files[kind]) } nav_st.nv_files[kind] = null if nav_st.nv_meshes[kind] != null { nvc_free(nav_st.nv_meshes[kind]) } nav_st.nv_meshes[kind] = h return h != null } # one kind's mesh let go (a bake writes each kind and drops it before the next) export function nav_drop(nav_st: mut NavState, kind: int) -> void { nv_set(nav_st, kind, null) } # every mesh let go: a new map, or the world closed export function nav_reset(nav_st: mut NavState) -> void { for k in 0 .. NAV_KINDS { nv_set(nav_st, k, null) } nav_st.nv_count = 0 nav_st.nv_asked = 0 nav_st.nv_found = 0 nav_st.nv_short = 0 }