GpuBuffer (gpu_buffer_new/free), GpuTexture, GpuFramebuffer, GpuRenderbuffer, Target (target_new/free), Model (gltf_load / model_release), Mesh (gpu_mesh_new / gpu_mesh_free, mesh_release), Actor (actor_new / actor_release) and SkinClone (skin_clone / skin_clone_free), for ludic deps --resources. Compiled (steady). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
88 lines
3.6 KiB
Text
88 lines
3.6 KiB
Text
# 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).
|
|
@releases(Model)
|
|
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
|
|
@releases(Mesh)
|
|
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)
|
|
}
|