8.18.1.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.18.1.53.1. Walkthrough

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

8.18.1.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.18.1.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.18.1.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.18.1.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.