8.19.54. Texture references
Dear ImGui 1.92 reworked texture handling: the raw ImTextureID you used to
hand to image() is now an ImTextureRef. This tutorial shows the full
path for displaying your own image — decode a PNG, upload it to a GL
texture, and pass that texture through an ImTextureRef:
var private g_tex : uint = 0u // GL texture name
let PICTURE_PATH = "{get_das_root()}/modules/dasImgui/doc/source/_static/icons/cube.png"
// 1. decode a PNG to RGBA pixels (dasStbImage)
var img : Image
let (loaded, err) = img->load(PICTURE_PATH, 4) // 4 channels => RGBA
// 2. upload to a GL texture
glGenTextures(1, safe_addr(g_tex))
glBindTexture(GL_TEXTURE_2D, g_tex)
glTexImage2D(GL_TEXTURE_2D, 0, int(GL_RGBA), img.width, img.height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, unsafe(addr(img.bytes[0])))
// 3. wrap the GL texture name in an ImTextureRef
unsafe {
var ref : ImTextureRef
ref._TexID = uint64(g_tex)
// 4. draw it
image(TR_PIC, (user_texture_id = ref,
size = float2(float(img.width), float(img.height))))
}
_TexID is the user slot of ImTextureRef (an ImTextureID == the GL
texture name here). With _TexData left null, the backend treats it as a
user-managed texture and binds the GL id directly — that is how you pass your
own texture in 1.92.
The demo loads one of the repo’s icon PNGs as a stand-in for an application
texture; point PICTURE_PATH at any image of your own.
Source: modules/dasImgui/examples/tutorial/texture_ref.das.
8.19.54.1. Walkthrough
1options gen2
2options _comment_hygiene = true
3options gc
4
5require imgui
6require imgui_app
7require opengl/opengl_boost
8require live/glfw_live
9require live/live_api
10require live/live_commands
11require live/live_vars
12require live_host
13require imgui/imgui_live
14require imgui/imgui_boost_runtime
15require imgui/imgui_boost_v2
16require imgui/imgui_widgets_builtin
17require imgui/imgui_containers_builtin
18require imgui/imgui_visual_aids
19require stbimage/stbimage_boost
20require daslib/safe_addr
21
22// =============================================================================
23// TUTORIAL: texture_ref — display YOUR OWN texture via the imgui 1.92 ImTextureRef.
24//
25// 1.92 replaced the raw `ImTextureID` handle with `ImTextureRef`. To show a real
26// image (not the font atlas), the steps are:
27//
28// 1. decode a PNG to RGBA pixels — dasStbImage `Image::load(path, 4)`
29// 2. upload to a GL texture — glGenTextures + glTexImage2D
30// 3. wrap the GL handle — var ref : ImTextureRef; ref._TexID = handle
31// 4. draw it — image(IDENT, (user_texture_id = ref, ...))
32//
33// `_TexID` is the user slot of ImTextureRef (an ImTextureID == the GL texture name
34// here). With `_TexData` left null, the backend treats it as a user-managed texture
35// and binds the GL id directly — that is how you pass your own texture in 1.92.
36//
37// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/texture_ref.das
38// LIVE: daslang-live modules/dasImgui/examples/tutorial/texture_ref.das
39// =============================================================================
40
41// One of the repo's icon PNGs stands in for an application texture.
42let PICTURE_PATH = "{get_das_root()}/modules/dasImgui/doc/source/_static/icons/cube.png"
43
44var private g_tex : uint = 0u // GL texture name
45var private g_tex_w = 0
46var private g_tex_h = 0
47var private g_load_err = ""
48
49def private upload_picture() {
50 var img : Image
51 let (ok, err) = img->load(PICTURE_PATH, 4) // request 4 channels => RGBA
52 if (!ok) {
53 g_load_err = "load failed: {err}"
54 return
55 }
56 g_tex_w = img.width
57 g_tex_h = img.height
58 glGenTextures(1, safe_addr(g_tex))
59 glBindTexture(GL_TEXTURE_2D, g_tex)
60 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
61 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
62 glTexImage2D(GL_TEXTURE_2D, 0, int(GL_RGBA), img.width, img.height, 0,
63 GL_RGBA, GL_UNSIGNED_BYTE, unsafe(addr(img.bytes[0])))
64}
65
66// Build the 1.92 image() handle from the GL texture name. _TexID is the user
67// slot (ImTextureID == ImU64 == uint64 here); _TexData stays null, so the
68// backend binds the GL id directly as a user-managed texture.
69def private texture_ref() : ImTextureRef {
70 unsafe {
71 var ref : ImTextureRef
72 ref._TexID = uint64(g_tex)
73 return ref
74 }
75}
76
77[export]
78def init() {
79 live_create_window("dasImgui texture_ref tutorial", 820, 520)
80 live_imgui_init(live_window)
81 let io & = unsafe(GetIO())
82 GetStyle().FontScaleMain = 1.3
83 // GL context is live now — decode + upload the picture once.
84 upload_picture()
85}
86
87[export]
88def update() {
89 if (!live_begin_frame()) return
90 begin_frame()
91
92 ImGui_ImplGlfw_NewFrame()
93 apply_synth_io_override()
94 NewFrame()
95
96 SetNextWindowPos(ImVec2(40.0f, 40.0f), ImGuiCond.Always)
97 SetNextWindowSize(ImVec2(740.0f, 440.0f), ImGuiCond.Always)
98 window(TR_WIN, (text = "texture_ref", closable = false,
99 flags = ImGuiWindowFlags.None)) {
100 if (g_tex == 0u) {
101 text(TR_ERR, (text = "no texture: {g_load_err}"))
102 } else {
103 text("A real PNG, decoded + uploaded to a GL texture, shown through")
104 text("an ImTextureRef whose _TexID is the GL texture name.")
105 separator()
106
107 // Full image, then a tinted + bordered copy — same texture reused.
108 // the named-tuple argument mints an ImTextureRef temp — a handled-type
109 // local, unsafe-scoped like any minted ImTextureRef
110 unsafe {
111 image(TR_PIC, (user_texture_id = texture_ref(),
112 size = float2(float(g_tex_w), float(g_tex_h)),
113 uv0 = float2(0.0f, 0.0f),
114 uv1 = float2(1.0f, 1.0f),
115 tint_col = float4(1.0f, 1.0f, 1.0f, 1.0f),
116 border_col = float4(0.6f, 0.6f, 0.6f, 1.0f)))
117 }
118 same_line(TR_GAP)
119 unsafe {
120 image(TR_TINT, (user_texture_id = texture_ref(),
121 size = float2(float(g_tex_w), float(g_tex_h)),
122 uv0 = float2(0.0f, 0.0f),
123 uv1 = float2(1.0f, 1.0f),
124 tint_col = float4(0.4f, 0.8f, 1.0f, 1.0f),
125 border_col = float4(1.0f, 1.0f, 1.0f, 1.0f)))
126 }
127 separator()
128 text("{g_tex_w}x{g_tex_h}. Swap PICTURE_PATH / _TexID for your own texture.")
129 }
130 }
131
132 end_of_frame()
133 Render()
134 var w, h : int
135 live_get_framebuffer_size(w, h)
136 glViewport(0, 0, w, h)
137 glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
138 glClear(GL_COLOR_BUFFER_BIT)
139 live_imgui_render()
140
141 live_end_frame()
142}
143
144[export]
145def shutdown() {
146 if (g_tex != 0u) {
147 glDeleteTextures(1, safe_addr(g_tex))
148 }
149 live_imgui_shutdown()
150 live_destroy_window()
151}
152
153[export]
154def main() {
155 init()
156 while (!exit_requested()) {
157 update()
158 maybe_collect_gc()
159 }
160 shutdown()
161}
8.19.54.1.1. Requires
stbimage/stbimage_boost for the PNG decode (the Image type and
Image::load), opengl/opengl_boost for the GL upload (already pulled in
by the live backend), and daslib/safe_addr for the texture-name address.
8.19.54.1.2. Behaviour
The picture is decoded + uploaded once in init (the GL context is live
after live_imgui_init), and the texture name is kept in a module global.
Each frame image() draws it twice through a freshly built ImTextureRef —
once plain, once tinted — to show the same texture reused while tint_col
varies per call. (border_col is echoed into ImageState for snapshot
assertions only; ImGui’s Image() takes no per-call border, it comes from the
ImGuiCol_Border style.) The texture is freed with glDeleteTextures on
shutdown.
8.19.54.1.3. Migration note
Pre-1.92 code passed an ImTextureID straight to image(). In 1.92 the
argument is an ImTextureRef; put your texture handle in ref._TexID (the
user slot) and leave ref._TexData null. The font atlas moved the same way:
io.Fonts.TexID → io.Fonts.TexRef (an ImTextureRef), gated on
io.Fonts.TexData != null.
See also
Full source: modules/dasImgui/examples/tutorial/texture_ref.das
Related: tree_node_ex + image — image() against the font
atlas, alongside tree_node_ex.