8.19.53. Dynamic fonts

Dear ImGui 1.92 reworked font handling to re-rasterize on demand: changing a font’s scale no longer bilinear-stretches a fixed-size bitmap, it draws crisp glyphs at the requested pixel size. dasImgui exposes that through two surfaces.

The whole-frame global scale lives on the style:

GetStyle().FontScaleMain = 1.5f   // every glyph this frame is 1.5x

FontScaleMain is the 1.92 replacement for the old io.FontGlobalScale and the removed SetWindowFontScale — set it before any text is submitted and the entire frame scales.

The per-push pixel size lives on the with_font wrapper, which now forwards a size argument to PushFont:

let f = GetFont()
with_font(f, 16.0f) { text(SIZE_16, (text = "small")) }
with_font(f, 32.0f) { text(SIZE_32, (text = "large")) }

So the same font renders at several sizes in one frame. size = 0.0f (the default) keeps the current size, so with_font(f) { ... } stays a pure font swap — existing call sites are unchanged.

Source: modules/dasImgui/examples/tutorial/dynamic_fonts.das.

8.19.53.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_scope_builtin
 19require imgui/imgui_visual_aids
 20require daslib/safe_addr
 21
 22// =============================================================================
 23// TUTORIAL: dynamic_fonts — imgui 1.92 dynamic-font scaling, two levers.
 24//
 25// imgui 1.92 reworked fonts to re-rasterize on demand: changing a font's
 26// scale no longer bilinear-stretches a fixed bitmap, it draws crisp glyphs at
 27// the requested pixel size. The boost layer exposes that through two surfaces:
 28//
 29//   GetStyle().FontScaleMain = s        — whole-frame global scale. The 1.92
 30//                                          replacement for io.FontGlobalScale and
 31//                                          the removed SetWindowFontScale. Set it
 32//                                          before submitting any text.
 33//
 34//   with_font(font, size) { ... }        — per-push pixel size. The wrapper now
 35//                                          forwards `size` to PushFont, so one
 36//                                          font renders at several sizes in a
 37//                                          single frame. `size = 0.0f` (default)
 38//                                          keeps the current size, so
 39//                                          with_font(font) { ... } stays a pure
 40//                                          font swap.
 41//
 42// STANDALONE: daslang.exe modules/dasImgui/examples/tutorial/dynamic_fonts.das
 43// LIVE:       daslang-live modules/dasImgui/examples/tutorial/dynamic_fonts.das
 44// =============================================================================
 45
 46var private g_global_scale : float = 1.0f
 47
 48[export]
 49def init() {
 50    live_create_window("dasImgui dynamic_fonts tutorial", 820, 560)
 51    live_imgui_init(live_window)
 52    let io & = unsafe(GetIO())
 53    GetStyle().FontScaleMain = 1.2
 54}
 55
 56[export]
 57def update() {
 58    if (!live_begin_frame()) return
 59    begin_frame()
 60
 61    ImGui_ImplGlfw_NewFrame()
 62    apply_synth_io_override()
 63    NewFrame()
 64
 65    // FontScaleMain is the per-frame global scale; the slider below feeds it.
 66    // Assign it before any text is submitted so the whole frame picks it up.
 67    GetStyle().FontScaleMain = g_global_scale
 68
 69    SetNextWindowPos(ImVec2(40.0f, 40.0f), ImGuiCond.Always)
 70    SetNextWindowSize(ImVec2(740.0f, 480.0f), ImGuiCond.Always)
 71    window(DF_WIN, (text = "dynamic_fonts", closable = false,
 72                    flags = ImGuiWindowFlags.None)) {
 73        text("imgui 1.92 re-rasterizes fonts on demand - scaling stays crisp.")
 74        separator()
 75
 76        // ---- Lever 1: whole-frame global scale ----
 77        text("Drag to rescale every glyph this frame (FontScaleMain):")
 78        edit_slider_float(safe_addr(g_global_scale),
 79            (id = "GLOBAL_SCALE", text = "global scale", v_min = 0.5f, v_max = 2.5f))
 80        separator()
 81
 82        // ---- Lever 2: per-push size via with_font(font, size) ----
 83        text("with_font(font, size) - one font, three sizes, one frame:")
 84        let f = GetFont()
 85        with_font(f, 16.0f) {
 86            text(SIZE_16, (text = "16 px - with_font(f, 16.0f)"))
 87        }
 88        with_font(f, 24.0f) {
 89            text(SIZE_24, (text = "24 px - with_font(f, 24.0f)"))
 90        }
 91        with_font(f, 32.0f) {
 92            text(SIZE_32, (text = "32 px - with_font(f, 32.0f)"))
 93        }
 94        separator()
 95
 96        with_font(f) {
 97            text(SWAP_ONLY, (text = "with_font(f) with no size - pure swap, size kept"))
 98        }
 99    }
100
101    end_of_frame()
102    Render()
103    var w, h : int
104    live_get_framebuffer_size(w, h)
105    glViewport(0, 0, w, h)
106    glClearColor(0.10f, 0.10f, 0.12f, 1.0f)
107    glClear(GL_COLOR_BUFFER_BIT)
108    live_imgui_render()
109
110    live_end_frame()
111}
112
113[export]
114def shutdown() {
115    live_imgui_shutdown()
116    live_destroy_window()
117}
118
119[export]
120def main() {
121    init()
122    while (!exit_requested()) {
123        update()
124        maybe_collect_gc()
125    }
126    shutdown()
127}

8.19.53.1.1. Requires

Same baseline as the other with_* wrappers — with_font is already in imgui/imgui_scope_builtin (re-exported by imgui/imgui_boost_v2). The slider that feeds FontScaleMain uses the edit_* external-binding rail plus daslib/safe_addr.

8.19.53.1.2. Behaviour

  • FontScaleMain applies to the whole frame. Assign it once, before submitting widgets; it is not a stack like the with_* wrappers.

  • with_font(font, size) scopes to its block exactly: PushFont(font, size) on entry, PopFont() on exit. Pass size = 0.0f to re-use the current size and only swap the font face.

  • Because 1.92 rasterizes per requested size, a large FontScaleMain or a large with_font size produces sharp glyphs rather than a magnified bitmap.

8.19.53.1.3. Migration note

Pre-1.92 code that called io.FontGlobalScale = s or SetWindowFontScale(s) should move to GetStyle().FontScaleMain = s. SetWindowFontScale no longer exists; the per-window scale is gone in favour of the global style scale plus per-push with_font sizes.

8.19.53.1.4. Standalone vs live

Same convention as the other tutorials. daslang.exe runs the demo headlessly to frame N; daslang-live keeps the window open and reloads on source edits — drag the slider to watch the whole frame rescale live.

See also

Full source: modules/dasImgui/examples/tutorial/dynamic_fonts.das

Integration test: modules/dasImgui/tests/test_dynamic_font_scale.das.

Boost macros — the macro layer.