# terrain_tiles_cut.ludic — the whole height field and photograph written out tile by tile, once a map is # made, and let go. The file is written fresh every time a map is made and never read by another # start, so no older generator's tiles are ever read; its header goes in last, so a start that died # writing it leaves a file whose magic is not there rather than one that looks whole. const TT_VERSION: int = 1 const TT_HEAD: int = 64 # bytes: 16 words @alloc_ok("a map being made: its tiles' file and their pools, once, not a frame") function terrain_tiles_cut(render3d_st: mut Render3dState) -> void { if render3d_st.tt_baked or render3d_st.tt_dir == "" or render3d_st.ter_heights == null { return } let t0 = gl_now_us() tt_close(render3d_st) let path = `{render3d_st.tt_dir}/{render3d_st.tt_key}.tiles` Fs.mkdir(render3d_st.tt_dir) let f = file_open(path, "wb") if f == null { tt_say_no_file(path); return } # the check compares the tiles with the whole copy, so it runs on the quantized copy the write leaves let bytes = ltt2_write(render3d_st, f, 0) file_close(f) if not tt_open_ltt2(render3d_st, path, 0) { tt_say_no_file(path); return } if r3d_env_has(render3d_st, "R3D_TT_CHECK") { tt_check(render3d_st) } ltt2_gpu_coarse(render3d_st) tt_say_cut(path, bytes, (gl_now_us() - t0) / 1000) } # the last map's file let go (a world swap, or the map made again) function tt_close(render3d_st: mut Render3dState) -> void { if render3d_st.tt_file != null { file_close(render3d_st.tt_file); render3d_st.tt_file = null } tf_forget(render3d_st) } function tt_say_no_file(path: string) -> void { print(`r3d: terrain: cannot write {path}; the whole height field stays in memory`) } function tt_say_cut(path: string, bytes: int, ms: int) -> void { print(`r3d: terrain: tiles written to {path} ({bytes / 1048576} MB, {ms} ms); the whole copies kept until terrain_tiles_build_done`) } # R3D_TT_CHECK: the tiles' answer against the whole copy's at 4000 points (must be exact), and the # coarse level's (what terrain_height_near falls back to) - while both are still here @alloc_ok("a developer check, once, under R3D_TT_CHECK") function tt_check(render3d_st: mut Render3dState) -> void { var worst = 0.0 var worst_c = 0.0 var seed = 12345 let half = float(render3d_st.TERRAIN_HALF) * 0.98 for k in 0 .. 4000 { seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF let x = render3d_st.ter_ox + (float(seed % 100000) / 50000.0 - 1.0) * half seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF let z = render3d_st.ter_oz + (float(seed % 100000) / 50000.0 - 1.0) * half let whole = terrain_height(render3d_st, x, z) let keep = render3d_st.ter_heights render3d_st.ter_heights = null let tiled = terrain_height(render3d_st, x, z) let scale = float(TERRAIN_RES) / float(render3d_st.TERRAIN_HALF * 2) let coarse = tt_coarse_at(render3d_st, (x - render3d_st.ter_ox + float(render3d_st.TERRAIN_HALF)) * scale, (z - render3d_st.ter_oz + float(render3d_st.TERRAIN_HALF)) * scale) render3d_st.ter_heights = keep worst = Math.max(worst, Math.abs(tiled - whole)) worst_c = Math.max(worst_c, Math.abs(coarse - whole)) } print(`r3d: terrain: tiles vs the whole copy at 4000 points: worst {worst} m; the coarse level: worst {worst_c} m`) } # The world's build places trees, rocks and cover over the whole map, asking exact heights # everywhere before any ring exists: through the tiles that read the file some 25 000 times. So the # whole copies stay through the build, and the game lets them go here when it is done (the end of # world_things, and after a swap's terrain_reload). Queries answer the same before and after. export function terrain_tiles_build_done(render3d_st: mut Render3dState) -> void { if render3d_st.tt_file == null { return } if render3d_st.ter_heights != null { free(render3d_st.ter_heights); render3d_st.ter_heights = null } if render3d_st.ter_ortho_px != null { free(render3d_st.ter_ortho_px); render3d_st.ter_ortho_px = null } render3d_st.tt_frame_reads = 0 tt_say_done() } function tt_say_done() -> void { print("r3d: terrain: the world is built; the whole height and photograph copies let go, tiles from here") }