diff --git a/packages/ludic.render3d/env.ludic b/packages/ludic.render3d/env.ludic index 7431de42..6ca513cf 100644 --- a/packages/ludic.render3d/env.ludic +++ b/packages/ludic.render3d/env.ludic @@ -831,6 +831,11 @@ export state Render3dState { ter_shadow_tex: int = 0 # height-field sun shadow: R32F, the lowest lit height stream_capture_c: Chunk = null # the bake's capture chunk (stream_baked.ludic) sb_rec: floats = floats(8) # one decoded baked record, reused (stream_baked.ludic) + tb_tiles: string = "" # the map's baked tiles and shadow (terrain_baked_boot.ludic) + tb_shadow: string = "" + tb_key: string = "" + tb_version: int = 0 + tb_shadow_ok: bool = false # the shadow came from its bake this map tt_dir: string = "" # terrain_tiles_to: where a map's tiles are written ("" keeps the whole copies) tt_key: string = "" tt_file: pointer = null # the tiles' file, open for reading (terrain_tiles.ludic) diff --git a/packages/ludic.render3d/r3d.ludic b/packages/ludic.render3d/r3d.ludic index c870cf20..3ac1e8a8 100644 --- a/packages/ludic.render3d/r3d.ludic +++ b/packages/ludic.render3d/r3d.ludic @@ -31,6 +31,7 @@ import "terrain_tiles.ludic" import "terrain_tiles_cut.ludic" import "terrain_ltt2_write.ludic" import "terrain_ltt2_read.ludic" +import "terrain_baked_boot.ludic" import "terrain_pages.ludic" import "terrain_pages_frame.ludic" import "terrain_pages_fill.ludic" diff --git a/packages/ludic.render3d/render.ludic b/packages/ludic.render3d/render.ludic index 69aa0fa1..663191ae 100644 --- a/packages/ludic.render3d/render.ludic +++ b/packages/ludic.render3d/render.ludic @@ -143,7 +143,7 @@ function r3d_load_step(render3d_st: mut Render3dState, i: int) -> bool { daylight_init(render3d_st) } else if t >= 0 and t < TERRAIN_INIT_STEPS { if render3d_st.r3d_plate { return true } - if t == 0 { + if t == 0 and not terrain_baked_try(render3d_st) { if render3d_st.r3d_dem_path != null { terrain_use_dem(render3d_st, render3d_st.r3d_dem_path, render3d_st.r3d_dem_min, render3d_st.r3d_dem_max, render3d_st.r3d_dem_base, render3d_st.r3d_dem_ox, render3d_st.r3d_dem_oz) } if render3d_st.r3d_ortho_path != null { terrain_use_ortho(render3d_st, render3d_st.r3d_ortho_path) } } diff --git a/packages/ludic.render3d/terrain.ludic b/packages/ludic.render3d/terrain.ludic index 264ea1ad..2759406e 100644 --- a/packages/ludic.render3d/terrain.ludic +++ b/packages/ludic.render3d/terrain.ludic @@ -413,7 +413,7 @@ const TERRAIN_INIT_STEPS: int = 4 function terrain_init_step(render3d_st: mut Render3dState, i: int) -> void { if i == 0 { if not render3d_st.tt_baked { terrain_generate(render3d_st) }; return } # a baked terrain whose shadow came from its own bake (terrain_shadow_from_bytes) keeps it - if i == 1 { if not (render3d_st.tt_baked and render3d_st.ter_shadow_tex != 0) { terrain_bake_shadow(render3d_st) }; return } + if i == 1 { if not (render3d_st.tt_baked and render3d_st.tb_shadow_ok) { terrain_bake_shadow(render3d_st) }; return } if i == 2 { terrain_load_textures(render3d_st); return } terrain_init_finish(render3d_st) } @@ -850,6 +850,14 @@ function terrain_reload(render3d_st: mut Render3dState, dem: string, emin: float terrain_unload(render3d_st) render3d_st.TERRAIN_HALF = half render3d_st.ter_ox = ox; render3d_st.ter_oz = oz + render3d_st.r3d_dem_ox = ox; render3d_st.r3d_dem_oz = oz + # a swap to a map that has its bake: the tiles and the shadow read, the bounds from the tiles + if terrain_baked_try(render3d_st) { + if not render3d_st.tb_shadow_ok { terrain_bake_shadow(render3d_st) } + cdlod_bounds(render3d_st) + gpu_check(render3d_st, "terrain reload") + return + } if len(dem) > 0 { terrain_use_dem(render3d_st, dem, emin, emax, base, ox, oz) } if len(ortho) > 0 { terrain_use_ortho(render3d_st, ortho) } terrain_generate(render3d_st) diff --git a/packages/ludic.render3d/terrain_baked_boot.ludic b/packages/ludic.render3d/terrain_baked_boot.ludic new file mode 100644 index 00000000..1359aa29 --- /dev/null +++ b/packages/ludic.render3d/terrain_baked_boot.ludic @@ -0,0 +1,37 @@ +# terrain_baked_boot.ludic — the game names its map's baked terrain (the tiles and the sun's shadow) before the +# map is made; the renderer's own start (r3d_init's terrain step) and terrain_reload then take it from +# them, and make the map from its survey as before when a bake is missing or not this version. + +# the map's bakes: the tiles' file and the shadow's, under the key and version they were baked as. +# "" for a path turns that one off. Before r3d_init at boot, and before terrain_reload on a swap +export function terrain_baked_at(render3d_st: mut Render3dState, tiles: string, shadow: string, key: string, version: int) -> void { + render3d_st.tb_tiles = intern(tiles) + render3d_st.tb_shadow = intern(shadow) + render3d_st.tb_key = intern(key) + render3d_st.tb_version = version +} + +# the map from its bake when there is one: true (nothing to generate), else false and nothing changed +function terrain_baked_try(render3d_st: mut Render3dState) -> bool { + render3d_st.tt_baked = false + if len(render3d_st.tb_tiles) == 0 { return false } + if not terrain_from_baked(render3d_st, render3d_st.tb_tiles, render3d_st.tb_key, render3d_st.tb_version, render3d_st.TERRAIN_HALF, render3d_st.r3d_dem_ox, render3d_st.r3d_dem_oz) { + tb_say_missing(render3d_st.tb_tiles) + return false + } + terrain_baked_shadow(render3d_st) + return true +} + +# the sun's height-field shadow from its bake, when there is one (else terrain_init bakes it from the coarse level) +@alloc_ok("a bake read once at load") +function terrain_baked_shadow(render3d_st: mut Render3dState) -> void { + render3d_st.tb_shadow_ok = false + if len(render3d_st.tb_shadow) == 0 { return } + let b = r3d_baked_read(render3d_st.tb_shadow, render3d_st.tb_key, render3d_st.tb_version) + if b != null { render3d_st.tb_shadow_ok = terrain_shadow_from_bytes(render3d_st, b) } + if not render3d_st.tb_shadow_ok { tb_say_missing(render3d_st.tb_shadow) } + if b != null { free(b) } +} + +function tb_say_missing(path: string) -> void { print(`bake: {path} missing or stale - the terrain made at run time (ludic bake)`) }