From 8140a9d8a69951dd99ba3bc1bcac73350cec412c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sun, 27 Apr 2025 15:33:44 +0200 Subject: [PATCH] Fonts: comments on ImTextureData fields. --- imgui.cpp | 59 +++++++++++++++++++++++++++++++++++-------------------- imgui.h | 36 +++++++++++++++++---------------- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 04cb11264..6c6ead519 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -298,7 +298,7 @@ CODE // Any application code here ImGui::Text("Hello, world!"); - // Render dear imgui into screen + // Render dear imgui into framebuffer ImGui::Render(); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); g_pSwapChain->Present(1, 0); @@ -311,24 +311,14 @@ CODE EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE - // Application init: create a dear imgui context, setup some options, load fonts + // Application init: create a Dear ImGui context, setup some options, load fonts ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); - // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls. - // TODO: Fill optional fields of the io structure later. + // TODO: set io.ConfigXXX values, e.g. + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable keyboard controls + // TODO: Load TTF/OTF fonts if you don't want to use the default font. - - // Build and load the texture atlas into a texture - // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer) - int width, height; - unsigned char* pixels = nullptr; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - - // At this point you've got the texture data and you need to upload that to your graphic system: - // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. - // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. - MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) - io.Fonts->SetTexID((void*)texture); + io.Fonts->AddFontFromFileTTF("NotoSans.ttf", 18.0f); // Application main loop while (true) @@ -351,12 +341,19 @@ CODE MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End(); MyGameRender(); // may use any Dear ImGui functions as well! - // Render dear imgui, swap buffers + // End the dear imgui frame // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code) - ImGui::EndFrame(); + ImGui::EndFrame(); // this is automatically called by Render(), but available ImGui::Render(); + + // Update textures + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + if (tex->Status != ImTextureStatus_OK) + MyImGuiBackend_UpdateTexture(tex); + + // Render dear imgui contents, swap buffers ImDrawData* draw_data = ImGui::GetDrawData(); - MyImGuiRenderFunction(draw_data); + MyImGuiBackend_RenderDrawData(draw_data); SwapBuffers(); } @@ -367,12 +364,32 @@ CODE you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags! Please read the FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" about this. - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE --------------------------------------------- The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function. - void MyImGuiRenderFunction(ImDrawData* draw_data) + void MyImGuiBackend_UpdateTexture(ImTextureData* tex) + { + if (tex->Status == ImTextureStatus_WantCreate) + { + // create texture based on tex->Width/Height/Pixels + // call tex->SetTexID() to specify backend-specific identifiers + // tex->Status = ImTextureStatus_OK; + } + if (tex->Status == ImTextureStatus_WantUpdates) + { + // update texture blocks based on tex->UpdateRect + // tex->Status = ImTextureStatus_OK; + } + if (tex->Status == ImTextureStatus_WantDestroy) + { + // destroy texture + // call tex->SetTexID(ImTextureID_Invalid) + // tex->Status = ImTextureStatus_Destroyed; + } + } + + void MyImGuiBackend_RenderDrawData(ImDrawData* draw_data) { // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering. diff --git a/imgui.h b/imgui.h index 005c9c01b..e38cce771 100644 --- a/imgui.h +++ b/imgui.h @@ -3079,7 +3079,7 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c struct ImDrawCmd { ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates - ImTextureRef TexRef; // 16 // User-provided texture ID. Set by user in ImFontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas. + ImTextureRef TexRef; // 16 // Reference to a font/texture atlas (where backend called ImTextureData::SetTexID()) or to a user-provided texture ID (via e.g. ImGui::Image() calls). Both will lead to a ImTextureID value. unsigned int VtxOffset; // 4 // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices. unsigned int IdxOffset; // 4 // Start offset in index buffer. unsigned int ElemCount; // 4 // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[]. @@ -3403,24 +3403,26 @@ struct ImTextureRect // Why does we store two identifiers: TexID and BackendUserData? // - ImTextureID TexID = lower-level identifier stored in ImDrawCmd. ImDrawCmd can refer to textures not created by the backend, and for which there's no ImTextureData. // - void* BackendUserData = higher-level opaque storage for backend own book-keeping. Some backends may have enough with TexID and not need both. + // In columns below: who reads/writes each fields? 'r'=read, 'w'=write, 'core'=main library, 'backend'=renderer backend struct ImTextureData { - ImTextureStatus Status; // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! - ImTextureFormat Format; // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 - int Width; // Texture width - int Height; // Texture height - int BytesPerPixel; // 4 or 1 - int UniqueID; // Sequential index to facilitate identifying a texture when debugging/printing. Only unique per atlas. - unsigned char* Pixels; // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. - ImTextureID TexID; // Always use SetTexID() to modify! Identifier stored in ImDrawCmd::GetTexID() and passed to backend RenderDrawData loop. - void* BackendUserData; // Convenience storage for backend. Some backends may have enough with TexID. - ImTextureRect UsedRect; // Bounding box encompassing all past and queued Updates[]. - ImTextureRect UpdateRect; // Bounding box encompassing all queued Updates[]. - ImVector Updates; // Array of individual updates. - int UnusedFrames; // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. - unsigned short RefCount; // Number of contexts using this texture. - bool UseColors; // Tell whether our texture data is known to use colors (rather than just white + alpha). - bool WantDestroyNextFrame; // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. + //------------------------------------------ core / backend --------------------------------------- + int UniqueID; // w - // Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas. + ImTextureStatus Status; // rw rw // ImTextureStatus_OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify! + void* BackendUserData; // - rw // Convenience storage for backend. Some backends may have enough with TexID. + ImTextureID TexID; // r w // Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function. + ImTextureFormat Format; // w r // ImTextureFormat_RGBA32 (default) or ImTextureFormat_Alpha8 + int Width; // w r // Texture width + int Height; // w r // Texture height + int BytesPerPixel; // w r // 4 or 1 + unsigned char* Pixels; // w r // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. + ImTextureRect UsedRect; // w r // Bounding box encompassing all past and queued Updates[]. + ImTextureRect UpdateRect; // w r // Bounding box encompassing all queued Updates[]. + ImVector Updates; // w r // Array of individual updates. + int UnusedFrames; // w r // In order to facilitate handling Status==WantDestroy in some backend: this is a count successive frames where the texture was not used. Always >0 when Status==WantDestroy. + unsigned short RefCount; // w r // Number of contexts using this texture. Used during backend shutdown. + bool UseColors; // w r // Tell whether our texture data is known to use colors (rather than just white + alpha). + bool WantDestroyNextFrame; // rw - // [Internal] Queued to set ImTextureStatus_WantDestroy next frame. May still be used in the current frame. // Functions ImTextureData() { memset(this, 0, sizeof(*this)); }