From 41f47c853bf300024a70482f3de76c6f2b68833c Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 6 Jun 2020 20:35:29 +0200 Subject: [PATCH 01/16] ImDrawList: Amend 0320e72 removed an unnecessary test. --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d5844dbea..97a5c9f76 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -482,7 +482,7 @@ void ImDrawList::UpdateTextureID() // If current command is used with different settings we need to add a new command const ImTextureID curr_texture_id = GetCurrentTextureId(); ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL) + if ((curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL) { AddDrawCmd(); return; From f6120f8e16eefcdb37b63974e6915a3dd35414be Mon Sep 17 00:00:00 2001 From: ocornut Date: Sat, 6 Jun 2020 21:31:31 +0200 Subject: [PATCH 02/16] ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where starting a split when current VtxOffset was not zero would lead to draw commands with wrong VtxOffset. (#259 --- docs/CHANGELOG.txt | 12 +++++++----- imgui_draw.cpp | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 54e5a1137..5f9f7b165 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,9 +56,11 @@ Other Changes: BeginMenu()/EndMenu() or BeginPopup/EndPopup(). (#3223, #1207) [@rokups] - Drag and Drop: Fixed unintended fallback "..." tooltip display during drag operation when drag source uses _SourceNoPreviewTooltip flags. (#3160) [@rokups] -- ImDrawList: Fixed an issue when draw command merging or cancelling while crossing the VtxOffset - boundary would lead to draw command being emitted with wrong VtxOffset value. (#3129, #3163, #3232) +- ImDrawList: Fixed an issue where draw command merging or primitive unreserve while crossing the + VtxOffset boundary would lead to draw commands with wrong VtxOffset. (#3129, #3163, #3232, #2591) [@thedmd, @Shironekoben, @sergeyn, @ocornut] +- ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where starting a split when current + VtxOffset was not zero would lead to draw commands with wrong VtxOffset. (#2591) - Misc, Freetype: Fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails. - CI: Added CI test to verify we're never accidentally dragging libstdc++ (on some compiler setups, static constructors for non-pod data seems to drag in libstdc++ due to thread-safety concerns). @@ -555,11 +557,11 @@ Other Changes: - Log/Capture: Fixed BeginTabItem() label not being included in a text log/capture. - ImDrawList: Added ImDrawCmd::VtxOffset value to support large meshes (64k+ vertices) using 16-bit indices. The renderer back-end needs to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' to enable - this, and honor the ImDrawCmd::VtxOffset field. Otherwise the value will always be zero. + this, and honor the ImDrawCmd::VtxOffset field. Otherwise the value will always be zero. (#2591) This has the advantage of preserving smaller index buffers and allowing to execute on hardware that do not support 32-bit indices. Most examples back-ends have been modified to support the VtxOffset field. - ImDrawList: Added ImDrawCmd::IdxOffset value, equivalent to summing element count for each draw command. - This is provided for convenience and consistency with VtxOffset. + This is provided for convenience and consistency with VtxOffset. (#2591) - ImDrawCallback: Allow to override the signature of ImDrawCallback by #define-ing it. This is meant to facilitate custom rendering back-ends passing local render-specific data to the draw callback. - ImFontAtlas: FreeType: Added RasterizerFlags::Monochrome flag to disable font anti-aliasing. Combine @@ -571,7 +573,7 @@ Other Changes: dealing with Win32, and to facilitate integration in custom engines. (#2546) [@andrewwillmott] - Backends: OSX: imgui_impl_osx: Added mouse cursor support. (#2585, #1873) [@actboy168] - Examples/Backends: DirectX9/10/11/12, Metal, Vulkan, OpenGL3 (Desktop GL only): Added support for large meshes - (64k+ vertices) with 16-bit indices, enable 'ImGuiBackendFlags_RendererHasVtxOffset' in those back-ends. + (64k+ vertices) with 16-bit indices, enable 'ImGuiBackendFlags_RendererHasVtxOffset' in those back-ends. (#2591) - Examples/Backends: Don't filter characters under 0x10000 before calling io.AddInputCharacter(), the filtering is done in io.AddInputCharacter() itself. This is in prevision for fuller Unicode support. (#2538, #2541) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 97a5c9f76..e3455812a 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1359,6 +1359,7 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) ImDrawCmd draw_cmd; draw_cmd.ClipRect = draw_list->_ClipRectStack.back(); draw_cmd.TextureId = draw_list->_TextureIdStack.back(); + draw_cmd.VtxOffset = draw_list->_VtxCurrentOffset; _Channels[i]._CmdBuffer.push_back(draw_cmd); } } From 57191fe3d088b4895bbee75e8622413a4deeed90 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 14:17:49 +0200 Subject: [PATCH 03/16] Comments about limiting WindowRounding to a reasonable size. --- imgui.cpp | 7 ++++++- imgui.h | 2 +- imgui_internal.h | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 07a832c40..95dc22a65 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1008,7 +1008,7 @@ ImGuiStyle::ImGuiStyle() { Alpha = 1.0f; // Global alpha applies to everything in ImGui WindowPadding = ImVec2(8,8); // Padding within a window - WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows + WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested. WindowMinSize = ImVec2(32,32); // Minimum window size WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text @@ -5757,8 +5757,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) window->Pos = ImFloor(window->Pos); // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies) + // Large values tend to lead to variety of artifacts and are not recommended. window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding; + // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts. + //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar)) + // window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f); + // Apply window focus (new and reactivated windows are moved to front) bool want_focus = false; if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing)) diff --git a/imgui.h b/imgui.h index 7906ae070..8fcd5416b 100644 --- a/imgui.h +++ b/imgui.h @@ -1371,7 +1371,7 @@ struct ImGuiStyle { float Alpha; // Global alpha applies to everything in Dear ImGui. ImVec2 WindowPadding; // Padding within a window. - float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. + float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended. float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints(). ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered. diff --git a/imgui_internal.h b/imgui_internal.h index 96e7b19e0..7b15e63fe 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1561,7 +1561,7 @@ struct IMGUI_API ImGuiWindow ImVec2 ContentSize; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding. ImVec2 ContentSizeExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize(). ImVec2 WindowPadding; // Window padding at the time of Begin(). - float WindowRounding; // Window rounding at the time of Begin(). + float WindowRounding; // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc. float WindowBorderSize; // Window border size at the time of Begin(). int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)! ImGuiID MoveId; // == window->GetID("#MOVE") From a6bb047baba31c3a4038b9f1b06977e7c0feb08e Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 15:22:44 +0200 Subject: [PATCH 04/16] ImDrawList: Store header/current ImDrawCmd in instance to simplify merging code. Amend 0320e72, toward #3163, #3129 --- imgui.h | 16 ++++---- imgui_draw.cpp | 102 +++++++++++++++++++++++-------------------------- 2 files changed, 57 insertions(+), 61 deletions(-) diff --git a/imgui.h b/imgui.h index 8fcd5416b..45f3aa7c4 100644 --- a/imgui.h +++ b/imgui.h @@ -1874,19 +1874,21 @@ typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* c #define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1) // Typically, 1 command = 1 GPU draw call (unless command is a callback) -// Pre 1.71 back-ends will typically ignore the VtxOffset/IdxOffset fields. When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' -// is enabled, those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. +// - VtxOffset/IdxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled, +// those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices. +// Pre-1.71 back-ends will typically ignore the VtxOffset/IdxOffset fields. +// - The ClipRect/TextureId/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for). struct ImDrawCmd { - 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[]. ImVec4 ClipRect; // 4*4 // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates ImTextureID TextureId; // 4-8 // 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. - unsigned int VtxOffset; // 4 // Start offset in vertex buffer. Pre-1.71 or without ImGuiBackendFlags_RendererHasVtxOffset: always 0. With ImGuiBackendFlags_RendererHasVtxOffset: may be >0 to support meshes larger than 64K vertices with 16-bit indices. + 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. Always equal to sum of ElemCount drawn so far. + 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[]. ImDrawCallback UserCallback; // 4-8 // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally. void* UserCallbackData; // 4-8 // The draw callback code can access this. - ImDrawCmd() { ElemCount = 0; TextureId = (ImTextureID)NULL; VtxOffset = IdxOffset = 0; UserCallback = NULL; UserCallbackData = NULL; } + ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed }; // Vertex index, default to 16-bit @@ -1977,17 +1979,17 @@ struct ImDrawList // [Internal, used while building lists] const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context) const char* _OwnerName; // Pointer to owner window's name for debugging - unsigned int _VtxCurrentOffset; // [Internal] Always 0 unless 'Flags & ImDrawListFlags_AllowVtxOffset'. unsigned int _VtxCurrentIdx; // [Internal] Generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0. ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much) ImVector _ClipRectStack; // [Internal] ImVector _TextureIdStack; // [Internal] ImVector _Path; // [Internal] current path building + ImDrawCmd _CmdHeader; // [Internal] Template of active commands. Fields should match those of CmdBuffer.back(). ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!) // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) - ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; Flags = ImDrawListFlags_None; _VtxCurrentOffset = _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; _OwnerName = NULL; } + ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; Flags = ImDrawListFlags_None; _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; _OwnerName = NULL; } ~ImDrawList() { ClearFreeMemory(); } IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e3455812a..43daede2d 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -379,11 +379,17 @@ void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error) // Initialize before use in a new frame. We always have a command ready in the buffer. void ImDrawList::ResetForNewFrame() { + // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. + // (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC) + IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0); + IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4)); + IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID)); + CmdBuffer.resize(0); IdxBuffer.resize(0); VtxBuffer.resize(0); Flags = _Data->InitialFlags; - _VtxCurrentOffset = 0; + memset(&_CmdHeader, 0, sizeof(_CmdHeader)); _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; @@ -400,7 +406,6 @@ void ImDrawList::ClearFreeMemory() IdxBuffer.clear(); VtxBuffer.clear(); Flags = ImDrawListFlags_None; - _VtxCurrentOffset = 0; _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; @@ -420,16 +425,12 @@ ImDrawList* ImDrawList::CloneOutput() const return dst; } -// Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds -#define GetCurrentClipRect() (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1] : _Data->ClipRectFullscreen) -#define GetCurrentTextureId() (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : (ImTextureID)NULL) - void ImDrawList::AddDrawCmd() { ImDrawCmd draw_cmd; - draw_cmd.ClipRect = GetCurrentClipRect(); - draw_cmd.TextureId = GetCurrentTextureId(); - draw_cmd.VtxOffset = _VtxCurrentOffset; + draw_cmd.ClipRect = _CmdHeader.ClipRect; // Same as calling ImDrawCmd_HeaderCopy() + draw_cmd.TextureId = _CmdHeader.TextureId; + draw_cmd.VtxOffset = _CmdHeader.VtxOffset; draw_cmd.IdxOffset = IdxBuffer.Size; IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w); @@ -450,68 +451,62 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) AddDrawCmd(); // Force a new command after us (see comment below) } +// Compare ClipRect, TextureId and VtxOffset with a single memcmp() +#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int)) +#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset +#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset + // Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. // The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. void ImDrawList::UpdateClipRect() { // If current command is used with different settings we need to add a new command - const ImVec4 curr_clip_rect = GetCurrentClipRect(); ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if ((curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL) + if ((curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL) { AddDrawCmd(); return; } // Try to merge with previous command if it matches, else use current command - if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1) + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) { - ImDrawCmd* prev_cmd = curr_cmd - 1; - if (memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->VtxOffset == _VtxCurrentOffset && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL) - { - CmdBuffer.pop_back(); - return; - } + CmdBuffer.pop_back(); + return; } - curr_cmd->ClipRect = curr_clip_rect; + curr_cmd->ClipRect = _CmdHeader.ClipRect; } void ImDrawList::UpdateTextureID() { // If current command is used with different settings we need to add a new command - const ImTextureID curr_texture_id = GetCurrentTextureId(); ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if ((curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL) + if ((curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) || curr_cmd->UserCallback != NULL) { AddDrawCmd(); return; } // Try to merge with previous command if it matches, else use current command - if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1) + ImDrawCmd* prev_cmd = curr_cmd - 1; + if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL) { - ImDrawCmd* prev_cmd = curr_cmd - 1; - if (prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->VtxOffset == _VtxCurrentOffset && prev_cmd->UserCallback == NULL) - { - CmdBuffer.pop_back(); - return; - } + CmdBuffer.pop_back(); + return; } - curr_cmd->TextureId = curr_texture_id; + curr_cmd->TextureId = _CmdHeader.TextureId; } -#undef GetCurrentClipRect -#undef GetCurrentTextureId - // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect) { ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y); - if (intersect_with_current_clip_rect && _ClipRectStack.Size) + if (intersect_with_current_clip_rect) { - ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size-1]; + ImVec4 current = _CmdHeader.ClipRect; if (cr.x < current.x) cr.x = current.x; if (cr.y < current.y) cr.y = current.y; if (cr.z > current.z) cr.z = current.z; @@ -521,6 +516,7 @@ void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_ cr.w = ImMax(cr.y, cr.w); _ClipRectStack.push_back(cr); + _CmdHeader.ClipRect = cr; UpdateClipRect(); } @@ -531,21 +527,22 @@ void ImDrawList::PushClipRectFullScreen() void ImDrawList::PopClipRect() { - IM_ASSERT(_ClipRectStack.Size > 0); _ClipRectStack.pop_back(); + _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1]; UpdateClipRect(); } void ImDrawList::PushTextureID(ImTextureID texture_id) { _TextureIdStack.push_back(texture_id); + _CmdHeader.TextureId = texture_id; UpdateTextureID(); } void ImDrawList::PopTextureID() { - IM_ASSERT(_TextureIdStack.Size > 0); _TextureIdStack.pop_back(); + _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1]; UpdateTextureID(); } @@ -558,7 +555,7 @@ void ImDrawList::PrimReserve(int idx_count, int vtx_count) IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0); if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) { - _VtxCurrentOffset = VtxBuffer.Size; + _CmdHeader.VtxOffset = VtxBuffer.Size; _VtxCurrentIdx = 0; AddDrawCmd(); } @@ -1235,9 +1232,9 @@ void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, if (font_size == 0.0f) font_size = _Data->FontSize; - IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. + IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font. - ImVec4 clip_rect = _ClipRectStack.back(); + ImVec4 clip_rect = _CmdHeader.ClipRect; if (cpu_fine_clip_rect) { clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x); @@ -1258,7 +1255,7 @@ void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, cons if ((col & IM_COL32_A_MASK) == 0) return; - const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; if (push_texture_id) PushTextureID(user_texture_id); @@ -1274,7 +1271,7 @@ void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, con if ((col & IM_COL32_A_MASK) == 0) return; - const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back(); + const bool push_texture_id = user_texture_id != _CmdHeader.TextureId; if (push_texture_id) PushTextureID(user_texture_id); @@ -1357,19 +1354,12 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) if (_Channels[i]._CmdBuffer.Size == 0) { ImDrawCmd draw_cmd; - draw_cmd.ClipRect = draw_list->_ClipRectStack.back(); - draw_cmd.TextureId = draw_list->_TextureIdStack.back(); - draw_cmd.VtxOffset = draw_list->_VtxCurrentOffset; + ImDrawCmd_HeaderCopy(&draw_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset _Channels[i]._CmdBuffer.push_back(draw_cmd); } } } -static inline bool CanMergeDrawCommands(ImDrawCmd* a, ImDrawCmd* b) -{ - return memcmp(&a->ClipRect, &b->ClipRect, sizeof(a->ClipRect)) == 0 && a->TextureId == b->TextureId && a->VtxOffset == b->VtxOffset && !a->UserCallback && !b->UserCallback; -} - void ImDrawListSplitter::Merge(ImDrawList* draw_list) { // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. @@ -1390,12 +1380,16 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) ImDrawChannel& ch = _Channels[i]; if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0) ch._CmdBuffer.pop_back(); - if (ch._CmdBuffer.Size > 0 && last_cmd != NULL && CanMergeDrawCommands(last_cmd, &ch._CmdBuffer[0])) + if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) { - // Merge previous channel last draw command with current channel first draw command if matching. - last_cmd->ElemCount += ch._CmdBuffer[0].ElemCount; - idx_offset += ch._CmdBuffer[0].ElemCount; - ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges. + ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; + if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL) + { + // Merge previous channel last draw command with current channel first draw command if matching. + last_cmd->ElemCount += next_cmd->ElemCount; + idx_offset += next_cmd->ElemCount; + ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges. + } } if (ch._CmdBuffer.Size > 0) last_cmd = &ch._CmdBuffer.back(); From 117d57df5bdddeaea8a286de8879879f5436a067 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 18:21:10 +0200 Subject: [PATCH 05/16] ImDrawList: Additional comments and extracted bits into ImDrawList::PopUnusedDrawCmd() --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 12 +++--------- imgui.h | 1 + imgui_draw.cpp | 19 ++++++++++++++++--- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5f9f7b165..6ab1019d6 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -61,6 +61,8 @@ Other Changes: [@thedmd, @Shironekoben, @sergeyn, @ocornut] - ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where starting a split when current VtxOffset was not zero would lead to draw commands with wrong VtxOffset. (#2591) +- ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where starting a split right after + a callback draw command would incorrectly override the callback draw command. - Misc, Freetype: Fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails. - CI: Added CI test to verify we're never accidentally dragging libstdc++ (on some compiler setups, static constructors for non-pod data seems to drag in libstdc++ due to thread-safety concerns). diff --git a/imgui.cpp b/imgui.cpp index 95dc22a65..1b190a6e6 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4077,18 +4077,12 @@ static void AddWindowToSortBuffer(ImVector* out_sorted_windows, Im static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* draw_list) { + // Remove trailing command if unused. + // Technically we could return directly instead of popping, but this make things looks neat in Metrics window as well. + draw_list->PopUnusedDrawCmd(); if (draw_list->CmdBuffer.Size == 0) return; - // Remove trailing command if unused - ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.back(); - if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL) - { - draw_list->CmdBuffer.pop_back(); - if (draw_list->CmdBuffer.Size == 0) - return; - } - // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. // May trigger for you if you are using PrimXXX functions incorrectly. IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size); diff --git a/imgui.h b/imgui.h index 45f3aa7c4..de4faf281 100644 --- a/imgui.h +++ b/imgui.h @@ -2061,6 +2061,7 @@ struct ImDrawList // NB: all primitives needs to be reserved via PrimReserve() beforehand! IMGUI_API void ResetForNewFrame(); IMGUI_API void ClearFreeMemory(); + IMGUI_API void PopUnusedDrawCmd(); IMGUI_API void PrimReserve(int idx_count, int vtx_count); IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 43daede2d..fb25fecba 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -437,6 +437,17 @@ void ImDrawList::AddDrawCmd() CmdBuffer.push_back(draw_cmd); } +// Pop trailing draw command (used before merging or presenting to user) +// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL +void ImDrawList::PopUnusedDrawCmd() +{ + if (CmdBuffer.Size == 0) + return; + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL) + CmdBuffer.pop_back(); +} + void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) { ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; @@ -1362,13 +1373,12 @@ void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count) void ImDrawListSplitter::Merge(ImDrawList* draw_list) { - // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. + // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use. if (_Count <= 1) return; SetCurrentChannel(draw_list, 0); - if (draw_list->CmdBuffer.Size != 0 && draw_list->CmdBuffer.back().ElemCount == 0) - draw_list->CmdBuffer.pop_back(); + draw_list->PopUnusedDrawCmd(); // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. int new_cmd_buffer_count = 0; @@ -1378,8 +1388,11 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) for (int i = 1; i < _Count; i++) { ImDrawChannel& ch = _Channels[i]; + + // Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback. if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0) ch._CmdBuffer.pop_back(); + if (ch._CmdBuffer.Size > 0 && last_cmd != NULL) { ImDrawCmd* next_cmd = &ch._CmdBuffer[0]; From e35a813d5767397d211644385f0dee95df54acca Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 18:35:13 +0200 Subject: [PATCH 06/16] ImDrawList: Separating PrimXXX sections from more internals helper in the header file. --- imgui.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/imgui.h b/imgui.h index de4faf281..706751896 100644 --- a/imgui.h +++ b/imgui.h @@ -2057,19 +2057,22 @@ struct ImDrawList inline void ChannelsMerge() { _Splitter.Merge(this); } inline void ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); } - // [Internal helpers] - // NB: all primitives needs to be reserved via PrimReserve() beforehand! - IMGUI_API void ResetForNewFrame(); - IMGUI_API void ClearFreeMemory(); - IMGUI_API void PopUnusedDrawCmd(); + // Advanced: Primitives allocations + // - We render triangles (three vertices) + // - All primitives needs to be reserved via PrimReserve() beforehand. IMGUI_API void PrimReserve(int idx_count, int vtx_count); IMGUI_API void PrimUnreserve(int idx_count, int vtx_count); IMGUI_API void PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col); // Axis aligned rectangle (composed of two triangles) IMGUI_API void PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col); IMGUI_API void PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col); - inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col){ _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } - inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } - inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } + inline void PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; } + inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; } + inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index + + // [Internal helpers] + IMGUI_API void ResetForNewFrame(); + IMGUI_API void ClearFreeMemory(); + IMGUI_API void PopUnusedDrawCmd(); IMGUI_API void UpdateClipRect(); IMGUI_API void UpdateTextureID(); }; From b1f2eacdf3b7ce64decbfd2e5e30819d05cf2ee1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 18:38:23 +0200 Subject: [PATCH 07/16] ImDrawList: Prefixed internal functions with underscore, renamed UpdateClipRect() to _OnChangedClipRect(), UpdateTextureID() -> _OnChangedTextureID() --- imgui.cpp | 14 +++++++------- imgui.h | 12 ++++++------ imgui_draw.cpp | 24 ++++++++++++------------ 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 1b190a6e6..43e713669 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -2994,7 +2994,7 @@ void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window) window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity; window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity; window->IDStack.clear(); - window->DrawList->ClearFreeMemory(); + window->DrawList->_ClearFreeMemory(); window->DC.ChildWindows.clear(); window->DC.ItemFlagsStack.clear(); window->DC.ItemWidthStack.clear(); @@ -3777,11 +3777,11 @@ void ImGui::NewFrame() if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; - g.BackgroundDrawList.ResetForNewFrame(); + g.BackgroundDrawList._ResetForNewFrame(); g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID); g.BackgroundDrawList.PushClipRectFullScreen(); - g.ForegroundDrawList.ResetForNewFrame(); + g.ForegroundDrawList._ResetForNewFrame(); g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID); g.ForegroundDrawList.PushClipRectFullScreen(); @@ -4019,8 +4019,8 @@ void ImGui::Shutdown(ImGuiContext* context) g.OpenPopupStack.clear(); g.BeginPopupStack.clear(); g.DrawDataBuilder.ClearFreeMemory(); - g.BackgroundDrawList.ClearFreeMemory(); - g.ForegroundDrawList.ClearFreeMemory(); + g.BackgroundDrawList._ClearFreeMemory(); + g.ForegroundDrawList._ClearFreeMemory(); g.TabBars.Clear(); g.CurrentTabBarStack.clear(); @@ -4079,7 +4079,7 @@ static void AddDrawListToDrawData(ImVector* out_list, ImDrawList* d { // Remove trailing command if unused. // Technically we could return directly instead of popping, but this make things looks neat in Metrics window as well. - draw_list->PopUnusedDrawCmd(); + draw_list->_PopUnusedDrawCmd(); if (draw_list->CmdBuffer.Size == 0) return; @@ -5859,7 +5859,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // DRAWING // Setup draw list and outer clipping rectangle - window->DrawList->ResetForNewFrame(); + window->DrawList->_ResetForNewFrame(); window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID); PushClipRect(host_rect.Min, host_rect.Max, false); diff --git a/imgui.h b/imgui.h index 706751896..b6c91a031 100644 --- a/imgui.h +++ b/imgui.h @@ -1991,7 +1991,7 @@ struct ImDrawList // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui) ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; Flags = ImDrawListFlags_None; _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; _OwnerName = NULL; } - ~ImDrawList() { ClearFreeMemory(); } + ~ImDrawList() { _ClearFreeMemory(); } IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false); // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) IMGUI_API void PushClipRectFullScreen(); IMGUI_API void PopClipRect(); @@ -2070,11 +2070,11 @@ struct ImDrawList inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index // [Internal helpers] - IMGUI_API void ResetForNewFrame(); - IMGUI_API void ClearFreeMemory(); - IMGUI_API void PopUnusedDrawCmd(); - IMGUI_API void UpdateClipRect(); - IMGUI_API void UpdateTextureID(); + IMGUI_API void _ResetForNewFrame(); + IMGUI_API void _ClearFreeMemory(); + IMGUI_API void _PopUnusedDrawCmd(); + IMGUI_API void _OnChangedClipRect(); + IMGUI_API void _OnChangedTextureID(); }; // All draw data to render a Dear ImGui frame diff --git a/imgui_draw.cpp b/imgui_draw.cpp index fb25fecba..d0ea99fb0 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -377,7 +377,7 @@ void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error) } // Initialize before use in a new frame. We always have a command ready in the buffer. -void ImDrawList::ResetForNewFrame() +void ImDrawList::_ResetForNewFrame() { // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory. // (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC) @@ -400,7 +400,7 @@ void ImDrawList::ResetForNewFrame() CmdBuffer.push_back(ImDrawCmd()); } -void ImDrawList::ClearFreeMemory() +void ImDrawList::_ClearFreeMemory() { CmdBuffer.clear(); IdxBuffer.clear(); @@ -439,7 +439,7 @@ void ImDrawList::AddDrawCmd() // Pop trailing draw command (used before merging or presenting to user) // Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL -void ImDrawList::PopUnusedDrawCmd() +void ImDrawList::_PopUnusedDrawCmd() { if (CmdBuffer.Size == 0) return; @@ -469,7 +469,7 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) // Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack. // The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only. -void ImDrawList::UpdateClipRect() +void ImDrawList::_OnChangedClipRect() { // If current command is used with different settings we need to add a new command ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; @@ -490,7 +490,7 @@ void ImDrawList::UpdateClipRect() curr_cmd->ClipRect = _CmdHeader.ClipRect; } -void ImDrawList::UpdateTextureID() +void ImDrawList::_OnChangedTextureID() { // If current command is used with different settings we need to add a new command ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; @@ -528,7 +528,7 @@ void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_ _ClipRectStack.push_back(cr); _CmdHeader.ClipRect = cr; - UpdateClipRect(); + _OnChangedClipRect(); } void ImDrawList::PushClipRectFullScreen() @@ -540,21 +540,21 @@ void ImDrawList::PopClipRect() { _ClipRectStack.pop_back(); _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1]; - UpdateClipRect(); + _OnChangedClipRect(); } void ImDrawList::PushTextureID(ImTextureID texture_id) { _TextureIdStack.push_back(texture_id); _CmdHeader.TextureId = texture_id; - UpdateTextureID(); + _OnChangedTextureID(); } void ImDrawList::PopTextureID() { _TextureIdStack.pop_back(); _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1]; - UpdateTextureID(); + _OnChangedTextureID(); } // Reserve space for a number of vertices and indices. @@ -1378,7 +1378,7 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) return; SetCurrentChannel(draw_list, 0); - draw_list->PopUnusedDrawCmd(); + draw_list->_PopUnusedDrawCmd(); // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command. int new_cmd_buffer_count = 0; @@ -1427,8 +1427,8 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } } draw_list->_IdxWritePtr = idx_write; - draw_list->UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call. - draw_list->UpdateTextureID(); + draw_list->_OnChangedClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call. + draw_list->_OnChangedTextureID(); _Count = 1; } From 3bef743df464c5dbbf527981c7f50be7a0f7f719 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 19:06:55 +0200 Subject: [PATCH 08/16] ImDrawList: Clarifying and guarateeing that CmdBuffer.back()->UserCallback should be always be NULL. --- imgui_draw.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index d0ea99fb0..0af2c3c52 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -451,7 +451,8 @@ void ImDrawList::_PopUnusedDrawCmd() void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data) { ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if (curr_cmd->ElemCount != 0 || curr_cmd->UserCallback != NULL) + IM_ASSERT(curr_cmd->UserCallback == NULL); + if (curr_cmd->ElemCount != 0) { AddDrawCmd(); curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; @@ -473,11 +474,12 @@ void ImDrawList::_OnChangedClipRect() { // If current command is used with different settings we need to add a new command ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if ((curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL) + if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0) { AddDrawCmd(); return; } + IM_ASSERT(curr_cmd->UserCallback == NULL); // Try to merge with previous command if it matches, else use current command ImDrawCmd* prev_cmd = curr_cmd - 1; @@ -494,11 +496,12 @@ void ImDrawList::_OnChangedTextureID() { // If current command is used with different settings we need to add a new command ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; - if ((curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) || curr_cmd->UserCallback != NULL) + if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId) { AddDrawCmd(); return; } + IM_ASSERT(curr_cmd->UserCallback == NULL); // Try to merge with previous command if it matches, else use current command ImDrawCmd* prev_cmd = curr_cmd - 1; @@ -1427,6 +1430,11 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; } } draw_list->_IdxWritePtr = idx_write; + + // Ensure there's always a non-callback draw command trailing the command-buffer + if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL) + draw_list->AddDrawCmd(); + draw_list->_OnChangedClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call. draw_list->_OnChangedTextureID(); _Count = 1; @@ -1437,6 +1445,7 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) IM_ASSERT(idx >= 0 && idx < _Count); if (_Current == idx) return; + // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap() memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer)); memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer)); From 84862ec78e0c2a249c94575a4ee39105e4061e68 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 20:53:11 +0200 Subject: [PATCH 09/16] ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where changing channels with different TextureId, VtxOffset would incorrectly apply new settings to draw channels. (#3129, #3163) --- docs/CHANGELOG.txt | 3 +++ imgui_draw.cpp | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6ab1019d6..1ae96e46f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -59,6 +59,9 @@ Other Changes: - ImDrawList: Fixed an issue where draw command merging or primitive unreserve while crossing the VtxOffset boundary would lead to draw commands with wrong VtxOffset. (#3129, #3163, #3232, #2591) [@thedmd, @Shironekoben, @sergeyn, @ocornut] +- ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where changing channels with different + TextureId, VtxOffset would incorrectly apply new settings to draw channels. (#3129, #3163) + [@ocornut, @thedmd, @Shironekoben] - ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where starting a split when current VtxOffset was not zero would lead to draw commands with wrong VtxOffset. (#2591) - ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where starting a split right after diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0af2c3c52..94f223ba4 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1435,8 +1435,13 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list) if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL) draw_list->AddDrawCmd(); - draw_list->_OnChangedClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call. - draw_list->_OnChangedTextureID(); + // If current command is used with different settings we need to add a new command + ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0) + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) + draw_list->AddDrawCmd(); + _Count = 1; } @@ -1453,6 +1458,13 @@ void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx) memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer)); memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer)); draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size; + + // If current command is used with different settings we need to add a new command + ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1]; + if (curr_cmd->ElemCount == 0) + ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset + else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0) + draw_list->AddDrawCmd(); } //----------------------------------------------------------------------------- From 9b3ce494fdee20f56ee672febe2f9d737a3927cc Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Jun 2020 22:38:19 +0200 Subject: [PATCH 10/16] Columns: Lower overhead on column switches and switching to background channel (some stress tests in debug builds went 3->2 ms). (#125) This change benefits Columns but was primarily made with Tables in mind. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 7 ++++++- imgui_internal.h | 1 + imgui_widgets.cpp | 29 +++++++++++++++++++++++++---- 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1ae96e46f..459bf25c5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,6 +46,8 @@ Other Changes: flag was also set, and _OpenOnArrow is frequently set along with _OpenOnDoubleClick). - TreeNode: Fixed bug where dragging a payload over a TreeNode() with either _OpenOnDoubleClick or _OpenOnArrow would open the node. (#143) +- Columns: Lower overhead on column switches and switching to background channel (some of our stress + tests in debug builds went 3->2 ms). Benefits Columns but was primarily made with Tables in mind! - Style: Added style.TabMinWidthForUnselectedCloseButton settings. Set to 0.0f (default) to always make a close button appear on hover (same as Chrome, VS). Set to FLT_MAX to only display a close button when selected (merely hovering is not enough). diff --git a/imgui.cpp b/imgui.cpp index 43e713669..fd84ed030 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4167,7 +4167,12 @@ static void SetupDrawData(ImVector* draw_lists, ImDrawData* draw_da } } -// When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result. +// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering. +// - When using this function it is sane to ensure that float are perfectly rounded to integer values, +// so that e.g. (int)(max.x-min.x) in user's render produce correct result. +// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect(): +// some frequently called functions which to modify both channels and clipping simultaneously tend to use a more +// specialized code path to added extraneous updates of the underlying ImDrawCmd. void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) { ImGuiWindow* window = GetCurrentWindow(); diff --git a/imgui_internal.h b/imgui_internal.h index 7b15e63fe..b07c55683 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -435,6 +435,7 @@ struct IMGUI_API ImRect void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. void Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); } bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } + ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); } }; // Helper: ImBitArray diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2ba7c6b4f..7d5bc5cfa 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7549,6 +7549,11 @@ void ImGui::PushColumnsBackground() ImGuiColumns* columns = window->DC.CurrentColumns; if (columns->Count == 1) return; + + // Set cmd header ahead to avoid SetCurrentChannel+PushClipRect doing an unnecessary AddDrawCmd/Pop + //if (window->DrawList->Flags & ImDrawListFlags_Debug) IMGUI_DEBUG_LOG("PushColumnsBackground()\n"); + window->DrawList->_CmdHeader.ClipRect = columns->HostClipRect.ToVec4(); + columns->Splitter.SetCurrentChannel(window->DrawList, 0); int cmd_size = window->DrawList->CmdBuffer.Size; PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false); @@ -7562,6 +7567,12 @@ void ImGui::PopColumnsBackground() ImGuiColumns* columns = window->DC.CurrentColumns; if (columns->Count == 1) return; + + // Set cmd header ahead to avoid SetCurrentChannel+PushClipRect doing an unnecessary AddDrawCmd/Pop + //if (window->DrawList->Flags & ImDrawListFlags_Debug) IMGUI_DEBUG_LOG("PopColumnsBackground()\n"); + ImVec4 pop_clip_rect = window->DrawList->_ClipRectStack.Data[window->DrawList->_ClipRectStack.Size - 2]; + window->DrawList->_CmdHeader.ClipRect = pop_clip_rect; + columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); PopClipRect(); } @@ -7684,11 +7695,22 @@ void ImGui::NextColumn() return; } PopItemWidth(); - PopClipRect(); + + // Next column + if (++columns->Current == columns->Count) + columns->Current = 0; + + // As a small optimization, to avoid doing PopClipRect() + SetCurrentChannel() + PushClipRect() + // (which would needlessly attempt to update commands in the wrong channel, then pop or overwrite them), + // We use a shortcut: we override ClipRect in window and drawlist's CmdHeader + SetCurrentChannel(). + ImGuiColumnData* column = &columns->Columns[columns->Current]; + window->ClipRect = column->ClipRect; + window->DrawList->_CmdHeader.ClipRect = column->ClipRect.ToVec4(); + //PopClipRect(); const float column_padding = g.Style.ItemSpacing.x; columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); - if (++columns->Current < columns->Count) + if (columns->Current > 0) { // Columns 1+ ignore IndentX (by canceling it out) // FIXME-COLUMNS: Unnecessary, could be locked? @@ -7701,7 +7723,6 @@ void ImGui::NextColumn() // Column 0 honor IndentX window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); columns->Splitter.SetCurrentChannel(window->DrawList, 1); - columns->Current = 0; columns->LineMinY = columns->LineMaxY; } window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); @@ -7709,7 +7730,7 @@ void ImGui::NextColumn() window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); window->DC.CurrLineTextBaseOffset = 0.0f; - PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite? + //PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup. float offset_0 = GetColumnOffset(columns->Current); From a72754886f703fd73048afc86c3eb1fce844e259 Mon Sep 17 00:00:00 2001 From: Scott Date: Tue, 9 Jun 2020 16:10:37 +0200 Subject: [PATCH 11/16] Docs: Initial draft of fonts documentation (#2861) --- docs/{FONTS.txt => FONTS.md} | 294 ++++++++++++++++------------------- 1 file changed, 133 insertions(+), 161 deletions(-) rename docs/{FONTS.txt => FONTS.md} (59%) diff --git a/docs/FONTS.txt b/docs/FONTS.md similarity index 59% rename from docs/FONTS.txt rename to docs/FONTS.md index e3690f14a..9f5c7d7f2 100644 --- a/docs/FONTS.txt +++ b/docs/FONTS.md @@ -1,85 +1,134 @@ -dear imgui -FONTS DOCUMENTATION - -Also read https://www.dearimgui.org/faq for more fonts related infos. +## Fonts The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' (by Tristan Grimmer), -a 13 pixels high, pixel-perfect font used by default. -We embed it font in source code so you can use Dear ImGui without any file system access. +a 13 pixels high, pixel-perfect font used by default. We embed it font in source code so you can use Dear ImGui without any file system access. -You may also load external .TTF/.OTF files. -The files in this folder are suggested fonts, provided as a convenience. +You may also load external .TTF/.OTF files. The files in this folder are suggested fonts, provided as a convenience. -Please read the FAQ: https://www.dearimgui.org/faq -Please use the Discord server: http://discord.dearimgui.org and not the Github issue tracker for basic font loading questions. +Fonts are rasterized in a single texture at the time of calling either of + +- `io.Fonts->GetTexDataAsAlpha8()` + +- `GetTexDataAsRGBA32()/Build()` + +**Please read the FAQ:** https://www.dearimgui.org/faq +Please use the Discord server: http://discord.dearimgui.org and not the GitHub issue tracker for basic font loading questions. --------------------------------------- - INDEX: ---------------------------------------- - -- Readme First / FAQ -- Fonts Loading Instructions -- Using Icons -- Using FreeType rasterizer -- Building Custom Glyph Ranges -- Using custom colorful icons -- Embedding Fonts in Source Code -- Credits/Licences for fonts included in repository -- Fonts Links +| Index | +|:---------------------------------------| +| [Readme First](#readme-first) | +| [Using Icons](#using-icons) | +| [Fonts Loading Instructions](#font-loading-instructions) | +| [FreeType Rasterizer, Small Font Sizes](#freeType-rasterizer-small-font-sizes) | +| [Building Custom Glyph Ranges](#building-custom-glyph-ranges) | +| [Using Custom Colorful Icons](#using-custom-colorful-icons) | +| [Embedding Fonts In Source Code](#embedding-fonts-in-source-code) | +| [Credits/Licenses For Fonts Included In This Folder](#creditslicenses-for-fonts-included-in-this-folder) | +| [Font Links](#font-links) | --------------------------------------- - README FIRST / FAQ ---------------------------------------- + ## Readme First - You can use the style editor ImGui::ShowStyleEditor() in the "Fonts" section to browse your fonts and understand what's going on if you have an issue. -- Fonts are rasterized in a single texture at the time of calling either of io.Fonts->GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build(). -- Make sure your font ranges data are persistent and available at the time the font atlas is being built. +- Make sure your font ranges data are persistent (available during the call to GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build(). - Use C++11 u8"my text" syntax to encode literal strings as UTF-8. e.g.: + ``` u8"hello" u8"こんにちは" // this will be encoded as UTF-8 -- If you want to include a backslash \ character in your string literal, you need to double them e.g. "folder\\filename". - Read FAQ for details. + ``` +- If you want to include a backslash \ character in your string literal, you need to double them e.g. "folder\\\filename". --------------------------------------- - FONTS LOADING INSTRUCTIONS ---------------------------------------- + ## Using Icons -Load default font: +- Using an icon font (such as [FontAwesome](http://fontawesome.io) or [OpenFontIcons](https://github.com/traverseda/OpenFontIcons)) is an easy and practical way to use icons in your Dear ImGui application. +- A common pattern is to merge the icon font within your main font, so you can embed icons directly from your strings without having to change fonts back and forth. +- To refer to the icon UTF-8 codepoints from your C++ code, you may use those headers files created by Juliette Foucaut: + https://github.com/juliettef/IconFontCppHeaders +**The C++11 version of those files uses the u8"" utf-8 encoding syntax + \u** + + ` #define ICON_FA_SEARCH u8"\uf002" ` + +**The pre-C++11 version has the values directly encoded as utf-8:** + + ` #define ICON_FA_SEARCH "\xEF\x80\x82" ` + +Example Setup: +```cpp + // Merge icons into default tool font + #include "IconsFontAwesome.h" ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontDefault(); -Load .TTF/.OTF file with: + ImFontConfig config; + config.MergeMode = true; + config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced + static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; + io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config, icon_ranges); +``` +Example Usage: +```cpp + // Usage, e.g. + ImGui::Text("%s among %d items", ICON_FA_SEARCH, count); + ImGui::Button(ICON_FA_SEARCH " Search"); + // C string _literals_ can be concatenated at compilation time, e.g. "hello" " world" + // ICON_FA_SEARCH is defined as a string literal so this is the same as "A" "B" becoming "AB" +``` +See Links below for other icons fonts and related tools. + +--------------------------------------- + ## Font Loading Instructions + +Load default font: +```cpp ImGuiIO& io = ImGui::GetIO(); - io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); - -Load multiple fonts: - + io.Fonts->AddFontDefault(); +``` +Load .TTF/.OTF file with: +```cpp ImGuiIO& io = ImGui::GetIO(); ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf", size_pixels); // Select font at runtime - ImGui::Text("Hello"); // use the default font (which is the first loaded font) + ImGui::Text("Hello"); // use the default font (which is the first loaded font) ImGui::PushFont(font2); ImGui::Text("Hello with another font"); ImGui::PopFont(); - +``` For advanced options create a ImFontConfig structure and pass it to the AddFont function (it will be copied internally): - +```cpp ImFontConfig config; config.OversampleH = 2; config.OversampleV = 1; config.GlyphExtraSpacing.x = 1.0f; ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); +``` +**Read about oversampling [here](https://github.com/nothings/stb/blob/master/tests/oversample)** + +- If you have very large number of glyphs or multiple fonts, the texture may become too big for your graphics API. +- The typical result of failing to upload a texture is if every glyphs appears as white rectangles. +- In particular, using a large range such as GetGlyphRangesChineseSimplifiedCommon() is not recommended unless you set OversampleH/OversampleV to 1 and use a small font size. +- Mind the fact that some graphics drivers have texture size limitation. +- If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. + +Some solutions: + + 1. Reduce glyphs ranges by calculating them from source localization data. + You can use ImFontGlyphRangesBuilder for this purpose, this will be the biggest win! + 2. You may reduce oversampling, e.g. config.OversampleH = config.OversampleV = 1, this will largely reduce your texture size. + 3. Set io.Fonts.TexDesiredWidth to specify a texture width to minimize texture height (see comment in ImFontAtlas::Build function). + 4. Set io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; to disable rounding the texture height to the next power of two. Combine two fonts into one: - +```cpp // Load a first font ImFont* font = io.Fonts->AddFontDefault(); @@ -92,28 +141,9 @@ Combine two fonts into one: io.Fonts->AddFontFromFileTTF("DroidSans.ttf", 18.0f, &config, io.Fonts->GetGlyphRangesJapanese()); io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 18.0f, &config, icons_ranges); io.Fonts->Build(); - -Font atlas is too large? - -- If you have very large number of glyphs or multiple fonts, the texture may become too big for your graphics API. -- The typical result of failing to upload a texture is if every glyphs appears as white rectangles. -- In particular, using a large range such as GetGlyphRangesChineseSimplifiedCommon() is not recommended - unless you set OversampleH/OversampleV to 1 and use a small font size. -- Mind the fact that some graphics drivers have texture size limitation. -- If you are building a PC application, mind the fact that users may run on hardware with lower specs than yours. - -Some solutions: - - - 1) Reduce glyphs ranges by calculating them from source localization data. - You can use ImFontGlyphRangesBuilder for this purpose, this will be the biggest win! - - 2) You may reduce oversampling, e.g. config.OversampleH = config.OversampleV = 1, this will largely reduce your texture size. - - 3) Set io.Fonts.TexDesiredWidth to specify a texture width to minimize texture height (see comment in ImFontAtlas::Build function). - - 4) Set io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; to disable rounding the texture height to the next power of two. - - Read about oversampling here: https://github.com/nothings/stb/blob/master/tests/oversample - - +``` Add a fourth parameter to bake specific font ranges only: - +```cpp // Basic Latin, Extended Latin io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesDefault()); @@ -122,79 +152,31 @@ Add a fourth parameter to bake specific font ranges only: // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); - -See "BUILDING CUSTOM GLYPH RANGES" section to create your own ranges. +``` +See [Building Custom Glyph Ranges](#building-custom-glyph-ranges) section to create your own ranges. Offset font vertically by altering the io.Font->DisplayOffset value: - +```cpp ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); font->DisplayOffset.y = 1; // Render 1 pixel down +``` + +--------------------------------------- + ## Freetype Rasterizer, Small Font Sizes + +- Dear ImGui uses imstb\_truetype.h to rasterize fonts (with optional oversampling). This technique and its implementation are not ideal for fonts rendered at small sizes, which may appear a little blurry or hard to read. +- There is an implementation of the ImFontAtlas builder using FreeType that you can use in the misc/freetype/ folder. +- FreeType supports auto-hinting which tends to improve the readability of small fonts. + +**Note** +- This code currently creates textures that are unoptimally too large (could be fixed with some work). +- Also note that correct sRGB space blending will have an important effect on your font rendering quality. --------------------------------------- - USING ICONS ---------------------------------------- - -Using an icon font (such as FontAwesome: http://fontawesome.io or OpenFontIcons. https://github.com/traverseda/OpenFontIcons) -is an easy and practical way to use icons in your Dear ImGui application. -A common pattern is to merge the icon font within your main font, so you can embed icons directly from your strings without -having to change fonts back and forth. - -To refer to the icon UTF-8 codepoints from your C++ code, you may use those headers files created by Juliette Foucaut: - - https://github.com/juliettef/IconFontCppHeaders - -Those files contains a bunch of named #define which you can use to refer to specific icons of the font, e.g.: - - #define ICON_FA_MUSIC "\xef\x80\x81" - #define ICON_FA_SEARCH "\xef\x80\x82" - -Example Setup: - - // Merge icons into default tool font - #include "IconsFontAwesome.h" - ImGuiIO& io = ImGui::GetIO(); - io.Fonts->AddFontDefault(); - - ImFontConfig config; - config.MergeMode = true; - config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced - static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; - io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config, icon_ranges); - -Example Usage: - - // Usage, e.g. - ImGui::Text("%s among %d items", ICON_FA_SEARCH, count); - ImGui::Button(ICON_FA_SEARCH " Search"); - -Important to understand: C string _literals_ can be concatenated at compilation time, e.g. "hello" " world" -ICON_FA_SEARCH is defined as a string literal so this is the same as "A" "B" becoming "AB" - -See Links below for other icons fonts and related tools. - - ---------------------------------------- - FREETYPE RASTERIZER, SMALL FONT SIZES ---------------------------------------- - -Dear ImGui uses imstb_truetype.h to rasterize fonts (with optional oversampling). -This technique and its implementation are not ideal for fonts rendered at _small sizes_, which may appear a -little blurry or hard to read. - -There is an implementation of the ImFontAtlas builder using FreeType that you can use in the misc/freetype/ folder. - -FreeType supports auto-hinting which tends to improve the readability of small fonts. -Note that this code currently creates textures that are unoptimally too large (could be fixed with some work). -Also note that correct sRGB space blending will have an important effect on your font rendering quality. - - ---------------------------------------- - BUILDING CUSTOM GLYPH RANGES ---------------------------------------- - -You can use the ImFontGlyphRangesBuilder helper to create glyph ranges based on text input. -For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. + ## Building Custom Glyph Ranges +You can use the ImFontGlyphRangesBuilder helper to create glyph ranges based on text input. For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. +```cpp ImVector ranges; ImFontGlyphRangesBuilder builder; builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) @@ -204,21 +186,18 @@ For example: for a game where your script is known, if you can feed your entire io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data); io.Fonts->Build(); // Build the atlas while 'ranges' is still in scope and not deleted. - +``` --------------------------------------- - USING CUSTOM COLORFUL ICONS ---------------------------------------- +## Using Custom Colorful Icons -(This is a BETA api, use if you are familiar with dear imgui and with your rendering back-end) +**(This is a BETA api, use if you are familiar with dear imgui and with your rendering back-end)** -You can use the ImFontAtlas::AddCustomRect() and ImFontAtlas::AddCustomRectFontGlyph() api to register rectangles -that will be packed into the font atlas texture. Register them before building the atlas, then call Build(). -You can then use ImFontAtlas::GetCustomRectByIndex(int) to query the position/size of your rectangle within the -texture, and blit/copy any graphics data of your choice into those rectangles. - -Pseudo-code: +- You can use the ImFontAtlas::AddCustomRect() and ImFontAtlas::AddCustomRectFontGlyph() api to register rectangles that will be packed into the font atlas texture. Register them before building the atlas, then call Build(). +- You can then use ImFontAtlas::GetCustomRectByIndex(int) to query the position/size of your rectangle within the texture, and blit/copy any graphics data of your choice into those rectangles. +#### Pseudo-code: +``` // Add font, then register two custom 13x13 rectangles mapped to glyph 'a' and 'b' of this font ImFont* font = io.Fonts->AddFontDefault(); int rect_ids[2]; @@ -247,29 +226,25 @@ Pseudo-code: } } } - +``` --------------------------------------- - EMBEDDING FONTS IN SOURCE CODE ---------------------------------------- + ## Embedding Fonts In Source Code -Compile and use 'binary_to_compressed_c.cpp' to create a compressed C style array that you can embed in source code. -See the documentation in binary_to_compressed_c.cpp for instruction on how to use the tool. -You may find a precompiled version binary_to_compressed_c.exe for Windows instead of demo binaries package (see README). -The tool can optionally output Base85 encoding to reduce the size of _source code_ but the read-only arrays in the -actual binary will be about 20% bigger. +- Compile and use 'binary\_to\_compressed\_c.cpp' to create a compressed C style array that you can embed in source code. +- See the documentation in binary\_to\_compressed\_c.cpp for instruction on how to use the tool. +- You may find a precompiled version binary_to_compressed_c.exe for Windows instead of demo binaries package (see README). +- The tool can optionally output Base85 encoding to reduce the size of _source code_ but the read-only arrays in the actual binary will be about 20% bigger. Then load the font with: - ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...); -or: - ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(compressed_data_base85, size_pixels, ...); + ` ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...); ` +or + `ImFont* font = io.Fonts- AddFontFromMemoryCompressedBase85TTF(compressed_data_base85, size_pixels, ...); + ` --------------------------------------- - CREDITS/LICENSES FOR FONTS INCLUDED IN REPOSITORY ---------------------------------------- - -Some fonts are available in the misc/fonts/ folder: + ## Credits/Licenses For Fonts Included In This Folder Roboto-Medium.ttf @@ -309,10 +284,9 @@ Karla-Regular.ttf --------------------------------------- - FONTS LINKS ---------------------------------------- + ## Font Links -ICON FONTS +#### ICON FONTS C/C++ header for icon fonts (#define with code points to use in source code string literals) https://github.com/juliettef/IconFontCppHeaders @@ -332,7 +306,7 @@ ICON FONTS IcoMoon - Custom Icon font builder https://icomoon.io/app -REGULAR FONTS +#### REGULAR FONTS Google Noto Fonts (worldwide languages) https://www.google.com/get/noto/ @@ -343,17 +317,15 @@ REGULAR FONTS (Japanese) M+ fonts by Coji Morishita are free http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html -MONOSPACE FONTS (PIXEL PERFECT) +#### MONOSPACE FONTS - Proggy Fonts, by Tristan Grimmer + (Pixel Perfect) Proggy Fonts, by Tristan Grimmer http://www.proggyfonts.net or http://upperbounds.net - Sweet16, Sweet16 Mono, by Martin Sedlak (Latin + Supplemental + Extended A) + (Pixel Perfect) Sweet16, Sweet16 Mono, by Martin Sedlak (Latin + Supplemental + Extended A) https://github.com/kmar/Sweet16Font Also include .inl file to use directly in dear imgui. -MONOSPACE FONTS (REGULAR) - Google Noto Mono Fonts https://www.google.com/get/noto/ From 40b799023b6dc3820c9040df55723d8d4a801897 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 9 Jun 2020 16:29:00 +0200 Subject: [PATCH 12/16] Docs: Update fonts.md (#2861) + update all references to FONTS.txt --- docs/FAQ.md | 8 +- docs/FONTS.md | 491 +++++++++++----------- examples/example_allegro5/main.cpp | 2 +- examples/example_emscripten/main.cpp | 2 +- examples/example_glfw_opengl2/main.cpp | 2 +- examples/example_glfw_opengl3/main.cpp | 2 +- examples/example_glfw_vulkan/main.cpp | 2 +- examples/example_glut_opengl2/main.cpp | 2 +- examples/example_marmalade/main.cpp | 2 +- examples/example_sdl_directx11/main.cpp | 2 +- examples/example_sdl_opengl2/main.cpp | 2 +- examples/example_sdl_opengl3/main.cpp | 2 +- examples/example_sdl_vulkan/main.cpp | 2 +- examples/example_win32_directx10/main.cpp | 2 +- examples/example_win32_directx11/main.cpp | 2 +- examples/example_win32_directx12/main.cpp | 2 +- examples/example_win32_directx9/main.cpp | 2 +- imgui.cpp | 2 +- imgui.h | 4 +- imgui_demo.cpp | 12 +- 20 files changed, 277 insertions(+), 270 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 6c1407607..15e2cd731 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -454,7 +454,7 @@ Default is ProggyClean.ttf, monospace, rendered at size 13, embedded in dear img (Tip: monospace fonts are convenient because they allow to facilitate horizontal alignment directly at the string level.) -(Read the [docs/FONTS.txt](https://github.com/ocornut/imgui/blob/master/docs/FONTS.txt) file for more details about font loading.) +(Read the [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) file for more details about font loading.) New programmers: remember that in C/C++ and most programming languages if you want to use a backslash \ within a string literal, you need to write it double backslash "\\": @@ -473,9 +473,9 @@ io.Fonts->AddFontFromFileTTF("MyFolder/MyFont.ttf", size); // ALSO CORRECT The most convenient and practical way is to merge an icon font such as FontAwesome inside you main font. Then you can refer to icons within your strings. You may want to see `ImFontConfig::GlyphMinAdvanceX` to make your icon look monospace to facilitate alignment. -(Read the [docs/FONTS.txt](https://github.com/ocornut/imgui/blob/master/docs/FONTS.txt) file for more details about icons font loading.) +(Read the [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) file for more details about icons font loading.) With some extra effort, you may use colorful icon by registering custom rectangle space inside the font atlas, -and copying your own graphics data into it. See docs/FONTS.txt about using the AddCustomRectFontGlyph API. +and copying your own graphics data into it. See docs/FONTS.md about using the AddCustomRectFontGlyph API. ##### [Return to Index](#index) @@ -483,7 +483,7 @@ and copying your own graphics data into it. See docs/FONTS.txt about using the A ### Q: How can I load multiple fonts? Use the font atlas to pack them into a single texture: -(Read the [docs/FONTS.txt](https://github.com/ocornut/imgui/blob/master/docs/FONTS.txt) file and the code in ImFontAtlas for more details.) +(Read the [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md) file and the code in ImFontAtlas for more details.) ```cpp ImGuiIO& io = ImGui::GetIO(); diff --git a/docs/FONTS.md b/docs/FONTS.md index 9f5c7d7f2..d2f40f2be 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -1,272 +1,306 @@ -## Fonts +## Dear ImGui: Using Fonts + +(You may browse this document at https://github.com/ocornut/imgui/blob/master/docs/FONTS.md or view this file with any Markdown viewer.) The code in imgui.cpp embeds a copy of 'ProggyClean.ttf' (by Tristan Grimmer), -a 13 pixels high, pixel-perfect font used by default. We embed it font in source code so you can use Dear ImGui without any file system access. +a 13 pixels high, pixel-perfect font used by default. We embed it in the source code so you can use Dear ImGui without any file system access. ProggyClean does not scale smoothly, therefore it is recommended that you load your own file when using Dear ImGui in an application aiming to look nice and wanting to support multiple resolutions. -You may also load external .TTF/.OTF files. The files in this folder are suggested fonts, provided as a convenience. +You may also load external .TTF/.OTF files. +In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) folder you can find a few suggested fonts, provided as a convenience. -Fonts are rasterized in a single texture at the time of calling either of +**Read the FAQ:** https://www.dearimgui.org/faq (there is a Fonts section!) -- `io.Fonts->GetTexDataAsAlpha8()` - -- `GetTexDataAsRGBA32()/Build()` - -**Please read the FAQ:** https://www.dearimgui.org/faq -Please use the Discord server: http://discord.dearimgui.org and not the GitHub issue tracker for basic font loading questions. - - ---------------------------------------- -| Index | -|:---------------------------------------| -| [Readme First](#readme-first) | -| [Using Icons](#using-icons) | -| [Fonts Loading Instructions](#font-loading-instructions) | -| [FreeType Rasterizer, Small Font Sizes](#freeType-rasterizer-small-font-sizes) | -| [Building Custom Glyph Ranges](#building-custom-glyph-ranges) | -| [Using Custom Colorful Icons](#using-custom-colorful-icons) | -| [Embedding Fonts In Source Code](#embedding-fonts-in-source-code) | -| [Credits/Licenses For Fonts Included In This Folder](#creditslicenses-for-fonts-included-in-this-folder) | -| [Font Links](#font-links) | +**Use the Discord server**: http://discord.dearimgui.org and not the GitHub issue tracker for basic font loading questions. +## Index +- [Readme First](#readme-first) +- [Fonts Loading Instructions](#font-loading-instructions) +- [Using Icons](#using-icons) +- [Using FreeType Rasterizer](#using-freetype-rasterizer) +- [Using Custom Glyph Ranges](#using-custom-glyph-ranges) +- [Using Custom Colorful Icons](#using-custom-colorful-icons) +- [Using Font Data Embedded In Source Code](#using-font-data-embedded-in-source-code) +- [About filenames](#about-filenames) +- [Credits/Licenses For Fonts Included In Repository](#creditslicenses-for-fonts-included-in-repository) +- [Font Links](#font-links) --------------------------------------- ## Readme First -- You can use the style editor ImGui::ShowStyleEditor() in the "Fonts" section to browse your fonts - and understand what's going on if you have an issue. -- Make sure your font ranges data are persistent (available during the call to GetTexDataAsAlpha8()/GetTexDataAsRGBA32()/Build(). +- All loaded fonts glyphs are rendered into a single texture atlas ahead of time. Calling either of `io.Fonts->GetTexDataAsAlpha8()`, `io.Fonts->GetTexDataAsRGBA32()` or `io.Fonts->Build()` will build the atlas. + +- You can use the style editor `ImGui::ShowStyleEditor()` in the "Fonts" section to browse your fonts and understand what's going on if you have an issue. You can also reach it in `Demo->Tools->Style Editor->Fonts`: + +![imgui_capture_0008](https://user-images.githubusercontent.com/8225057/84162822-1a731f00-aa71-11ea-9b6b-89c2332aa161.png) + +- Make sure your font ranges data are persistent (available during the calls to `GetTexDataAsAlpha8()`/`GetTexDataAsRGBA32()/`Build()`. + - Use C++11 u8"my text" syntax to encode literal strings as UTF-8. e.g.: - ``` - u8"hello" - u8"こんにちは" // this will be encoded as UTF-8 - ``` -- If you want to include a backslash \ character in your string literal, you need to double them e.g. "folder\\\filename". - - ---------------------------------------- - ## Using Icons - -- Using an icon font (such as [FontAwesome](http://fontawesome.io) or [OpenFontIcons](https://github.com/traverseda/OpenFontIcons)) is an easy and practical way to use icons in your Dear ImGui application. -- A common pattern is to merge the icon font within your main font, so you can embed icons directly from your strings without having to change fonts back and forth. -- To refer to the icon UTF-8 codepoints from your C++ code, you may use those headers files created by Juliette Foucaut: - https://github.com/juliettef/IconFontCppHeaders - -**The C++11 version of those files uses the u8"" utf-8 encoding syntax + \u** - - ` #define ICON_FA_SEARCH u8"\uf002" ` - -**The pre-C++11 version has the values directly encoded as utf-8:** - - ` #define ICON_FA_SEARCH "\xEF\x80\x82" ` - -Example Setup: ```cpp - // Merge icons into default tool font - #include "IconsFontAwesome.h" - ImGuiIO& io = ImGui::GetIO(); - io.Fonts->AddFontDefault(); - - ImFontConfig config; - config.MergeMode = true; - config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced - static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; - io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config, icon_ranges); +u8"hello" +u8"こんにちは" // this will be encoded as UTF-8 ``` -Example Usage: + +##### [Return to Index](#index) + +## Font Loading Instructions + +**Load default font:** ```cpp - // Usage, e.g. - ImGui::Text("%s among %d items", ICON_FA_SEARCH, count); - ImGui::Button(ICON_FA_SEARCH " Search"); - // C string _literals_ can be concatenated at compilation time, e.g. "hello" " world" - // ICON_FA_SEARCH is defined as a string literal so this is the same as "A" "B" becoming "AB" +ImGuiIO& io = ImGui::GetIO(); +io.Fonts->AddFontDefault(); ``` -See Links below for other icons fonts and related tools. - ---------------------------------------- - ## Font Loading Instructions - -Load default font: +**Load .TTF/.OTF file with:** ```cpp - ImGuiIO& io = ImGui::GetIO(); - io.Fonts->AddFontDefault(); +ImGuiIO& io = ImGui::GetIO(); +io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); ``` -Load .TTF/.OTF file with: -```cpp - ImGuiIO& io = ImGui::GetIO(); - ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); - ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf", size_pixels); +If you get an assert stating "Could not load font file!", your font filename is likely incorrect. Read "[About filenames](#about-filenames)" carefully. - // Select font at runtime - ImGui::Text("Hello"); // use the default font (which is the first loaded font) - ImGui::PushFont(font2); - ImGui::Text("Hello with another font"); - ImGui::PopFont(); -``` -For advanced options create a ImFontConfig structure and pass it to the AddFont function (it will be copied internally): +**Load multiple fonts:** ```cpp - ImFontConfig config; - config.OversampleH = 2; - config.OversampleV = 1; - config.GlyphExtraSpacing.x = 1.0f; - ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); -``` -**Read about oversampling [here](https://github.com/nothings/stb/blob/master/tests/oversample)** +ImGuiIO& io = ImGui::GetIO(); +ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); +ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf", size_pixels); -- If you have very large number of glyphs or multiple fonts, the texture may become too big for your graphics API. -- The typical result of failing to upload a texture is if every glyphs appears as white rectangles. -- In particular, using a large range such as GetGlyphRangesChineseSimplifiedCommon() is not recommended unless you set OversampleH/OversampleV to 1 and use a small font size. +// Select font at runtime +ImGui::Text("Hello"); // use the default font (which is the first loaded font) +ImGui::PushFont(font2); +ImGui::Text("Hello with another font"); +ImGui::PopFont(); +``` + +**For advanced options create a ImFontConfig structure and pass it to the AddFont() function (it will be copied internally):** +```cpp +ImFontConfig config; +config.OversampleH = 2; +config.OversampleV = 1; +config.GlyphExtraSpacing.x = 1.0f; +ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); +``` + +**Combine multiple fonts into one:** +```cpp +// Load a first font +ImFont* font = io.Fonts->AddFontDefault(); + +// Add character ranges and merge into the previous font +// The ranges array is not copied by the AddFont* functions and is used lazily +// so ensure it is available at the time of building or calling GetTexDataAsRGBA32(). +static const ImWchar icons_ranges[] = { 0xf000, 0xf3ff, 0 }; // Will not be copied by AddFont* so keep in scope. +ImFontConfig config; +config.MergeMode = true; +io.Fonts->AddFontFromFileTTF("DroidSans.ttf", 18.0f, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge into first font +io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 18.0f, &config, icons_ranges); // Merge into first font +io.Fonts->Build(); +``` + +**Add a fourth parameter to bake specific font ranges only:** +```cpp +// Basic Latin, Extended Latin +io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesDefault()); + +// Default + Selection of 2500 Ideographs used by Simplified Chinese +io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); + +// Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs +io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); +``` +See [Using Custom Glyph Ranges](#using-custom-glyph-ranges) section to create your own ranges. + +**Offset font vertically by altering the `io.Font->DisplayOffset` value:** +```cpp +ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); +font->DisplayOffset.y = 1; // Render 1 pixel down +``` + +**Font Atlas too large?** + +- If you have very large number of glyphs or multiple fonts, the texture may become too big for your graphics API. The typical result of failing to upload a texture is if every glyphs appears as white rectangles. +- In particular, using a large range such as `GetGlyphRangesChineseSimplifiedCommon()` is not recommended unless you set `OversampleH`/`OversampleV` to 1 and use a small font size. - Mind the fact that some graphics drivers have texture size limitation. - If you are building a PC application, mind the fact that your users may use hardware with lower limitations than yours. Some solutions: - 1. Reduce glyphs ranges by calculating them from source localization data. - You can use ImFontGlyphRangesBuilder for this purpose, this will be the biggest win! - 2. You may reduce oversampling, e.g. config.OversampleH = config.OversampleV = 1, this will largely reduce your texture size. - 3. Set io.Fonts.TexDesiredWidth to specify a texture width to minimize texture height (see comment in ImFontAtlas::Build function). - 4. Set io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight; to disable rounding the texture height to the next power of two. +1. Reduce glyphs ranges by calculating them from source localization data. + You can use the `ImFontGlyphRangesBuilder` for this purpose, this will be the biggest win! +2. You may reduce oversampling, e.g. `font_config.OversampleH = font_config.OversampleV = 1`, this will largely reduce your texture size. +3. Set `io.Fonts.TexDesiredWidth` to specify a texture width to minimize texture height (see comment in `ImFontAtlas::Build()` function). +4. Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two. +5. Read about oversampling [here](https://github.com/nothings/stb/blob/master/tests/oversample). -Combine two fonts into one: +##### [Return to Index](#index) + +## Using Icons + +Using an icon font (such as [FontAwesome](http://fontawesome.io) or [OpenFontIcons](https://github.com/traverseda/OpenFontIcons)) is an easy and practical way to use icons in your Dear ImGui application. +A common pattern is to merge the icon font within your main font, so you can embed icons directly from your strings without having to change fonts back and forth. + +To refer to the icon UTF-8 codepoints from your C++ code, you may use those headers files created by Juliette Foucaut: https://github.com/juliettef/IconFontCppHeaders. + +So you can use `ICON_FA_SEARCH` as a string that will render as a "Search" icon. + +Example Setup: ```cpp - // Load a first font - ImFont* font = io.Fonts->AddFontDefault(); +// Merge icons into default tool font +#include "IconsFontAwesome.h" +ImGuiIO& io = ImGui::GetIO(); +io.Fonts->AddFontDefault(); - // Add character ranges and merge into the previous font - // The ranges array is not copied by the AddFont* functions and is used lazily - // so ensure it is available at the time of building or calling GetTexDataAsRGBA32(). - static const ImWchar icons_ranges[] = { 0xf000, 0xf3ff, 0 }; // Will not be copied by AddFont* so keep in scope. - ImFontConfig config; - config.MergeMode = true; - io.Fonts->AddFontFromFileTTF("DroidSans.ttf", 18.0f, &config, io.Fonts->GetGlyphRangesJapanese()); - io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 18.0f, &config, icons_ranges); - io.Fonts->Build(); +ImFontConfig config; +config.MergeMode = true; +config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced +static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 }; +io.Fonts->AddFontFromFileTTF("fonts/fontawesome-webfont.ttf", 13.0f, &config, icon_ranges); ``` -Add a fourth parameter to bake specific font ranges only: +Example Usage: ```cpp - // Basic Latin, Extended Latin - io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesDefault()); - - // Default + Selection of 2500 Ideographs used by Simplified Chinese - io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); - - // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs - io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); -``` -See [Building Custom Glyph Ranges](#building-custom-glyph-ranges) section to create your own ranges. -Offset font vertically by altering the io.Font->DisplayOffset value: -```cpp - ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); - font->DisplayOffset.y = 1; // Render 1 pixel down +// Usage, e.g. +ImGui::Text("%s among %d items", ICON_FA_SEARCH, count); +ImGui::Button(ICON_FA_SEARCH " Search"); +// C string _literals_ can be concatenated at compilation time, e.g. "hello" " world" +// ICON_FA_SEARCH is defined as a string literal so this is the same as "A" "B" becoming "AB" ``` +See Links below for other icons fonts and related tools. ---------------------------------------- - ## Freetype Rasterizer, Small Font Sizes +Here's an application using icons ("Avoyd", https://www.avoyd.com): +![avoyd](https://user-images.githubusercontent.com/8225057/81696852-c15d9e80-9464-11ea-9cab-2a4d4fc84396.jpg) + +##### [Return to Index](#index) + +## Using FreeType Rasterizer - Dear ImGui uses imstb\_truetype.h to rasterize fonts (with optional oversampling). This technique and its implementation are not ideal for fonts rendered at small sizes, which may appear a little blurry or hard to read. -- There is an implementation of the ImFontAtlas builder using FreeType that you can use in the misc/freetype/ folder. +- There is an implementation of the ImFontAtlas builder using FreeType that you can use in the [misc/freetype/](https://github.com/ocornut/imgui/tree/master/misc/freetype) folder. - FreeType supports auto-hinting which tends to improve the readability of small fonts. +- Read documentation in the [misc/freetype/](https://github.com/ocornut/imgui/tree/master/misc/freetype) folder. +- Correct sRGB space blending will have an important effect on your font rendering quality. -**Note** -- This code currently creates textures that are unoptimally too large (could be fixed with some work). -- Also note that correct sRGB space blending will have an important effect on your font rendering quality. +##### [Return to Index](#index) +## Using Custom Glyph Ranges ---------------------------------------- - ## Building Custom Glyph Ranges - -You can use the ImFontGlyphRangesBuilder helper to create glyph ranges based on text input. For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. +You can use the `ImFontGlyphRangesBuilder` helper to create glyph ranges based on text input. For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs. ```cpp - ImVector ranges; - ImFontGlyphRangesBuilder builder; - builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) - builder.AddChar(0x7262); // Add a specific character - builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges - builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted) +ImVector ranges; +ImFontGlyphRangesBuilder builder; +builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters) +builder.AddChar(0x7262); // Add a specific character +builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges +builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted) - io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data); - io.Fonts->Build(); // Build the atlas while 'ranges' is still in scope and not deleted. +io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data); +io.Fonts->Build(); // Build the atlas while 'ranges' is still in scope and not deleted. ``` ---------------------------------------- +##### [Return to Index](#index) + ## Using Custom Colorful Icons **(This is a BETA api, use if you are familiar with dear imgui and with your rendering back-end)** -- You can use the ImFontAtlas::AddCustomRect() and ImFontAtlas::AddCustomRectFontGlyph() api to register rectangles that will be packed into the font atlas texture. Register them before building the atlas, then call Build(). -- You can then use ImFontAtlas::GetCustomRectByIndex(int) to query the position/size of your rectangle within the texture, and blit/copy any graphics data of your choice into those rectangles. +- You can use the `ImFontAtlas::AddCustomRect()` and `ImFontAtlas::AddCustomRectFontGlyph()` api to register rectangles that will be packed into the font atlas texture. Register them before building the atlas, then call Build()`. +- You can then use `ImFontAtlas::GetCustomRectByIndex(int)` to query the position/size of your rectangle within the texture, and blit/copy any graphics data of your choice into those rectangles. +- This API is beta because it is likely to change in order to support multi-dpi (multiple viewports on multiple monitors with varying DPI scale). #### Pseudo-code: -``` - // Add font, then register two custom 13x13 rectangles mapped to glyph 'a' and 'b' of this font - ImFont* font = io.Fonts->AddFontDefault(); - int rect_ids[2]; - rect_ids[0] = io.Fonts->AddCustomRectFontGlyph(font, 'a', 13, 13, 13+1); - rect_ids[1] = io.Fonts->AddCustomRectFontGlyph(font, 'b', 13, 13, 13+1); +```cpp +// Add font, then register two custom 13x13 rectangles mapped to glyph 'a' and 'b' of this font +ImFont* font = io.Fonts->AddFontDefault(); +int rect_ids[2]; +rect_ids[0] = io.Fonts->AddCustomRectFontGlyph(font, 'a', 13, 13, 13+1); +rect_ids[1] = io.Fonts->AddCustomRectFontGlyph(font, 'b', 13, 13, 13+1); - // Build atlas - io.Fonts->Build(); +// Build atlas +io.Fonts->Build(); - // Retrieve texture in RGBA format - unsigned char* tex_pixels = NULL; - int tex_width, tex_height; - io.Fonts->GetTexDataAsRGBA32(&tex_pixels, &tex_width, &tex_height); +// Retrieve texture in RGBA format +unsigned char* tex_pixels = NULL; +int tex_width, tex_height; +io.Fonts->GetTexDataAsRGBA32(&tex_pixels, &tex_width, &tex_height); - for (int rect_n = 0; rect_n < IM_ARRAYSIZE(rect_ids); rect_n++) - { - int rect_id = rects_ids[rect_n]; - if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) - { - // Fill the custom rectangle with red pixels (in reality you would draw/copy your bitmap data here!) - for (int y = 0; y < rect->Height; y++) - { - ImU32* p = (ImU32*)tex_pixels + (rect->Y + y) * tex_width + (rect->X); - for (int x = rect->Width; x > 0; x--) - *p++ = IM_COL32(255, 0, 0, 255); - } - } - } +for (int rect_n = 0; rect_n < IM_ARRAYSIZE(rect_ids); rect_n++) +{ + int rect_id = rects_ids[rect_n]; + if (const ImFontAtlas::CustomRect* rect = io.Fonts->GetCustomRectByIndex(rect_id)) + { + // Fill the custom rectangle with red pixels (in reality you would draw/copy your bitmap data here!) + for (int y = 0; y < rect->Height; y++) + { + ImU32* p = (ImU32*)tex_pixels + (rect->Y + y) * tex_width + (rect->X); + for (int x = rect->Width; x > 0; x--) + *p++ = IM_COL32(255, 0, 0, 255); + } + } +} ``` ---------------------------------------- - ## Embedding Fonts In Source Code +##### [Return to Index](#index) -- Compile and use 'binary\_to\_compressed\_c.cpp' to create a compressed C style array that you can embed in source code. -- See the documentation in binary\_to\_compressed\_c.cpp for instruction on how to use the tool. -- You may find a precompiled version binary_to_compressed_c.exe for Windows instead of demo binaries package (see README). +## Using Font Data Embedded In Source Code + +- Compile and use [binary_to_compressed_c.cpp](https://github.com/ocornut/imgui/blob/master/misc/fonts/binary_to_compressed_c.cpp) to create a compressed C style array that you can embed in source code. +- See the documentation in [binary_to_compressed_c.cpp](https://github.com/ocornut/imgui/blob/master/misc/fonts/binary_to_compressed_c.cpp) for instruction on how to use the tool. +- You may find a precompiled version binary_to_compressed_c.exe for Windows instead of demo binaries package (see [README](https://github.com/ocornut/imgui/blob/master/docs/README.md)). - The tool can optionally output Base85 encoding to reduce the size of _source code_ but the read-only arrays in the actual binary will be about 20% bigger. Then load the font with: - ` ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...); ` +```cpp +ImFont* font = io.Fonts->AddFontFromMemoryCompressedTTF(compressed_data, compressed_data_size, size_pixels, ...); +``` or - `ImFont* font = io.Fonts- AddFontFromMemoryCompressedBase85TTF(compressed_data_base85, size_pixels, ...); - ` +```cpp +ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(compressed_data_base85, size_pixels, ...); +``` +##### [Return to Index](#index) ---------------------------------------- - ## Credits/Licenses For Fonts Included In This Folder +## About filenames +**Please note that many new C/C++ users have issues their files _because the filename they provide is wrong_.** + +Two things to watch for: +- Make sure your IDE/debugger settings starts your executable from the right working directory. In Visual Studio you can change your working directory in project `Properties > General > Debugging > Working Directory`. People assume that their execution will start from the root folder of the project, where by default it oftens start from the folder where object or executable files are stored. +```cpp +// Relative filename depends on your Working Directory when running your program! +io.Fonts->AddFontFromFileTTF("MyImage01.jpg", ...); + +// Load from the parent folder of your Working Directory +io.Fonts->AddFontFromFileTTF("../MyImage01.jpg", ...); +``` +- In C/C++ and most programming languages if you want to use a backslash `\` within a string literal, you need to write it double backslash `\\`. At it happens, Windows uses backslashes as a path separator, so be mindful. +```cpp +io.Fonts->AddFontFromFileTTF("MyFiles\MyImage01.jpg", ...); // This is INCORRECT!! +io.Fonts->AddFontFromFileTTF("MyFiles\\MyImage01.jpg", ...); // This is CORRECT +``` +In some situations, you may also use `/` path separator under Windows. + +##### [Return to Index](#index) + +## Credits/Licenses For Fonts Included In Repository + +Some fonts files are available in the `misc/fonts/` folder: + +``` Roboto-Medium.ttf - Apache License 2.0 - by Christian Robertson + by Christian Robetson https://fonts.google.com/specimen/Roboto Cousine-Regular.ttf - by Steve Matteson Digitized data copyright (c) 2010 Google Corporation. Licensed under the SIL Open Font License, Version 1.1 https://fonts.google.com/specimen/Cousine DroidSans.ttf - Copyright (c) Steve Matteson Apache License, version 2.0 https://www.fontsquirrel.com/fonts/droid-sans ProggyClean.ttf - Copyright (c) 2004, 2005 Tristan Grimmer MIT License recommended loading setting: Size = 13.0, DisplayOffset.Y = +1 @@ -281,68 +315,41 @@ ProggyTiny.ttf Karla-Regular.ttf Copyright (c) 2012, Jonathan Pinhorn SIL OPEN FONT LICENSE Version 1.1 +``` +##### [Return to Index](#index) ---------------------------------------- - ## Font Links +## Font Links #### ICON FONTS - C/C++ header for icon fonts (#define with code points to use in source code string literals) - https://github.com/juliettef/IconFontCppHeaders - - FontAwesome - https://fortawesome.github.io/Font-Awesome - - OpenFontIcons - https://github.com/traverseda/OpenFontIcons - - Google Icon Fonts - https://design.google.com/icons/ - - Kenney Icon Font (Game Controller Icons) - https://github.com/nicodinh/kenney-icon-font - - IcoMoon - Custom Icon font builder - https://icomoon.io/app +- C/C++ header for icon fonts (#define with code points to use in source code string literals) https://github.com/juliettef/IconFontCppHeaders +- FontAwesome https://fortawesome.github.io/Font-Awesome +- OpenFontIcons https://github.com/traverseda/OpenFontIcons +- Google Icon Fonts https://design.google.com/icons/ +- Kenney Icon Font (Game Controller Icons) https://github.com/nicodinh/kenney-icon-font +- IcoMoon - Custom Icon font builder https://icomoon.io/app #### REGULAR FONTS - Google Noto Fonts (worldwide languages) - https://www.google.com/get/noto/ - - Open Sans Fonts - https://fonts.google.com/specimen/Open+Sans - - (Japanese) M+ fonts by Coji Morishita are free - http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html +- Google Noto Fonts (worldwide languages) https://www.google.com/get/noto/ +- Open Sans Fonts https://fonts.google.com/specimen/Open+Sans +- (Japanese) M+ fonts by Coji Morishita http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html #### MONOSPACE FONTS - (Pixel Perfect) Proggy Fonts, by Tristan Grimmer - http://www.proggyfonts.net or http://upperbounds.net +Pixel Perfect: +- Proggy Fonts, by Tristan Grimmer http://www.proggyfonts.net or http://upperbounds.net +- Sweet16, Sweet16 Mono, by Martin Sedlak (Latin + Supplemental + Extended A) https://github.com/kmar/Sweet16Font (also include an .inl file to use directly in dear imgui.) - (Pixel Perfect) Sweet16, Sweet16 Mono, by Martin Sedlak (Latin + Supplemental + Extended A) - https://github.com/kmar/Sweet16Font - Also include .inl file to use directly in dear imgui. +Regular: +- Google Noto Mono Fonts https://www.google.com/get/noto/ +- Typefaces for source code beautification https://github.com/chrissimpkins/codeface +- Programmation fonts http://s9w.github.io/font_compare/ +- Inconsolata http://www.levien.com/type/myfonts/inconsolata.html +- Adobe Source Code Pro: Monospaced font family for ui & coding environments https://github.com/adobe-fonts/source-code-pro +- Monospace/Fixed Width Programmer's Fonts http://www.lowing.org/fonts/ - Google Noto Mono Fonts - https://www.google.com/get/noto/ +Or use Arial Unicode or other Unicode fonts provided with Windows for full characters coverage (not sure of their licensing). - Typefaces for source code beautification - https://github.com/chrissimpkins/codeface - - Programmation fonts - http://s9w.github.io/font_compare/ - - Inconsolata - http://www.levien.com/type/myfonts/inconsolata.html - - Adobe Source Code Pro: Monospaced font family for user interface and coding environments - https://github.com/adobe-fonts/source-code-pro - - Monospace/Fixed Width Programmer's Fonts - http://www.lowing.org/fonts/ - - - Or use Arial Unicode or other Unicode fonts provided with Windows for full characters coverage (not sure of their licensing). +##### [Return to Index](#index) diff --git a/examples/example_allegro5/main.cpp b/examples/example_allegro5/main.cpp index 5a026840a..c32125b68 100644 --- a/examples/example_allegro5/main.cpp +++ b/examples/example_allegro5/main.cpp @@ -40,7 +40,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_emscripten/main.cpp b/examples/example_emscripten/main.cpp index f0eb3a2b3..6867b4cd9 100644 --- a/examples/example_emscripten/main.cpp +++ b/examples/example_emscripten/main.cpp @@ -81,7 +81,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // - Emscripten allows preloading a file or folder to be accessible at runtime. See Makefile for details. //io.Fonts->AddFontDefault(); diff --git a/examples/example_glfw_opengl2/main.cpp b/examples/example_glfw_opengl2/main.cpp index a50b46377..411062faf 100644 --- a/examples/example_glfw_opengl2/main.cpp +++ b/examples/example_glfw_opengl2/main.cpp @@ -59,7 +59,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_glfw_opengl3/main.cpp b/examples/example_glfw_opengl3/main.cpp index 8df734bd5..6a3592f16 100644 --- a/examples/example_glfw_opengl3/main.cpp +++ b/examples/example_glfw_opengl3/main.cpp @@ -119,7 +119,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_glfw_vulkan/main.cpp b/examples/example_glfw_vulkan/main.cpp index 3ce1984a7..80763a01e 100644 --- a/examples/example_glfw_vulkan/main.cpp +++ b/examples/example_glfw_vulkan/main.cpp @@ -401,7 +401,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_glut_opengl2/main.cpp b/examples/example_glut_opengl2/main.cpp index d36c1f842..997eeaef3 100644 --- a/examples/example_glut_opengl2/main.cpp +++ b/examples/example_glut_opengl2/main.cpp @@ -125,7 +125,7 @@ int main(int argc, char** argv) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_marmalade/main.cpp b/examples/example_marmalade/main.cpp index 82435f208..9f2ef7987 100644 --- a/examples/example_marmalade/main.cpp +++ b/examples/example_marmalade/main.cpp @@ -34,7 +34,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_sdl_directx11/main.cpp b/examples/example_sdl_directx11/main.cpp index eadf8ff73..61a930709 100644 --- a/examples/example_sdl_directx11/main.cpp +++ b/examples/example_sdl_directx11/main.cpp @@ -69,7 +69,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_sdl_opengl2/main.cpp b/examples/example_sdl_opengl2/main.cpp index ff54ec411..fcd9ae325 100644 --- a/examples/example_sdl_opengl2/main.cpp +++ b/examples/example_sdl_opengl2/main.cpp @@ -57,7 +57,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp index ae794ef40..3146084dc 100644 --- a/examples/example_sdl_opengl3/main.cpp +++ b/examples/example_sdl_opengl3/main.cpp @@ -114,7 +114,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_sdl_vulkan/main.cpp b/examples/example_sdl_vulkan/main.cpp index 9eaea9451..0a2ea9ee7 100644 --- a/examples/example_sdl_vulkan/main.cpp +++ b/examples/example_sdl_vulkan/main.cpp @@ -385,7 +385,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp index 41833cb53..f6b8b2155 100644 --- a/examples/example_win32_directx10/main.cpp +++ b/examples/example_win32_directx10/main.cpp @@ -62,7 +62,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index 05de7433e..2cc36a7f1 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -62,7 +62,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 8642ad454..6ea896bc6 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -96,7 +96,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index 331236250..c8ad69f12 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -60,7 +60,7 @@ int main(int, char**) // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return NULL. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - The fonts will be rasterized at a given size (w/ oversampling) and stored into a texture when calling ImFontAtlas::Build()/GetTexDataAsXXXX(), which ImGui_ImplXXXX_NewFrame below will call. - // - Read 'docs/FONTS.txt' for more instructions and details. + // - Read 'docs/FONTS.md' for more instructions and details. // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! //io.Fonts->AddFontDefault(); //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f); diff --git a/imgui.cpp b/imgui.cpp index fd84ed030..2d740d1bd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -769,7 +769,7 @@ CODE Q: How can I easily use icons in my application? Q: How can I load multiple fonts? Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? - >> See https://www.dearimgui.org/faq and docs/FONTS.txt + >> See https://www.dearimgui.org/faq (docs/FAQ.md) docs/FONTS.md Q&A: Concerns ============= diff --git a/imgui.h b/imgui.h index b6c91a031..3f25e81eb 100644 --- a/imgui.h +++ b/imgui.h @@ -60,7 +60,7 @@ Index of this file: // Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens) #define IMGUI_VERSION "1.77 WIP" -#define IMGUI_VERSION_NUM 17601 +#define IMGUI_VERSION_NUM 17602 #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Define attributes of all API symbols declarations (e.g. for DLL under Windows) @@ -2244,7 +2244,7 @@ struct ImFontAtlas // After calling Build(), you can query the rectangle position and render your pixels. // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), // so you can render e.g. custom colorful icons and use them as regular glyphs. - // Read docs/FONTS.txt for more details about using colorful icons. + // Read docs/FONTS.md for more details about using colorful icons. // Note: this API may be redesigned later in order to support multi-monitor varying DPI settings. IMGUI_API int AddCustomRectRegular(int width, int height); IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0)); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8cece7bef..ace91fd0d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -152,7 +152,7 @@ static void ShowExampleAppCustomRendering(bool* p_open); static void ShowExampleMenuFile(); // Helper to display a little (?) mark which shows a tooltip when hovered. -// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.txt) +// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md) static void HelpMarker(const char* desc) { ImGui::TextDisabled("(?)"); @@ -861,7 +861,7 @@ static void ShowDemoWindowWidgets() if (ImGui::TreeNode("UTF-8 Text")) { // UTF-8 test with Japanese characters - // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.txt for details.) + // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.) // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8 // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you // can save your source files as 'UTF-8 without signature'). @@ -873,7 +873,7 @@ static void ShowDemoWindowWidgets() ImGui::TextWrapped( "CJK text will only appears if the font was loaded with the appropriate CJK character ranges. " "Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. " - "Read docs/FONTS.txt for details."); + "Read docs/FONTS.md for details."); ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string. ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; @@ -3538,7 +3538,7 @@ void ImGui::ShowFontSelector(const char* label) HelpMarker( "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n" "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n" - "- Read FAQ and docs/FONTS.txt for more details.\n" + "- Read FAQ and docs/FONTS.md for more details.\n" "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame()."); } @@ -3766,7 +3766,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { // Tips: in a real user application, you may want to merge and use an icon font into the main font, // so instead of "Save"/"Revert" you'd use icons! - // Read the FAQ and docs/FONTS.txt about using icon fonts. It's really easy and super convenient! + // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient! ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; } ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; } } @@ -3784,7 +3784,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) { ImGuiIO& io = ImGui::GetIO(); ImFontAtlas* atlas = io.Fonts; - HelpMarker("Read FAQ and docs/FONTS.txt for details on font loading."); + HelpMarker("Read FAQ and docs/FONTS.md for details on font loading."); ImGui::PushItemWidth(120); for (int i = 0; i < atlas->Fonts.Size; i++) { From 53f0f972737a42472fce671864cb9b5fa4514562 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 9 Jun 2020 17:29:26 +0200 Subject: [PATCH 13/16] Added FAQ entry about DPI. Added Japanese font loading example. --- docs/CHANGELOG.txt | 2 ++ docs/FAQ.md | 28 ++++++++++++++++++++++++++-- docs/FONTS.md | 34 ++++++++++++++++++++++++++++++++++ imgui.cpp | 3 ++- 4 files changed, 64 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 459bf25c5..90e06972e 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,6 +69,8 @@ Other Changes: - ImDrawList, ImDrawListSplitter, Columns: Fixed an issue where starting a split right after a callback draw command would incorrectly override the callback draw command. - Misc, Freetype: Fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails. +- Docs: Improved and moved font documentation to docs/FONTS.md so it can be readable on the web. + Updated various links/wiki accordingly. Added FAQ entry about DPI. (#2861) [@ButternCream, @ocornut] - CI: Added CI test to verify we're never accidentally dragging libstdc++ (on some compiler setups, static constructors for non-pod data seems to drag in libstdc++ due to thread-safety concerns). Fixed a static contructor which led to this dependency on some compiler setups (unclear which). diff --git a/docs/FAQ.md b/docs/FAQ.md index 15e2cd731..5e824b86d 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -27,6 +27,7 @@ or view this file with any Markdown viewer. | [How can I interact with standard C++ types (such as std::string and std::vector)?](#q-how-can-i-interact-with-standard-c-types-such-as-stdstring-and-stdvector) | | [How can I display custom shapes? (using low-level ImDrawList API)](#q-how-can-i-display-custom-shapes-using-low-level-imdrawlist-api) | | **Q&A: Fonts, Text** | +| [How should I handle DPi in my application?](#q-how-should-i-handle-dpi-in-my-application) | | [How can I load a different font than the default?](#q-how-can-i-load-a-different-font-than-the-default) | | [How can I easily use icons in my application?](#q-how-can-i-easily-use-icons-in-my-application) | | [How can I load multiple fonts?](#q-how-can-i-load-multiple-fonts) | @@ -441,10 +442,33 @@ ImGui::End(); # Q&A: Fonts, Text +### Q: How should I handle DPI in my application? + +The short answer is: obtain the desired DPI scale, load a suitable font resized with that scale (always round down font size to nearest integer), and scale your Style structure accordingly using `style.ScaleAllSizes()`. + +Your application may want to detect DPI change and reload the font and reset style being frames. + +Your ui code should avoid using hardcoded constants for size and positioning. Prefer to express values as multiple of reference values such as `ImGui::GetFontSize()` or `ImGui::GetFrameHeight()`. So e.g. instead of seeing a hardcoded height of 500 for a given item/window, you may want to use `30*ImGui::GetFontSize()` instead. + +Down the line Dear ImGui will provide a variety of standardized reference values to facilitate using this. + +Applications in the `examples/` folder are not DPI aware partly because they are unable to load a custom font from the file-system (may change that in the future). + +The reason DPI is not auto-magically solved in stock examples is that we don't yet have a satisfying solution for the "multi-dpi" problem (using the `docking` branch: when multiple viewport windows are over multiple monitors using different DPI scale). The current way to handle this on the application side is: +- Create and maintain one font atlas per active DPI scale (e.g. by iterating `platform_io.Monitors[]` before `NewFrame()`). +- Hook `platform_io.OnChangedViewport()` to detect when a `Begin()` call makes a Dear ImGui window change monitor (and therefore DPI). +- In the hook: swap atlas, swap style with correctly sized one, remap the current font from one atlas to the other (may need to maintain a remapping table of your fonts at variying DPI scale). + +This approach is relatively easy and functional but come with two issues: +- It's not possibly to reliably size or position a window ahead of `Begin()` without knowing on which monitor it'll land. +- Style override may be lost during the `Begin()` call crossing monitor boundaries. You may need to do some custom scaling mumbo-jumbo if you want your `OnChangedViewport()` handler to preserve style overrides. + +Please note that if you are not using multi-viewports with multi-monitors using different DPI scale, you can ignore all of this and use the simpler technique recommended at the top. + ### Q: How can I load a different font than the default? Use the font atlas to load the TTF/OTF file you want: -```c +```cpp ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels); io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8() @@ -459,7 +483,7 @@ Default is ProggyClean.ttf, monospace, rendered at size 13, embedded in dear img New programmers: remember that in C/C++ and most programming languages if you want to use a backslash \ within a string literal, you need to write it double backslash "\\": -```c +```cpp io.Fonts->AddFontFromFileTTF("MyFolder\MyFont.ttf", size); // WRONG (you are escaping the M here!) io.Fonts->AddFontFromFileTTF("MyFolder\\MyFont.ttf", size; // CORRECT io.Fonts->AddFontFromFileTTF("MyFolder/MyFont.ttf", size); // ALSO CORRECT diff --git a/docs/FONTS.md b/docs/FONTS.md index d2f40f2be..158e08abc 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -14,6 +14,7 @@ In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) fo ## Index - [Readme First](#readme-first) +- [How should I handle DPI in my application?](#how-should-i-handle-dpi-in-my-application) - [Fonts Loading Instructions](#font-loading-instructions) - [Using Icons](#using-icons) - [Using FreeType Rasterizer](#using-freetype-rasterizer) @@ -43,6 +44,13 @@ u8"こんにちは" // this will be encoded as UTF-8 ##### [Return to Index](#index) +## How should I handle DPI in my application? + +See [FAQ entry](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-how-should-i-handle-dpi-in-my-application). + +##### [Return to Index](#index) + + ## Font Loading Instructions **Load default font:** @@ -51,6 +59,7 @@ ImGuiIO& io = ImGui::GetIO(); io.Fonts->AddFontDefault(); ``` + **Load .TTF/.OTF file with:** ```cpp ImGuiIO& io = ImGui::GetIO(); @@ -58,6 +67,7 @@ io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); ``` If you get an assert stating "Could not load font file!", your font filename is likely incorrect. Read "[About filenames](#about-filenames)" carefully. + **Load multiple fonts:** ```cpp ImGuiIO& io = ImGui::GetIO(); @@ -71,6 +81,7 @@ ImGui::Text("Hello with another font"); ImGui::PopFont(); ``` + **For advanced options create a ImFontConfig structure and pass it to the AddFont() function (it will be copied internally):** ```cpp ImFontConfig config; @@ -80,6 +91,7 @@ config.GlyphExtraSpacing.x = 1.0f; ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config); ``` + **Combine multiple fonts into one:** ```cpp // Load a first font @@ -97,6 +109,7 @@ io.Fonts->Build(); ``` **Add a fourth parameter to bake specific font ranges only:** + ```cpp // Basic Latin, Extended Latin io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRangesDefault()); @@ -109,6 +122,27 @@ io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, NULL, io.Fonts->GetGlyphRa ``` See [Using Custom Glyph Ranges](#using-custom-glyph-ranges) section to create your own ranges. + +**Example loading and using a Japanese font:** + +```cpp +ImGuiIO& io = ImGui::GetIO(); +io.Fonts->AddFontFromFileTTF("NotoSansCJKjp-Medium.otf", 20.0f, NULL, io.Fonts->GetGlyphRangesJapanese()); +``` +```cpp +ImGui::Text(u8"こんにちは!テスト %d", 123); +if (ImGui::Button(u8"ロード")) +{ + // do stuff +} +ImGui::InputText("string", buf, IM_ARRAYSIZE(buf)); +ImGui::SliderFloat("float", &f, 0.0f, 1.0f); +``` + +![sample code output](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v160/code_sample_02_jp.png) +
_(settings: Dark style (left), Light style (right) / Font: NotoSansCJKjp-Medium, 20px / Rounding: 5)_ + + **Offset font vertically by altering the `io.Font->DisplayOffset` value:** ```cpp ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels); diff --git a/imgui.cpp b/imgui.cpp index 2d740d1bd..b05f969ad 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -765,11 +765,12 @@ CODE Q&A: Fonts, Text ================ + Q: How should I handle DPI in my application? Q: How can I load a different font than the default? Q: How can I easily use icons in my application? Q: How can I load multiple fonts? Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic? - >> See https://www.dearimgui.org/faq (docs/FAQ.md) docs/FONTS.md + >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md Q&A: Concerns ============= From 16da8e6da6ae58c9ab639eb678d69bd22e729528 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 10 Jun 2020 17:54:19 +0200 Subject: [PATCH 14/16] Revert "Columns: Lower overhead on column switches and switching to background channel (some stress tests in debug builds went 3->2 ms). (#125)" This reverts commit 9b3ce494fdee20f56ee672febe2f9d737a3927cc. --- docs/CHANGELOG.txt | 2 -- imgui.cpp | 7 +------ imgui_internal.h | 1 - imgui_widgets.cpp | 29 ++++------------------------- 4 files changed, 5 insertions(+), 34 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 90e06972e..9ca3d3870 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -46,8 +46,6 @@ Other Changes: flag was also set, and _OpenOnArrow is frequently set along with _OpenOnDoubleClick). - TreeNode: Fixed bug where dragging a payload over a TreeNode() with either _OpenOnDoubleClick or _OpenOnArrow would open the node. (#143) -- Columns: Lower overhead on column switches and switching to background channel (some of our stress - tests in debug builds went 3->2 ms). Benefits Columns but was primarily made with Tables in mind! - Style: Added style.TabMinWidthForUnselectedCloseButton settings. Set to 0.0f (default) to always make a close button appear on hover (same as Chrome, VS). Set to FLT_MAX to only display a close button when selected (merely hovering is not enough). diff --git a/imgui.cpp b/imgui.cpp index b05f969ad..4f66fda2c 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4168,12 +4168,7 @@ static void SetupDrawData(ImVector* draw_lists, ImDrawData* draw_da } } -// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering. -// - When using this function it is sane to ensure that float are perfectly rounded to integer values, -// so that e.g. (int)(max.x-min.x) in user's render produce correct result. -// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect(): -// some frequently called functions which to modify both channels and clipping simultaneously tend to use a more -// specialized code path to added extraneous updates of the underlying ImDrawCmd. +// When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result. void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect) { ImGuiWindow* window = GetCurrentWindow(); diff --git a/imgui_internal.h b/imgui_internal.h index b07c55683..7b15e63fe 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -435,7 +435,6 @@ struct IMGUI_API ImRect void ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped. void Floor() { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); } bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; } - ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); } }; // Helper: ImBitArray diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 7d5bc5cfa..2ba7c6b4f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -7549,11 +7549,6 @@ void ImGui::PushColumnsBackground() ImGuiColumns* columns = window->DC.CurrentColumns; if (columns->Count == 1) return; - - // Set cmd header ahead to avoid SetCurrentChannel+PushClipRect doing an unnecessary AddDrawCmd/Pop - //if (window->DrawList->Flags & ImDrawListFlags_Debug) IMGUI_DEBUG_LOG("PushColumnsBackground()\n"); - window->DrawList->_CmdHeader.ClipRect = columns->HostClipRect.ToVec4(); - columns->Splitter.SetCurrentChannel(window->DrawList, 0); int cmd_size = window->DrawList->CmdBuffer.Size; PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false); @@ -7567,12 +7562,6 @@ void ImGui::PopColumnsBackground() ImGuiColumns* columns = window->DC.CurrentColumns; if (columns->Count == 1) return; - - // Set cmd header ahead to avoid SetCurrentChannel+PushClipRect doing an unnecessary AddDrawCmd/Pop - //if (window->DrawList->Flags & ImDrawListFlags_Debug) IMGUI_DEBUG_LOG("PopColumnsBackground()\n"); - ImVec4 pop_clip_rect = window->DrawList->_ClipRectStack.Data[window->DrawList->_ClipRectStack.Size - 2]; - window->DrawList->_CmdHeader.ClipRect = pop_clip_rect; - columns->Splitter.SetCurrentChannel(window->DrawList, columns->Current + 1); PopClipRect(); } @@ -7695,22 +7684,11 @@ void ImGui::NextColumn() return; } PopItemWidth(); - - // Next column - if (++columns->Current == columns->Count) - columns->Current = 0; - - // As a small optimization, to avoid doing PopClipRect() + SetCurrentChannel() + PushClipRect() - // (which would needlessly attempt to update commands in the wrong channel, then pop or overwrite them), - // We use a shortcut: we override ClipRect in window and drawlist's CmdHeader + SetCurrentChannel(). - ImGuiColumnData* column = &columns->Columns[columns->Current]; - window->ClipRect = column->ClipRect; - window->DrawList->_CmdHeader.ClipRect = column->ClipRect.ToVec4(); - //PopClipRect(); + PopClipRect(); const float column_padding = g.Style.ItemSpacing.x; columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y); - if (columns->Current > 0) + if (++columns->Current < columns->Count) { // Columns 1+ ignore IndentX (by canceling it out) // FIXME-COLUMNS: Unnecessary, could be locked? @@ -7723,6 +7701,7 @@ void ImGui::NextColumn() // Column 0 honor IndentX window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f); columns->Splitter.SetCurrentChannel(window->DrawList, 1); + columns->Current = 0; columns->LineMinY = columns->LineMaxY; } window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); @@ -7730,7 +7709,7 @@ void ImGui::NextColumn() window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); window->DC.CurrLineTextBaseOffset = 0.0f; - //PushColumnClipRect(columns->Current); + PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite? // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup. float offset_0 = GetColumnOffset(columns->Current); From 64d8d302fb379dd9d7fbe5475a32bd6d61004db5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 10 Jun 2020 19:16:06 +0200 Subject: [PATCH 15/16] ImDrawList: Fixed VtxOffset change leading to unnecessary leading empty ImDrawCmd in certain cases. --- imgui.h | 1 + imgui_draw.cpp | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 3f25e81eb..4de178996 100644 --- a/imgui.h +++ b/imgui.h @@ -2075,6 +2075,7 @@ struct ImDrawList IMGUI_API void _PopUnusedDrawCmd(); IMGUI_API void _OnChangedClipRect(); IMGUI_API void _OnChangedTextureID(); + IMGUI_API void _OnChangedVtxOffset(); }; // All draw data to render a Dear ImGui frame diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 94f223ba4..5b0a98556 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -514,6 +514,21 @@ void ImDrawList::_OnChangedTextureID() curr_cmd->TextureId = _CmdHeader.TextureId; } +void ImDrawList::_OnChangedVtxOffset() +{ + // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this. + _VtxCurrentIdx = 0; + ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; + IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); + if (curr_cmd->ElemCount != 0) + { + AddDrawCmd(); + return; + } + IM_ASSERT(curr_cmd->UserCallback == NULL); + curr_cmd->VtxOffset = _CmdHeader.VtxOffset; +} + // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling) void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect) { @@ -570,8 +585,7 @@ void ImDrawList::PrimReserve(int idx_count, int vtx_count) if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset)) { _CmdHeader.VtxOffset = VtxBuffer.Size; - _VtxCurrentIdx = 0; - AddDrawCmd(); + _OnChangedVtxOffset(); } ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1]; From a933cc4f4d366340eff5c6dcb3a927478c9006a7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 11 Jun 2020 09:52:46 +0200 Subject: [PATCH 16/16] Documentation update --- docs/FAQ.md | 11 +++++++++-- docs/README.md | 29 ++++++++++++++++------------- imgui.cpp | 3 ++- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 5e824b86d..1401486ab 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -20,6 +20,7 @@ or view this file with any Markdown viewer. | [How can I use this on a machine without mouse, keyboard or screen? (input share, remote display)](#q-how-can-i-use-this-on-a-machine-without-mouse-keyboard-or-screen-input-share-remote-display) | | [I integrated Dear ImGui in my engine and the text or lines are blurry..](#q-i-integrated-dear-imgui-in-my-engine-and-the-text-or-lines-are-blurry) | | [I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-clipping-or-disappearing-when-i-move-windows-around) | +| [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries..](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries) | **Q&A: Usage** | | **[Why are multiple widgets reacting when I interact with a single one?
How can I have multiple widgets with the same label or with an empty label?](#q-why-are-multiple-widgets-reacting-when-i-interact-with-a-single-one-q-how-can-i-have-multiple-widgets-with-the-same-label-or-with-an-empty-label)** | | [How can I display an image? What is ImTextureID, how does it work?](#q-how-can-i-display-an-image-what-is-imtextureid-how-does-it-work)| @@ -27,7 +28,7 @@ or view this file with any Markdown viewer. | [How can I interact with standard C++ types (such as std::string and std::vector)?](#q-how-can-i-interact-with-standard-c-types-such-as-stdstring-and-stdvector) | | [How can I display custom shapes? (using low-level ImDrawList API)](#q-how-can-i-display-custom-shapes-using-low-level-imdrawlist-api) | | **Q&A: Fonts, Text** | -| [How should I handle DPi in my application?](#q-how-should-i-handle-dpi-in-my-application) | +| [How should I handle DPI in my application?](#q-how-should-i-handle-dpi-in-my-application) | | [How can I load a different font than the default?](#q-how-can-i-load-a-different-font-than-the-default) | | [How can I easily use icons in my application?](#q-how-can-i-easily-use-icons-in-my-application) | | [How can I load multiple fonts?](#q-how-can-i-load-multiple-fonts) | @@ -78,6 +79,9 @@ You may use the [docking](https://github.com/ocornut/imgui/tree/docking) branch Many projects are using this branch and it is kept in sync with master regularly. +You may merge in the [tables](https://github.com/ocornut/imgui/tree/tables) branch which includes: +- [Table features](https://github.com/ocornut/imgui/issues/2957) + ##### [Return to Index](#index) ---- @@ -144,11 +148,14 @@ Also make sure your orthographic projection matrix and io.DisplaySize matches yo --- ### Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. +### Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries.. You are probably mishandling the clipping rectangles in your render function. -Rectangles provided by ImGui are defined as +Each draw command needs the triangle rendered using the clipping rectangle provided in the ImDrawCmd structure (`ImDrawCmd->CllipRect`). +Rectangles provided by Dear ImGui are defined as `(x1=left,y1=top,x2=right,y2=bottom)` and **NOT** as `(x1,y1,width,height)` +Refer to rendering back-ends in the [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder for references of how to handle the `ClipRect` field. ##### [Return to Index](#index) diff --git a/docs/README.md b/docs/README.md index 5536c5bcb..df32b9c2b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,7 +5,7 @@ Dear ImGui (This library is available under a free and permissive license, but needs financial support to sustain its continued improvements. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using Dear ImGui, please consider reaching out.) Businesses: support continued development via invoiced technical support, maintenance, sponsoring contracts: -
  _E-mail: contact @ dearimgui dot org_ +
  _E-mail: contact @ dearimgui dot com_ Individuals: support continued maintenance and development with [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S). @@ -99,7 +99,7 @@ Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcas You should be able to build the examples from sources (tested on Windows/Mac/Linux). If you don't, let me know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: - [imgui-demo-binaries-20190715.zip](http://www.dearimgui.org/binaries/imgui-demo-binaries-20200412.zip) (Windows binaries, 1.76, built 2020/04/12, master branch) or [older demo binaries](http://www.dearimgui.org/binaries). -The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at different scale, and scale your style with `style.ScaleAllSizes()`. +The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at different scale, and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.org/faq)). ### Integration @@ -122,11 +122,11 @@ Also see [Wiki](https://github.com/ocornut/imgui/wiki) for more links and ideas. ### Upcoming Changes Some of the goals for 2020 are: -- Finish work on docking, tabs. (see [#2109](https://github.com/ocornut/imgui/issues/2109), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch looking for feedback) -- Finish work on multiple viewports / multiple OS windows. (see [#1542](https://github.com/ocornut/imgui/issues/1542), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch looking for feedback) -- Finish work on gamepad/keyboard controls. (see [#787](https://github.com/ocornut/imgui/issues/787)) -- Finish work on new Tables API (to replace Columns). (see [#2957](https://github.com/ocornut/imgui/issues/2957)) -- Add an automation and testing system, both to test the library and end-user apps. (see [#435](https://github.com/ocornut/imgui/issues/435)) +- Work on docking. (see [#2109](https://github.com/ocornut/imgui/issues/2109), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch) +- Work on multiple viewports / multiple OS windows. (see [#1542](https://github.com/ocornut/imgui/issues/1542), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch looking for feedback) +- Work on gamepad/keyboard controls. (see [#787](https://github.com/ocornut/imgui/issues/787)) +- Work on new Tables API (to replace Columns). (see [#2957](https://github.com/ocornut/imgui/issues/2957)) +- Work on automation and testing system, both to test the library and end-user apps. (see [#435](https://github.com/ocornut/imgui/issues/435)) - Make the examples look better, improve styles, improve font support, make the examples hi-DPI and multi-DPI aware. ### Gallery @@ -154,7 +154,7 @@ If you are new to Dear ImGui and have issues with: compiling, linking, adding fo Otherwise, for any other questions, bug reports, requests, feedback, you may post on https://github.com/ocornut/imgui/issues. Please read and fill the New Issue template carefully. -Paid private support is available for business customers (E-mail: _contact @ dearimgui dot org_). +Private support is available for paying business customers (E-mail: _contact @ dearimgui dot com_). **Which version should I get?** @@ -174,14 +174,14 @@ How to help - You may participate in the [Discord server](http://discord.dearimgui.org), [GitHub forum/issues](https://github.com/ocornut/imgui/issues). - You may help with development and submit pull requests! Please understand that by submitting a PR you are also submitting a request for the maintainer to review your code and then take over its maintenance forever. PR should be crafted both in the interest in the end-users and also to ease the maintainer into understanding and accepting it. - See [Help wanted](https://github.com/ocornut/imgui/wiki/Help-Wanted) on the [Wiki](https://github.com/ocornut/imgui/wiki/) for some more ideas. -- Have your company financially support this project. +- Have your company financially support this project (please reach by e-mail) **How can I help financing further development of Dear ImGui?** Your contributions are keeping this project alive. The library is available under a free and permissive license, but continued maintenance and development are a full-time endeavor and I would like to grow the team. In addition to maintenance and stability there are many desirable features yet to be added. If your company is using Dear ImGui, please consider reaching out for invoiced technical support and maintenance contracts. Thank you! Businesses: support continued development via invoiced technical support, maintenance, sponsoring contracts: -
  _E-mail: contact @ dearimgui dot org_ +
  _E-mail: contact @ dearimgui.com_ Individuals: support continued maintenance and development with [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WGHNC6MBFLZ2S). @@ -194,7 +194,7 @@ Ongoing Dear ImGui development is financially supported by users and private spo - [Blizzard](https://careers.blizzard.com/en-us/openings/engineering/all/all/all/1), [Google](https://github.com/google/filament), [Nvidia](https://developer.nvidia.com/nvidia-omniverse), [Ubisoft](https://montreal.ubisoft.com/en/ubisoft-sponsors-user-interface-library-for-c-dear-imgui/) *Double-chocolate and Salty caramel sponsors* -- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Arkane Studios](https://www.arkane-studios.com), [Dotemu](http://www.dotemu.com), [Framefield](http://framefield.com), [Hexagon](https://hexagonxalt.com/the-technology/xalt-visualization), [Kylotonn](https://www.kylotonn.com), [Media Molecule](http://www.mediamolecule.com), [Mesh Consultants](https://www.meshconsultants.ca), [Mobigame](http://www.mobigame.net), [Nadeo](https://www.nadeo.com), [Next Level Games](https://www.nextlevelgames.com), [Supercell](http://www.supercell.com), [Remedy Entertainment](https://www.remedygames.com/), [Unit 2 Games](https://unit2games.com/) +- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Arkane Studios](https://www.arkane-studios.com), [Dotemu](http://www.dotemu.com), [Framefield](http://framefield.com), [Hexagon](https://hexagonxalt.com/the-technology/xalt-visualization), [Kylotonn](https://www.kylotonn.com), [Media Molecule](http://www.mediamolecule.com), [Mesh Consultants](https://www.meshconsultants.ca), [Mobigame](http://www.mobigame.net), [Nadeo](https://www.nadeo.com), [Next Level Games](https://www.nextlevelgames.com), [RAD Game Tools](http://www.radgametools.com/), [Supercell](http://www.supercell.com), [Remedy Entertainment](https://www.remedygames.com/), [Unit 2 Games](https://unit2games.com/) From November 2014 to December 2019, ongoing development has also been financially supported by its users on Patreon and through individual donations. Please see [detailed list of Dear ImGui supporters](https://github.com/ocornut/imgui/wiki/Sponsors). @@ -208,9 +208,12 @@ Dear ImGui is using software and services provided free of charge for open sourc Credits ------- -Developed by [Omar Cornut](http://www.miracleworld.net) and every direct or indirect contributors to the GitHub. The early version of this library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com) (PS Vita). +Developed by [Omar Cornut](http://www.miracleworld.net) and every direct or indirect [contributors](https://github.com/ocornut/imgui/graphs/contributors) to the GitHub. The early version of this library was developed with the support of [Media Molecule](http://www.mediamolecule.com) and first used internally on the game [Tearaway](http://tearaway.mediamolecule.com) (PS Vita). -I first discovered the IMGUI paradigm at [Q-Games](http://www.q-games.com) where Atman Binstock had dropped his own simple implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating and improving it. +Recurring contributors (2020): Omar Cornut [@ocornut](https://github.com/ocornut), Rokas Kupstys [@rokups](https://github.com/rokups), Ben Carter [@ShironekoBen](https://github.com/ShironekoBen). +A large portion of work on automation systems, regression tests and other features are currently unpublished. + +"I first discovered the IMGUI paradigm at [Q-Games](http://www.q-games.com) where Atman Binstock had dropped his own simple implementation in the codebase, which I spent quite some time improving and thinking about. It turned out that Atman was exposed to the concept directly by working with Casey. When I moved to Media Molecule I rewrote a new library trying to overcome the flaws and limitations of the first one I've worked with. It became this library and since then I have spent an unreasonable amount of time iterating and improving it." Embeds [ProggyClean.ttf](http://upperbounds.net) font by Tristan Grimmer (MIT license). diff --git a/imgui.cpp b/imgui.cpp index 4f66fda2c..fcdcfd3a3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -633,7 +633,8 @@ CODE Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display) Q: I integrated Dear ImGui in my engine and the text or lines are blurry.. Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around.. - >> See https://www.dearimgui.org/faq + Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries.. +>> See https://www.dearimgui.org/faq Q&A: Usage ----------