# render3d_image.ludic - pictures for the render3d backend: a texture by path (its sRGB bytes as they # are, clamped at its edges, loaded again when the file changes) and a cell of a named atlas module ludic_ui function r3u_tex(render3d_st: mut Render3dState, ui_st: mut UiState, path: string) -> int { for i in 0 .. len(ui_st.r3u_tex_paths) { if ui_st.r3u_tex_paths[i] == path { return r3u_tex_fresh(render3d_st, ui_st, i) } } push(ui_st.r3u_tex_paths, path) push(ui_st.r3u_tex_ids, r3u_tex_load(render3d_st, path)) push(ui_st.r3u_tex_sizes, Fs.size(path)) push(ui_st.r3u_tex_seen, r3u_now()) return ui_st.r3u_tex_ids[len(ui_st.r3u_tex_ids) - 1] } # a picture is looked at again every half second: a file that has changed (or that was not there, # and is now) is loaded again, so an of a photograph written over the old one shows the new one function r3u_tex_fresh(render3d_st: mut Render3dState, ui_st: mut UiState, i: int) -> int { let now = r3u_now() if now - ui_st.r3u_tex_seen[i] < 0.5 and now >= ui_st.r3u_tex_seen[i] { return ui_st.r3u_tex_ids[i] } ui_st.r3u_tex_seen[i] = now let size = Fs.size(ui_st.r3u_tex_paths[i]) if size == ui_st.r3u_tex_sizes[i] and (ui_st.r3u_tex_ids[i] != 0 or size < 0) { return ui_st.r3u_tex_ids[i] } if ui_st.r3u_tex_ids[i] != 0 { gpu_tex_free(render3d_st, ui_st.r3u_tex_ids[i]) } ui_st.r3u_tex_ids[i] = r3u_tex_load(render3d_st, ui_st.r3u_tex_paths[i]) ui_st.r3u_tex_sizes[i] = size return ui_st.r3u_tex_ids[i] } # the interface is drawn in sRGB, and a picture's bytes are sRGB, so they are taken as they are # (not decoded to linear, which would darken it); clamped at its edges function r3u_tex_load(render3d_st: mut Render3dState, path: string) -> int { let t = tex_load(render3d_st, path, false) if t != 0 { gpu_tex_bind(render3d_st, GPU_TEX2D, t) gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) } return t } # a picture the program has written again, loaded again the next time it is drawn export function ui_image_reload(ui_st: mut UiState, path: string) -> void { for i in 0 .. len(ui_st.r3u_tex_paths) { if ui_st.r3u_tex_paths[i] == path { ui_st.r3u_tex_seen[i] = -1000000.0 ui_st.r3u_tex_sizes[i] = -2 } } } function r3u_image(render3d_st: mut Render3dState, ui_st: mut UiState, src: string, x: float, y: float, w: float, h: float, c: int, a: float) -> void { for k in 0 .. len(ui_st.r3u_atlas) { # icon:NAME, the atlas and the name read in place let p = ui_st.r3u_atlas[k] if len(src) > len(p) and src[len(p)] == 58 and sat(src, 0, p) { r3u_cell(render3d_st, ui_st, k, src, len(p) + 1, x, y, w, h, c, a) return } } let t = r3u_tex(render3d_st, ui_st, src) if t != 0 { ov_sub(render3d_st, t, int(x), int(y), int(w), int(h), 0.0, 0.0, 1.0, 1.0, r3u_r(c), r3u_g(c), r3u_b(c), a) } } # a picture's own size, for object-fit; an atlas cell is drawn square function r3u_image_w(render3d_st: mut Render3dState, ui_st: mut UiState, src: string) -> float { if r3u_is_cell(ui_st, src) { return 1.0 } return float(tex_width(render3d_st, r3u_tex(render3d_st, ui_st, src))) } function r3u_image_h(render3d_st: mut Render3dState, ui_st: mut UiState, src: string) -> float { if r3u_is_cell(ui_st, src) { return 1.0 } return float(tex_height(render3d_st, r3u_tex(render3d_st, ui_st, src))) } function r3u_is_cell(ui_st: UiState, src: string) -> bool { for k in 0 .. len(ui_st.r3u_atlas) { let p = ui_st.r3u_atlas[k] if len(src) > len(p) and sat(src, 0, p) and src[len(p)] == 58 { return true } } return false } # the cell whose name is src from `at` on (compared where it stands), or its number function r3u_cell(render3d_st: mut Render3dState, ui_st: mut UiState, k: int, src: string, at: int, x: float, y: float, w: float, h: float, c: int, a: float) -> void { let names = ui_st.r3u_atlas_names[k] let n = len(src) - at var idx = -1 for i in 0 .. len(names) { if len(names[i]) == n and sat(src, at, names[i]) { idx = i } } if idx < 0 and n > 0 and src[at] >= 48 and src[at] <= 57 { idx = int(el_num_in(src, at, len(src))) } if idx < 0 { @alloc_ok("only when a template is wrong: a broken screen, never a working one") ui_err(ui_st, `{src}: the atlas has no such picture`) return } let cols = ui_st.r3u_atlas_cols[k] let rows = ui_st.r3u_atlas_rows[k] let cx = idx % cols let cy = idx / cols let u0 = float(cx) / float(cols) let v0 = float(cy) / float(rows) let s = Math.min(w, h) ov_sub(render3d_st, ui_st.r3u_atlas_tex[k], int(x + (w - s) / 2.0), int(y + (h - s) / 2.0), int(s), int(s), u0, v0, u0 + 1.0 / float(cols), v0 + 1.0 / float(rows), r3u_r(c), r3u_g(c), r3u_b(c), a) }