# gltf_release.ludic - a loaded model let go of: its meshes, and each texture once nothing else uses # it. The glTF loader shares textures between models (a path loaded once, a LOD chain borrowing its # LOD0's material), so each cached texture carries a count of the primitives using it. # one more primitive uses the cached texture `id` (0, or a texture the cache did not load: nothing) function gltf_tex_ref(render3d_st: mut Render3dState, id: int) -> void { if id == 0 or render3d_st.gltf_tex_refs == null { return } for i in 0 .. render3d_st.gltf_tex_n { if render3d_st.gltf_tex_ids[i] == id { render3d_st.gltf_tex_refs[i] += 1; return } } } # one primitive fewer: the last one frees the texture and forgets it, with every material naming it function gltf_tex_unref(render3d_st: mut Render3dState, id: int) -> void { if id == 0 or render3d_st.gltf_tex_refs == null { return } for i in 0 .. render3d_st.gltf_tex_n { if render3d_st.gltf_tex_ids[i] == id { render3d_st.gltf_tex_refs[i] -= 1 if render3d_st.gltf_tex_refs[i] > 0 { return } gpu_tex_free(render3d_st, id) gltf_tex_forget(render3d_st, i) gltf_mats_forget(render3d_st, id) return } } } # the cache entry i goes; the last entry takes its place function gltf_tex_forget(render3d_st: mut Render3dState, i: int) -> void { let last = render3d_st.gltf_tex_n - 1 let paths = render3d_st.gltf_tex_paths free(paths[i]) paths[i] = paths[last] render3d_st.gltf_tex_ids[i] = render3d_st.gltf_tex_ids[last] render3d_st.gltf_tex_refs[i] = render3d_st.gltf_tex_refs[last] List.pop(paths) render3d_st.gltf_tex_n = last } # a remembered material whose texture was freed is forgotten, so no later load borrows it function gltf_mats_forget(render3d_st: mut Render3dState, id: int) -> void { if render3d_st.gltf_mat_names == null { return } var k = 0 while k < render3d_st.gltf_mat_n { if render3d_st.gltf_mat_diff[k] == id or render3d_st.gltf_mat_nrm[k] == id or render3d_st.gltf_mat_arm[k] == id { let last = render3d_st.gltf_mat_n - 1 let names = render3d_st.gltf_mat_names free(names[k]) names[k] = names[last] render3d_st.gltf_mat_diff[k] = render3d_st.gltf_mat_diff[last] render3d_st.gltf_mat_nrm[k] = render3d_st.gltf_mat_nrm[last] render3d_st.gltf_mat_arm[k] = render3d_st.gltf_mat_arm[last] List.pop(names) render3d_st.gltf_mat_n = last } else { k += 1 } } } # Let a model go: every primitive's mesh, and its textures once no other model uses it; the # primitives, their meshes and the model itself are freed, and a model gltf_cached handed out # leaves its cache. The caller says when: nothing may draw the model, or hold it, afterwards. For # a model gltf_load or gltf_cached made (a procedural one - a card, a blade - owns its parts otherwise). function model_release(render3d_st: mut Render3dState, m: Model) -> void { if m == null { return } gltf_cached_forget(render3d_st, m) if m.prims != null { for i in 0 .. len(m.prims) { let pr = m.prims[i] gltf_tex_unref(render3d_st, pr.diff); gltf_tex_unref(render3d_st, pr.nrm); gltf_tex_unref(render3d_st, pr.arm) if pr.mesh != null { mesh_release(render3d_st, pr.mesh) } if pr.name != null { free(pr.name) } free(pr) } free(m.prims) } skin_free(m.skin) free(m) } # a mesh and what it holds: its buffers (their handles given back), its layout and buffer lists function mesh_release(render3d_st: mut Render3dState, me: Mesh) -> void { gpu_mesh_free(render3d_st, me) if me.attrs != null { free(me.attrs) } if me.vbufs != null { free(me.vbufs) } free(me) }