Просмотр исходного кода

Merge pull request #1294 from floooh/imgui-1.92.0

Port sokol_imgui.h to Imgui 1.92.0
Andre Weissflog 3 недель назад
Родитель
Сommit
6bfe9e0ea7
4 измененных файлов с 848 добавлено и 594 удалено
  1. 47 0
      CHANGELOG.md
  2. 1 1
      README.md
  3. 424 355
      util/sokol_gfx_imgui.h
  4. 376 238
      util/sokol_imgui.h

+ 47 - 0
CHANGELOG.md

@@ -1,5 +1,52 @@
 ## Updates
 
+### 29-Jun-2025
+
+The Dear ImGui backend in sokol_imgui.h has been updated for Dear ImGui 1.92.0.
+
+This may be a breaking change if:
+
+- you are attaching your own fonts to Dear ImGui
+- you use the C bindings and render images in the UI
+- you were calling the sokol_imgui.h functions `simgui_create_fonts_texture()`
+  and `simgui_destroy_fonts_texture()` (those are no longer necessary and have
+  been removed)
+
+If you had been attaching your own fonts to Dear ImGui, remove any code which
+explicitly creates a sokol-gfx font texture image object. Specifically:
+
+- do not call the Dear ImGui `GetTexDataAsRGBA32()` method
+- do not call `sg_make_image()` with the receiced data
+- do not set `Fonts->TexID` on the Dear ImGui IO object
+
+If you are using Dear ImGui C bindings, you'll need to fix the places where
+the `igImage()` function is called. This now takes an `ImTextureRef` struct
+instead of an `ImTextureID` (in C++ this is not a problem since the ImTextureRef
+is automatically constructed on the fly from the ImTextureID, but in C you'll
+need to do this by hand, e.g. change:
+
+```c
+igImage(my_tex_id, ...);
+```
+...to:
+```c
+igImage((ImTextureRef){ ._TexID=my_tex_id}, ...);
+```
+Dear Bindings is currently missing a helper function for this conversion, also
+see: https://github.com/dearimgui/dear_bindings/issues/99
+
+...and a drive-by update in `sokol_gfx_imgui.h`: when used from C, the function
+prefix of the C bindings can now be configured via the macro `SOKOL_GFX_IMGUI_CPREFIX`.
+The default prefix is `ig` which makes it compatible with the bindings from
+https://github.com/floooh/dcimgui (which are the recommended C bindings for use
+with the sokol headers).
+
+Related PRs:
+
+- the actual changes: https://github.com/floooh/sokol/pull/1294
+- fixes in the v6502r project (custom fonts): https://github.com/floooh/v6502r/pull/33
+- various fixes in the sokol-samples: https://github.com/floooh/sokol-samples/pull/173
+
 ### 28-Jun-2025
 
 sokol_gfx.h d3d11: `#include` statements are now supported when directly passing HLSL

+ 1 - 1
README.md

@@ -6,7 +6,7 @@
 
 # Sokol
 
-[**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**24-May-2025** sokol_gfx.h: the Compute Milestone 2 update
+[**See what's new**](https://github.com/floooh/sokol/blob/master/CHANGELOG.md) (**29-Jun-2025** sokol_imgui.h: updated for Dear ImGui 1.92.0 (some breaking changes!)
 
 [![Build](/../../actions/workflows/main.yml/badge.svg)](/../../actions/workflows/main.yml) [![Bindings](/../../actions/workflows/gen_bindings.yml/badge.svg)](/../../actions/workflows/gen_bindings.yml) [![build](https://github.com/floooh/sokol-zig/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-zig/actions/workflows/main.yml) [![build](https://github.com/floooh/sokol-nim/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-nim/actions/workflows/main.yml) [![Odin](https://github.com/floooh/sokol-odin/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-odin/actions/workflows/main.yml)[![Rust](https://github.com/floooh/sokol-rust/actions/workflows/main.yml/badge.svg)](https://github.com/floooh/sokol-rust/actions/workflows/main.yml)[![Dlang](https://github.com/kassane/sokol-d/actions/workflows/build.yml/badge.svg)](https://github.com/kassane/sokol-d/actions/workflows/build.yml)[![C3](https://github.com/floooh/sokol-c3/actions/workflows/build.yml/badge.svg)](https://github.com/floooh/sokol-c3/actions/workflows/build.yml)
 

Разница между файлами не показана из-за своего большого размера
+ 424 - 355
util/sokol_gfx_imgui.h


+ 376 - 238
util/sokol_imgui.h

@@ -229,6 +229,21 @@
 
         simgui_shutdown()
 
+    ON ATTACHING YOUR OWN FONTS
+    ===========================
+    Since Dear ImGui 1.92.0, using using non-default fonts has been greatly simplified:
+
+    First, call `simgui_setup()` with the `.no_default_font` so that
+    sokol_imgui.h skips adding the default font.
+
+    ...then simply call `AddFontDefault()` or `AddFontFromMemoryTTF()` on
+    the Dear ImGui IO object.
+
+    Do *NOT*:
+        - call the deprecated `GetTexDataAsRGBA32()` function
+        - create a sokol-gfx image object for the font
+        - set the `Font->TexID` on the ImGui IO object
+
 
     ON USER-PROVIDED IMAGES AND SAMPLERS
     ====================================
@@ -264,6 +279,21 @@
         sg_image img = simgui_image_from_imtextureid(imtex_id);
         sg_sampler smp = simgui_sampler_from_imtextureid(imtex_id);
 
+    NOTE on C bindings since 1.92.0:
+
+        Since Dear ImGui v1.92.0 the ImGui::Image function takes an
+        ImTextureRef object instead of ImTextureID. In C++ this doesn't
+        require a code change since the ImTextureRef is automatically constructed
+        from the ImTextureID.
+
+        In C this doesn't work and you need to explicitly create an
+        ImTextureRef struct, for instance:
+
+            igImage((ImTextureRef){ ._TexID = my_tex_id }, ...);
+
+        Currently Dear Bindings is missing a wrapper function for this,
+        also see: https://github.com/dearimgui/dear_bindings/issues/99
+
 
     MEMORY ALLOCATION OVERRIDE
     ==========================
@@ -492,10 +522,12 @@ typedef struct simgui_font_tex_desc_t {
 SOKOL_IMGUI_API_DECL void simgui_setup(const simgui_desc_t* desc);
 SOKOL_IMGUI_API_DECL void simgui_new_frame(const simgui_frame_desc_t* desc);
 SOKOL_IMGUI_API_DECL void simgui_render(void);
+
 SOKOL_IMGUI_API_DECL uint64_t simgui_imtextureid(sg_image img);
 SOKOL_IMGUI_API_DECL uint64_t simgui_imtextureid_with_sampler(sg_image img, sg_sampler smp);
 SOKOL_IMGUI_API_DECL sg_image simgui_image_from_imtextureid(uint64_t imtex_id);
 SOKOL_IMGUI_API_DECL sg_sampler simgui_sampler_from_imtextureid(uint64_t imtex_id);
+
 SOKOL_IMGUI_API_DECL void simgui_add_focus_event(bool focus);
 SOKOL_IMGUI_API_DECL void simgui_add_mouse_pos_event(float x, float y);
 SOKOL_IMGUI_API_DECL void simgui_add_touch_pos_event(float x, float y);
@@ -505,13 +537,12 @@ SOKOL_IMGUI_API_DECL void simgui_add_key_event(int imgui_key, bool down);
 SOKOL_IMGUI_API_DECL void simgui_add_input_character(uint32_t c);
 SOKOL_IMGUI_API_DECL void simgui_add_input_characters_utf8(const char* c);
 SOKOL_IMGUI_API_DECL void simgui_add_touch_button_event(int mouse_button, bool down);
+
 #if !defined(SOKOL_IMGUI_NO_SOKOL_APP)
 SOKOL_IMGUI_API_DECL bool simgui_handle_event(const sapp_event* ev);
 SOKOL_IMGUI_API_DECL int simgui_map_keycode(sapp_keycode keycode);  // returns ImGuiKey_*
 #endif
 SOKOL_IMGUI_API_DECL void simgui_shutdown(void);
-SOKOL_IMGUI_API_DECL void simgui_create_fonts_texture(const simgui_font_tex_desc_t* desc);
-SOKOL_IMGUI_API_DECL void simgui_destroy_fonts_texture(void);
 
 #ifdef __cplusplus
 } // extern "C"
@@ -519,7 +550,6 @@ SOKOL_IMGUI_API_DECL void simgui_destroy_fonts_texture(void);
 // reference-based equivalents for C++
 inline void simgui_setup(const simgui_desc_t& desc) { return simgui_setup(&desc); }
 inline void simgui_new_frame(const simgui_frame_desc_t& desc) { return simgui_new_frame(&desc); }
-inline void simgui_create_fonts_texture(const simgui_font_tex_desc_t& desc) { return simgui_create_fonts_texture(&desc); }
 
 #endif
 #endif /* SOKOL_IMGUI_INCLUDED */
@@ -592,9 +622,6 @@ typedef struct {
     float cur_dpi_scale;
     sg_buffer vbuf;
     sg_buffer ibuf;
-    sg_image font_img;
-    sg_sampler font_smp;
-    sg_image def_img;       // used as default image for user images
     sg_sampler def_smp;     // used as default sampler for user images
     sg_shader def_shd;
     sg_pipeline def_pip;
@@ -2328,8 +2355,7 @@ static simgui_desc_t _simgui_desc_defaults(const simgui_desc_t* desc) {
     return res;
 }
 
-#if !defined(SOKOL_IMGUI_NO_SOKOL_APP)
-static ImGuiPlatformIO* _simgui_get_platform_io(void) {
+static ImGuiPlatformIO* _simgui_imgui_get_platform_io(void) {
     #if defined(__cplusplus)
         return &ImGui::GetPlatformIO();
     #else
@@ -2342,9 +2368,8 @@ static ImGuiPlatformIO* _simgui_get_platform_io(void) {
         #endif
     #endif
 }
-#endif
 
-static ImGuiIO* _simgui_get_io(void) {
+static ImGuiIO* _simgui_imgui_get_io(void) {
     #if defined(__cplusplus)
         return &ImGui::GetIO();
     #else
@@ -2358,6 +2383,268 @@ static ImGuiIO* _simgui_get_io(void) {
     #endif
 }
 
+static void _simgui_imgui_newframe(void) {
+    #if defined(__cplusplus)
+        ImGui::NewFrame();
+    #else
+        _SIMGUI_CFUNC(NewFrame)();
+    #endif
+}
+
+static void _simgui_imgui_create_context(void) {
+    #if defined(__cplusplus)
+        ImGui::CreateContext();
+    #else
+        _SIMGUI_CFUNC(CreateContext)(0);
+    #endif
+}
+
+static void _simgui_imgui_destroy_context(void) {
+    #if defined(__cplusplus)
+        ImGui::DestroyContext();
+    #else
+        _SIMGUI_CFUNC(DestroyContext)(0);
+    #endif
+}
+
+static void _simgui_imgui_style_colors_dark(void) {
+    #if defined(__cplusplus)
+        ImGui::StyleColorsDark();
+    #else
+        _SIMGUI_CFUNC(StyleColorsDark)(_SIMGUI_CFUNC(GetStyle)());
+    #endif
+}
+
+static void _simgui_io_add_font_default(ImGuiIO* io) {
+    #if defined(__cplusplus)
+        io->Fonts->AddFontDefault();
+    #else
+        ImFontAtlas_AddFontDefault(io->Fonts, 0);
+    #endif
+}
+
+static void _simgui_io_add_focus_event(ImGuiIO* io, bool focus) {
+    #if defined(__cplusplus)
+        io->AddFocusEvent(focus);
+    #else
+        ImGuiIO_AddFocusEvent(io, focus);
+    #endif
+}
+
+static void _simgui_io_add_mouse_source_event(ImGuiIO* io, ImGuiMouseSource source) {
+    #if defined(__cplusplus)
+        io->AddMouseSourceEvent(source);
+    #else
+        ImGuiIO_AddMouseSourceEvent(io, source);
+    #endif
+}
+
+static void _simgui_io_add_mouse_pos_event(ImGuiIO* io, float x, float y) {
+    #if defined(__cplusplus)
+        io->AddMousePosEvent(x, y);
+    #else
+        ImGuiIO_AddMousePosEvent(io, x, y);
+    #endif
+}
+
+static void _simgui_io_add_mouse_button_event(ImGuiIO* io, int mouse_button, bool down) {
+    #if defined(__cplusplus)
+        io->AddMouseButtonEvent(mouse_button, down);
+    #else
+        ImGuiIO_AddMouseButtonEvent(io, mouse_button, down);
+    #endif
+}
+
+static void _simgui_io_add_mouse_wheel_event(ImGuiIO* io, float x, float y) {
+    #if defined(__cplusplus)
+        io->AddMouseWheelEvent(x, y);
+    #else
+        ImGuiIO_AddMouseWheelEvent(io, x, y);
+    #endif
+}
+
+static void _simgui_io_add_key_event(ImGuiIO* io, ImGuiKey imgui_key, bool down) {
+    #if defined(__cplusplus)
+        io->AddKeyEvent(imgui_key, down);
+    #else
+        ImGuiIO_AddKeyEvent(io, imgui_key, down);
+    #endif
+}
+
+static void _simgui_io_add_input_character(ImGuiIO* io, uint32_t c) {
+    #if defined(__cplusplus)
+        io->AddInputCharacter(c);
+    #else
+        ImGuiIO_AddInputCharacter(io, c);
+    #endif
+}
+
+static void _simgui_io_add_input_characters_utf8(ImGuiIO* io, const char* c) {
+    #if defined(__cplusplus)
+        io->AddInputCharactersUTF8(c);
+    #else
+        ImGuiIO_AddInputCharactersUTF8(io, c);
+    #endif
+}
+
+#if !defined(SOKOL_IMGUI_NO_SOKOL_APP)
+static ImGuiMouseCursor _simgui_imgui_get_mouse_cursor(void) {
+    #if defined(__cplusplus)
+        return ImGui::GetMouseCursor();
+    #else
+        return _SIMGUI_CFUNC(GetMouseCursor)();
+    #endif
+}
+#endif
+
+static ImDrawList* _simgui_imdrawlist_at(ImDrawData* draw_data, int cl_index) {
+    #if defined(__cplusplus)
+        return draw_data->CmdLists[cl_index];
+    #else
+        return draw_data->CmdLists.Data[cl_index];
+    #endif
+}
+
+static ImTextureID _simgui_imtexturedata_gettexid(ImTextureData* tex) {
+    #if defined(__cplusplus)
+        return tex->GetTexID();
+    #else
+        return ImTextureData_GetTexID(tex);
+    #endif
+}
+
+static void _simgui_imtexturedata_settexid(ImTextureData* tex, ImTextureID tex_id) {
+    #if defined(__cplusplus)
+        tex->SetTexID(tex_id);
+    #else
+        ImTextureData_SetTexID(tex, tex_id);
+    #endif
+}
+
+static void _simgui_imtexturedata_setstatus(ImTextureData* tex, ImTextureStatus status) {
+    #if defined(__cplusplus)
+        tex->SetStatus(status);
+    #else
+        ImTextureData_SetStatus(tex, status);
+    #endif
+}
+
+static void* _simgui_imtexturedata_getpixels(ImTextureData* tex) {
+    #if defined(__cplusplus)
+        return tex->GetPixels();
+    #else
+        return ImTextureData_GetPixels(tex);
+    #endif
+}
+
+static int _simgui_imtexturedata_getsizeinbytes(ImTextureData* tex) {
+    #if defined(__cplusplus)
+        return tex->GetSizeInBytes();
+    #else
+        return ImTextureData_GetSizeInBytes(tex);
+    #endif
+}
+
+static ImTextureID _simgui_imdrawcmd_gettexid(ImDrawCmd* cmd) {
+    #if defined(__cplusplus)
+        return cmd->GetTexID();
+    #else
+        return ImDrawCmd_GetTexID(cmd);
+    #endif
+}
+
+static int _simgui_imdrawlist_cmd_buffer_size(ImDrawList* cl) {
+    #if defined(__cplusplus)
+        return cl->CmdBuffer.size();
+    #else
+        return cl->CmdBuffer.Size;
+    #endif
+}
+
+static int _simgui_imdrawlist_vtx_buffer_size(ImDrawList* cl) {
+    #if defined(__cplusplus)
+        return cl->VtxBuffer.size();
+    #else
+        return cl->VtxBuffer.Size;
+    #endif
+}
+
+static int _simgui_imdrawlist_idx_buffer_size(ImDrawList* cl) {
+    #if defined(__cplusplus)
+        return cl->IdxBuffer.size();
+    #else
+        return cl->IdxBuffer.Size;
+    #endif
+}
+
+static void _simgui_imgui_render(void) {
+    #if defined(__cplusplus)
+        ImGui::Render();
+    #else
+        _SIMGUI_CFUNC(Render)();
+    #endif
+}
+
+static ImDrawData* _simgui_imgui_get_draw_data(void) {
+    #if defined(__cplusplus)
+        return ImGui::GetDrawData();
+    #else
+        return _SIMGUI_CFUNC(GetDrawData)();
+    #endif
+}
+
+static void _simgui_destroy_texture(ImTextureData* tex) {
+    SOKOL_ASSERT(tex);
+    const sg_image img = simgui_image_from_imtextureid(_simgui_imtexturedata_gettexid(tex));
+    const sg_sampler smp = simgui_sampler_from_imtextureid(_simgui_imtexturedata_gettexid(tex));
+    sg_destroy_image(img);
+    sg_destroy_sampler(smp);
+    _simgui_imtexturedata_settexid(tex, ImTextureID_Invalid);
+    _simgui_imtexturedata_setstatus(tex, ImTextureStatus_Destroyed);
+}
+
+static void _simgui_update_texture(ImTextureData* tex) {
+    SOKOL_ASSERT(tex);
+    SOKOL_ASSERT(tex->Format == ImTextureFormat_RGBA32);
+    if (tex->Status == ImTextureStatus_WantCreate) {
+        // create new sokol-gfx texture
+        SOKOL_ASSERT(tex->TexID == 0);
+        sg_image_desc img_desc;
+        _simgui_clear(&img_desc, sizeof(img_desc));
+        img_desc.usage.dynamic_update = true;
+        img_desc.width = tex->Width;
+        img_desc.height = tex->Height;
+        img_desc.pixel_format = SG_PIXELFORMAT_RGBA8;
+        img_desc.label = "sokol-imgui-texture";
+        sg_image img = sg_make_image(&img_desc);
+
+        sg_sampler_desc smp_desc;
+        _simgui_clear(&smp_desc, sizeof(smp_desc));
+        smp_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE;
+        smp_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE;
+        smp_desc.min_filter = SG_FILTER_LINEAR;
+        smp_desc.mag_filter = SG_FILTER_LINEAR;
+        smp_desc.label = "sokol-imgui-sampler";
+        sg_sampler smp = sg_make_sampler(&smp_desc);
+
+        _simgui_imtexturedata_settexid(tex, simgui_imtextureid_with_sampler(img, smp));
+    }
+    if ((tex->Status == ImTextureStatus_WantCreate) || (tex->Status == ImTextureStatus_WantUpdates)) {
+        SOKOL_ASSERT(tex->TexID != 0);
+        const sg_image img = simgui_image_from_imtextureid(_simgui_imtexturedata_gettexid(tex));
+        sg_image_data img_data;
+        _simgui_clear(&img_data, sizeof(img_data));
+        img_data.subimage[0][0].ptr = _simgui_imtexturedata_getpixels(tex);
+        img_data.subimage[0][0].size = (size_t)_simgui_imtexturedata_getsizeinbytes(tex);
+        sg_update_image(img, &img_data);
+        _simgui_imtexturedata_setstatus(tex, ImTextureStatus_OK);
+    }
+    if ((tex->Status == ImTextureStatus_WantDestroy) && (tex->UnusedFrames > 0)) {
+        SOKOL_ASSERT(tex->TexID != 0);
+        _simgui_destroy_texture(tex);
+    }
+}
+
 // ██████  ██    ██ ██████  ██      ██  ██████
 // ██   ██ ██    ██ ██   ██ ██      ██ ██
 // ██████  ██    ██ ██████  ██      ██ ██
@@ -2385,29 +2672,21 @@ SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) {
     _simgui.indices.ptr = _simgui_malloc(_simgui.indices.size);
 
     // initialize Dear ImGui
-    #if defined(__cplusplus)
-        ImGui::CreateContext();
-        ImGui::StyleColorsDark();
-        ImGuiIO* io = _simgui_get_io();
-        if (!_simgui.desc.no_default_font) {
-            io->Fonts->AddFontDefault();
-        }
-    #else
-        _SIMGUI_CFUNC(CreateContext)(NULL);
-        _SIMGUI_CFUNC(StyleColorsDark)(_SIMGUI_CFUNC(GetStyle)());
-        ImGuiIO* io = _simgui_get_io();
-        if (!_simgui.desc.no_default_font) {
-            ImFontAtlas_AddFontDefault(io->Fonts, NULL);
-        }
-    #endif
+    _simgui_imgui_create_context();
+    _simgui_imgui_style_colors_dark();
+    ImGuiIO* io = _simgui_imgui_get_io();
+    if (!_simgui.desc.no_default_font) {
+        _simgui_io_add_font_default(io);
+    }
     io->IniFilename = _simgui.desc.ini_filename;
     io->ConfigMacOSXBehaviors = _simgui_is_osx();
-    io->BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
+    io->BackendRendererName = "sokol-imgui";
+    io->BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures;
     #if !defined(SOKOL_IMGUI_NO_SOKOL_APP)
         if (!_simgui.desc.disable_set_mouse_cursor) {
             io->BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
         }
-        ImGuiPlatformIO* pio = _simgui_get_platform_io();
+        ImGuiPlatformIO* pio = _simgui_imgui_get_platform_io();
         pio->Platform_SetClipboardTextFn = _simgui_set_clipboard;
         pio->Platform_GetClipboardTextFn = _simgui_get_clipboard;
     #endif
@@ -2557,90 +2836,27 @@ SOKOL_API_IMPL void simgui_setup(const simgui_desc_t* desc) {
     def_sampler_desc.label = "sokol-imgui-default-sampler";
     _simgui.def_smp = sg_make_sampler(&def_sampler_desc);
 
-    // a default user image
-    static uint32_t def_pixels[64];
-    memset(def_pixels, 0xFF, sizeof(def_pixels));
-    sg_image_desc def_image_desc;
-    _simgui_clear(&def_image_desc, sizeof(def_image_desc));
-    def_image_desc.width = 8;
-    def_image_desc.height = 8;
-    def_image_desc.pixel_format = SG_PIXELFORMAT_RGBA8;
-    def_image_desc.data.subimage[0][0].ptr = def_pixels;
-    def_image_desc.data.subimage[0][0].size = sizeof(def_pixels);
-    def_image_desc.label = "sokol-imgui-default-image";
-    _simgui.def_img = sg_make_image(&def_image_desc);
-
-    // default font texture
-    if (!_simgui.desc.no_default_font) {
-        simgui_font_tex_desc_t simgui_font_smp_desc;
-        _simgui_clear(&simgui_font_smp_desc, sizeof(simgui_font_smp_desc));
-        simgui_create_fonts_texture(&simgui_font_smp_desc);
-    }
-
     sg_pop_debug_group();
 }
 
-SOKOL_API_IMPL void simgui_create_fonts_texture(const simgui_font_tex_desc_t* desc) {
-    SOKOL_ASSERT(desc);
-    SOKOL_ASSERT(SG_INVALID_ID == _simgui.font_smp.id);
-    SOKOL_ASSERT(SG_INVALID_ID == _simgui.font_img.id);
-    ImGuiIO* io = _simgui_get_io();
-
-    // a default font sampler
-    sg_sampler_desc font_smp_desc;
-    _simgui_clear(&font_smp_desc, sizeof(font_smp_desc));
-    font_smp_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE;
-    font_smp_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE;
-    font_smp_desc.min_filter = desc->min_filter;
-    font_smp_desc.mag_filter = desc->mag_filter;
-    font_smp_desc.label = "sokol-imgui-font-sampler";
-    _simgui.font_smp = sg_make_sampler(&font_smp_desc);
-
-    unsigned char* font_pixels;
-    int font_width, font_height;
-    #if defined(__cplusplus)
-        io->Fonts->GetTexDataAsRGBA32(&font_pixels, &font_width, &font_height);
-    #else
-        int bytes_per_pixel;
-        ImFontAtlas_GetTexDataAsRGBA32(io->Fonts, &font_pixels, &font_width, &font_height, &bytes_per_pixel);
-    #endif
-    sg_image_desc font_img_desc;
-    _simgui_clear(&font_img_desc, sizeof(font_img_desc));
-    font_img_desc.width = font_width;
-    font_img_desc.height = font_height;
-    font_img_desc.pixel_format = SG_PIXELFORMAT_RGBA8;
-    font_img_desc.data.subimage[0][0].ptr = font_pixels;
-    font_img_desc.data.subimage[0][0].size = (size_t)(font_width * font_height) * sizeof(uint32_t);
-    font_img_desc.label = "sokol-imgui-font-image";
-    _simgui.font_img = sg_make_image(&font_img_desc);
-
-    io->Fonts->TexID = simgui_imtextureid_with_sampler(_simgui.font_img, _simgui.font_smp);
-}
-
-SOKOL_API_IMPL void simgui_destroy_fonts_texture(void) {
-    // NOTE: it's valid to call the destroy funcs with SG_INVALID_ID
-    sg_destroy_sampler(_simgui.font_smp);
-    sg_destroy_image(_simgui.font_img);
-    _simgui.font_smp.id = SG_INVALID_ID;
-    _simgui.font_img.id = SG_INVALID_ID;
-}
-
 SOKOL_API_IMPL void simgui_shutdown(void) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    #if defined(__cplusplus)
-        ImGui::DestroyContext();
-    #else
-        _SIMGUI_CFUNC(DestroyContext)(0);
-    #endif
+
+    const ImGuiPlatformIO* pio = _simgui_imgui_get_platform_io();
+    for (size_t i = 0; i < (size_t)pio->Textures.Size; i++) {
+        ImTextureData* tex = pio->Textures.Data[i];
+        if (tex->RefCount == 1) {
+            _simgui_destroy_texture(tex);
+        }
+    }
+    _simgui_imgui_destroy_context();
+
     // NOTE: it's valid to call the destroy funcs with SG_INVALID_ID
     sg_destroy_pipeline(_simgui.pip_unfilterable);
     sg_destroy_shader(_simgui.shd_unfilterable);
     sg_destroy_pipeline(_simgui.def_pip);
     sg_destroy_shader(_simgui.def_shd);
-    sg_destroy_sampler(_simgui.font_smp);
-    sg_destroy_image(_simgui.font_img);
     sg_destroy_sampler(_simgui.def_smp);
-    sg_destroy_image(_simgui.def_img);
     sg_destroy_buffer(_simgui.ibuf);
     sg_destroy_buffer(_simgui.vbuf);
     sg_pop_debug_group();
@@ -2678,13 +2894,7 @@ SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) {
     SOKOL_ASSERT(desc->width > 0);
     SOKOL_ASSERT(desc->height > 0);
     _simgui.cur_dpi_scale = _simgui_def(desc->dpi_scale, 1.0f);
-    ImGuiIO* io = _simgui_get_io();
-    if (!io->Fonts->TexReady) {
-        simgui_destroy_fonts_texture();
-        simgui_font_tex_desc_t simgui_font_smp_desc;
-        _simgui_clear(&simgui_font_smp_desc, sizeof(simgui_font_smp_desc));
-        simgui_create_fonts_texture(&simgui_font_smp_desc);
-    }
+    ImGuiIO* io = _simgui_imgui_get_io();
     io->DisplaySize.x = ((float)desc->width) / _simgui.cur_dpi_scale;
     io->DisplaySize.y = ((float)desc->height) / _simgui.cur_dpi_scale;
     io->DeltaTime = (float)desc->delta_time;
@@ -2696,11 +2906,7 @@ SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) {
             sapp_show_keyboard(false);
         }
         if (!_simgui.desc.disable_set_mouse_cursor) {
-            #if defined(__cplusplus)
-                ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
-            #else
-                ImGuiMouseCursor imgui_cursor = _SIMGUI_CFUNC(GetMouseCursor)();
-            #endif
+            ImGuiMouseCursor imgui_cursor = _simgui_imgui_get_mouse_cursor();
             sapp_mouse_cursor cursor = sapp_get_mouse_cursor();
             switch (imgui_cursor) {
                 case ImGuiMouseCursor_Arrow:        cursor = SAPP_MOUSECURSOR_ARROW; break;
@@ -2717,11 +2923,7 @@ SOKOL_API_IMPL void simgui_new_frame(const simgui_frame_desc_t* desc) {
             sapp_set_mouse_cursor(cursor);
         }
     #endif
-    #if defined(__cplusplus)
-        ImGui::NewFrame();
-    #else
-        _SIMGUI_CFUNC(NewFrame)();
-    #endif
+    _simgui_imgui_newframe();
 }
 
 static sg_pipeline _simgui_bind_image_sampler(sg_bindings* bindings, ImTextureID imtex_id) {
@@ -2734,30 +2936,28 @@ static sg_pipeline _simgui_bind_image_sampler(sg_bindings* bindings, ImTextureID
     }
 }
 
-static ImDrawList* _simgui_imdrawlist_at(ImDrawData* draw_data, int cl_index) {
-    #if defined(__cplusplus)
-        return draw_data->CmdLists[cl_index];
-    #else
-        return draw_data->CmdLists.Data[cl_index];
-    #endif
-}
-
 SOKOL_API_IMPL void simgui_render(void) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        ImGui::Render();
-        ImDrawData* draw_data = ImGui::GetDrawData();
-    #else
-        _SIMGUI_CFUNC(Render)();
-        ImDrawData* draw_data = _SIMGUI_CFUNC(GetDrawData)();
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_imgui_render();
+    ImDrawData* draw_data = _simgui_imgui_get_draw_data();
     if (0 == draw_data) {
         return;
     }
     if (draw_data->CmdListsCount == 0) {
         return;
     }
+
+    // catch up with texture updates
+    if (draw_data->Textures) {
+        for (size_t i = 0; i < (size_t)draw_data->Textures->Size; i++) {
+            ImTextureData* tex = draw_data->Textures->Data[i];
+            if (tex->Status != ImTextureStatus_OK) {
+                _simgui_update_texture(tex);
+            }
+        }
+    }
+
     /* copy vertices and indices into an intermediate buffer so that
        they can be updated with a single sg_update_buffer() call each
        (sg_append_buffer() has performance problems on some GL platforms),
@@ -2827,8 +3027,7 @@ SOKOL_API_IMPL void simgui_render(void) {
     _simgui_clear((void*)&bind, sizeof(bind));
     bind.vertex_buffers[0] = _simgui.vbuf;
     bind.index_buffer = _simgui.ibuf;
-    ImTextureID tex_id = io->Fonts->TexID;
-    _simgui_bind_image_sampler(&bind, tex_id);
+    ImTextureID tex_id = 0;
     int vb_offset = 0;
     int ib_offset = 0;
     for (int cl_index = 0; cl_index < cmd_list_count; cl_index++) {
@@ -2836,13 +3035,11 @@ SOKOL_API_IMPL void simgui_render(void) {
 
         bind.vertex_buffer_offsets[0] = vb_offset;
         bind.index_buffer_offset = ib_offset;
-        sg_apply_bindings(&bind);
+        if (tex_id != 0) {
+            sg_apply_bindings(&bind);
+        }
 
-        #if defined(__cplusplus)
-            const int num_cmds = cl->CmdBuffer.size();
-        #else
-            const int num_cmds = cl->CmdBuffer.Size;
-        #endif
+        const int num_cmds = _simgui_imdrawlist_cmd_buffer_size(cl);
         uint32_t vtx_offset = 0;
         for (int cmd_index = 0; cmd_index < num_cmds; cmd_index++) {
             ImDrawCmd* pcmd = &cl->CmdBuffer.Data[cmd_index];
@@ -2859,8 +3056,9 @@ SOKOL_API_IMPL void simgui_render(void) {
                     sg_apply_bindings(&bind);
                 }
             } else {
-                if ((tex_id != pcmd->TextureId) || (vtx_offset != pcmd->VtxOffset)) {
-                    tex_id = pcmd->TextureId;
+                ImTextureID cmd_tex_id = _simgui_imdrawcmd_gettexid(pcmd);
+                if ((tex_id != cmd_tex_id) || (vtx_offset != pcmd->VtxOffset)) {
+                    tex_id = cmd_tex_id;
                     vtx_offset = pcmd->VtxOffset;
                     sg_pipeline pip = _simgui_bind_image_sampler(&bind, tex_id);
                     sg_apply_pipeline(pip);
@@ -2876,15 +3074,8 @@ SOKOL_API_IMPL void simgui_render(void) {
                 sg_draw((int)pcmd->IdxOffset, (int)pcmd->ElemCount, 1);
             }
         }
-        #if defined(__cplusplus)
-            const size_t vtx_size = (size_t)cl->VtxBuffer.size() * sizeof(ImDrawVert);
-            const size_t idx_size = (size_t)cl->IdxBuffer.size() * sizeof(ImDrawIdx);
-        #else
-            const size_t vtx_size = (size_t)cl->VtxBuffer.Size * sizeof(ImDrawVert);
-            const size_t idx_size = (size_t)cl->IdxBuffer.Size * sizeof(ImDrawIdx);
-        #endif
-        vb_offset += (int)vtx_size;
-        ib_offset += (int)idx_size;
+        vb_offset += _simgui_imdrawlist_vtx_buffer_size(cl) * (int)sizeof(ImDrawVert);
+        ib_offset += _simgui_imdrawlist_idx_buffer_size(cl) * (int)sizeof(ImDrawIdx);
     }
     sg_apply_viewport(0, 0, fb_width, fb_height, true);
     sg_apply_scissor_rect(0, 0, fb_width, fb_height, true);
@@ -2893,102 +3084,61 @@ SOKOL_API_IMPL void simgui_render(void) {
 
 SOKOL_API_IMPL void simgui_add_focus_event(bool focus) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        io->AddFocusEvent(focus);
-    #else
-        ImGuiIO_AddFocusEvent(io, focus);
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_io_add_focus_event(io, focus);
 }
 
 SOKOL_API_IMPL void simgui_add_mouse_pos_event(float x, float y) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        io->AddMouseSourceEvent(ImGuiMouseSource_Mouse);
-        io->AddMousePosEvent(x, y);
-    #else
-        ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_Mouse);
-        ImGuiIO_AddMousePosEvent(io, x, y);
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_io_add_mouse_source_event(io, ImGuiMouseSource_Mouse);
+    _simgui_io_add_mouse_pos_event(io, x, y);
 }
 
 SOKOL_API_IMPL void simgui_add_touch_pos_event(float x, float y) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        io->AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);
-        io->AddMousePosEvent(x, y);
-    #else
-        ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_TouchScreen);
-        ImGuiIO_AddMousePosEvent(io, x, y);
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_io_add_mouse_source_event(io, ImGuiMouseSource_TouchScreen);
+    _simgui_io_add_mouse_pos_event(io, x, y);
 }
 
 SOKOL_API_IMPL void simgui_add_mouse_button_event(int mouse_button, bool down) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        io->AddMouseSourceEvent(ImGuiMouseSource_Mouse);
-        io->AddMouseButtonEvent(mouse_button, down);
-    #else
-        ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_Mouse);
-        ImGuiIO_AddMouseButtonEvent(io, mouse_button, down);
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_io_add_mouse_source_event(io, ImGuiMouseSource_Mouse);
+    _simgui_io_add_mouse_button_event(io, mouse_button, down);
 }
 
 SOKOL_API_IMPL void simgui_add_touch_button_event(int mouse_button, bool down) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        io->AddMouseSourceEvent(ImGuiMouseSource_TouchScreen);
-        io->AddMouseButtonEvent(mouse_button, down);
-    #else
-        ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_TouchScreen);
-        ImGuiIO_AddMouseButtonEvent(io, mouse_button, down);
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_io_add_mouse_source_event(io, ImGuiMouseSource_TouchScreen);
+    _simgui_io_add_mouse_button_event(io, mouse_button, down);
 }
 
 SOKOL_API_IMPL void simgui_add_mouse_wheel_event(float wheel_x, float wheel_y) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        io->AddMouseSourceEvent(ImGuiMouseSource_Mouse);
-        io->AddMouseWheelEvent(wheel_x, wheel_y);
-    #else
-        ImGuiIO_AddMouseSourceEvent(io, ImGuiMouseSource_Mouse);
-        ImGuiIO_AddMouseWheelEvent(io, wheel_x, wheel_y);
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_io_add_mouse_source_event(io, ImGuiMouseSource_Mouse);
+    _simgui_io_add_mouse_wheel_event(io, wheel_x, wheel_y);
 }
 
 SOKOL_API_IMPL void simgui_add_key_event(int imgui_key, bool down) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        io->AddKeyEvent((ImGuiKey)imgui_key, down);
-    #else
-        ImGuiIO_AddKeyEvent(io, (ImGuiKey)imgui_key, down);
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_io_add_key_event(io, (ImGuiKey)imgui_key, down);
 }
 
 SOKOL_API_IMPL void simgui_add_input_character(uint32_t c) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        io->AddInputCharacter(c);
-    #else
-        ImGuiIO_AddInputCharacter(io, c);
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_io_add_input_character(io, c);
 }
 
 SOKOL_API_IMPL void simgui_add_input_characters_utf8(const char* c) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
-    ImGuiIO* io = _simgui_get_io();
-    #if defined(__cplusplus)
-        io->AddInputCharactersUTF8(c);
-    #else
-        ImGuiIO_AddInputCharactersUTF8(io, c);
-    #endif
+    ImGuiIO* io = _simgui_imgui_get_io();
+    _simgui_io_add_input_characters_utf8(io, c);
 }
 
 #if !defined(SOKOL_IMGUI_NO_SOKOL_APP)
@@ -3113,26 +3263,14 @@ _SOKOL_PRIVATE ImGuiKey _simgui_map_keycode(sapp_keycode key) {
 
 _SOKOL_PRIVATE void _simgui_add_sapp_key_event(ImGuiIO* io, sapp_keycode sapp_key, bool down) {
     const ImGuiKey imgui_key = _simgui_map_keycode(sapp_key);
-    #if defined(__cplusplus)
-        io->AddKeyEvent(imgui_key, down);
-    #else
-        ImGuiIO_AddKeyEvent(io, imgui_key, down);
-    #endif
-}
-
-_SOKOL_PRIVATE void _simgui_add_imgui_key_event(ImGuiIO* io, ImGuiKey imgui_key, bool down) {
-    #if defined(__cplusplus)
-        io->AddKeyEvent(imgui_key, down);
-    #else
-        ImGuiIO_AddKeyEvent(io, imgui_key, down);
-    #endif
+    _simgui_io_add_key_event(io, imgui_key, down);
 }
 
 _SOKOL_PRIVATE void _simgui_update_modifiers(ImGuiIO* io, uint32_t mods) {
-    _simgui_add_imgui_key_event(io, ImGuiMod_Ctrl, (mods & SAPP_MODIFIER_CTRL) != 0);
-    _simgui_add_imgui_key_event(io, ImGuiMod_Shift, (mods & SAPP_MODIFIER_SHIFT) != 0);
-    _simgui_add_imgui_key_event(io, ImGuiMod_Alt, (mods & SAPP_MODIFIER_ALT) != 0);
-    _simgui_add_imgui_key_event(io, ImGuiMod_Super, (mods & SAPP_MODIFIER_SUPER) != 0);
+    _simgui_io_add_key_event(io, ImGuiMod_Ctrl, (mods & SAPP_MODIFIER_CTRL) != 0);
+    _simgui_io_add_key_event(io, ImGuiMod_Shift, (mods & SAPP_MODIFIER_SHIFT) != 0);
+    _simgui_io_add_key_event(io, ImGuiMod_Alt, (mods & SAPP_MODIFIER_ALT) != 0);
+    _simgui_io_add_key_event(io, ImGuiMod_Super, (mods & SAPP_MODIFIER_SUPER) != 0);
 }
 
 // returns Ctrl or Super, depending on platform
@@ -3148,7 +3286,7 @@ SOKOL_API_IMPL int simgui_map_keycode(sapp_keycode keycode) {
 SOKOL_API_IMPL bool simgui_handle_event(const sapp_event* ev) {
     SOKOL_ASSERT(_SIMGUI_INIT_COOKIE == _simgui.init_cookie);
     const float dpi_scale = _simgui.cur_dpi_scale;
-    ImGuiIO* io = _simgui_get_io();
+    ImGuiIO* io = _simgui_imgui_get_io();
     switch (ev->type) {
         case SAPP_EVENTTYPE_FOCUSED:
             simgui_add_focus_event(true);
@@ -3250,10 +3388,10 @@ SOKOL_API_IMPL bool simgui_handle_event(const sapp_event* ev) {
         case SAPP_EVENTTYPE_CLIPBOARD_PASTED:
             // simulate a Ctrl-V key down/up
             if (!_simgui.desc.disable_paste_override) {
-                _simgui_add_imgui_key_event(io, _simgui_copypaste_modifier(), true);
-                _simgui_add_imgui_key_event(io, ImGuiKey_V, true);
-                _simgui_add_imgui_key_event(io, ImGuiKey_V, false);
-                _simgui_add_imgui_key_event(io, _simgui_copypaste_modifier(), false);
+                _simgui_io_add_key_event(io, _simgui_copypaste_modifier(), true);
+                _simgui_io_add_key_event(io, ImGuiKey_V, true);
+                _simgui_io_add_key_event(io, ImGuiKey_V, false);
+                _simgui_io_add_key_event(io, _simgui_copypaste_modifier(), false);
             }
             break;
         default:

Некоторые файлы не были показаны из-за большого количества измененных файлов