diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index db2549041..5fd2f0c93 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -137,6 +137,7 @@ Other Changes: calculated text width. Among noticeable side-effects, it would make sequences of repeated Text/SameLine calls not align the same as a single call, and create mismatch between high-level size calculation and those performed with the lower-level ImDrawList api. (#792) [@SlNPacifist] +- Font: Fixed building atlas when specifying duplicate/overlapping ranges within a same font. (#2353, #2233) - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] - ImGuiTextBuffer: Added append() function (unformatted). @@ -145,8 +146,8 @@ Other Changes: - ImFontAtlas: FreeType: Fixed using imgui_freetype.cpp in unity builds. (#2302) - Demo: Fixed "Log" demo not initializing properly, leading to the first line not showing before a Clear. (#2318) [@bluescan] - Demo: Added "Auto-scroll" option in Log/Console demos. (#2300) [@nicolasnoble, @ocornut] -- Examples: Metal, OpenGL2, OpenGL3: Fixed offsetting of clipping rectangle with ImDrawData::DisplayPos != (0,0) when - the display frame-buffer scale scale is not (1,1). While this doesn't make a difference when using master branch, +- Examples: Metal, OpenGL2, OpenGL3, Vulkan: Fixed offsetting of clipping rectangle with ImDrawData::DisplayPos != (0,0) + when the display frame-buffer scale scale is not (1,1). While this doesn't make a difference when using master branch, this is effectively fixing support for multi-viewport with Mac Retina Displays on those examples. (#2306) [@rasky, @ocornut] Also using ImDrawData::FramebufferScale instead of io.DisplayFramebufferScale. - Examples: Clarified the use the ImDrawData::DisplayPos to offset clipping rectangles. diff --git a/examples/example_apple_opengl2/main.mm b/examples/example_apple_opengl2/main.mm index 25316be8d..b5442ec48 100644 --- a/examples/example_apple_opengl2/main.mm +++ b/examples/example_apple_opengl2/main.mm @@ -91,7 +91,6 @@ ImGui::Render(); [[self openGLContext] makeCurrentContext]; - ImGuiIO& io = ImGui::GetIO(); ImDrawData* draw_data = ImGui::GetDrawData(); GLsizei width = (GLsizei)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); GLsizei height = (GLsizei)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); diff --git a/examples/imgui_impl_vulkan.cpp b/examples/imgui_impl_vulkan.cpp index 5797e60b7..5b28205be 100644 --- a/examples/imgui_impl_vulkan.cpp +++ b/examples/imgui_impl_vulkan.cpp @@ -14,6 +14,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2019-02-16: Vulkan: Viewport and clipping rectangles correctly using draw_data->FramebufferScale to allow retina display. // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. // 2018-08-25: Vulkan: Fixed mishandled VkSurfaceCapabilitiesKHR::maxImageCount=0 case. // 2018-06-22: Inverted the parameters to ImGui_ImplVulkan_RenderDrawData() to be consistent with other bindings. @@ -207,10 +208,13 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer) { - VkResult err; - if (draw_data->TotalVtxCount == 0) + // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) + int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); + int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); + if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0) return; + VkResult err; FrameDataForRender* fd = &g_FramesDataBuffers[g_FrameIndex]; g_FrameIndex = (g_FrameIndex + 1) % IMGUI_VK_QUEUED_FRAMES; @@ -271,8 +275,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm VkViewport viewport; viewport.x = 0; viewport.y = 0; - viewport.width = draw_data->DisplaySize.x; - viewport.height = draw_data->DisplaySize.y; + viewport.width = (float)fb_width; + viewport.height = (float)fb_height; viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; vkCmdSetViewport(command_buffer, 0, 1, &viewport); @@ -291,10 +295,13 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm vkCmdPushConstants(command_buffer, g_PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate); } - // Render the command lists: + // Will project scissor/clipping rectangles into framebuffer space + ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports + ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) + + // Render command lists int vtx_offset = 0; int idx_offset = 0; - ImVec2 clip_off = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; @@ -307,17 +314,26 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm } else { - // Apply scissor/clipping rectangle - // FIXME: We could clamp width/height based on clamped min/max values. - VkRect2D scissor; - scissor.offset.x = (int32_t)(pcmd->ClipRect.x - clip_off.x) > 0 ? (int32_t)(pcmd->ClipRect.x - clip_off.x) : 0; - scissor.offset.y = (int32_t)(pcmd->ClipRect.y - clip_off.y) > 0 ? (int32_t)(pcmd->ClipRect.y - clip_off.y) : 0; - scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x); - scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here? - vkCmdSetScissor(command_buffer, 0, 1, &scissor); + // Project scissor/clipping rectangles into framebuffer space + ImVec4 clip_rect; + clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; + clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; + clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; + clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; - // Draw - vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0); + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) + { + // Apply scissor/clipping rectangle + VkRect2D scissor; + scissor.offset.x = (int32_t)(clip_rect.x); + scissor.offset.y = (int32_t)(clip_rect.y); + scissor.extent.width = (uint32_t)(clip_rect.z - clip_rect.x); + scissor.extent.height = (uint32_t)(clip_rect.w - clip_rect.y); + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + + // Draw + vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0); + } } idx_offset += pcmd->ElemCount; } diff --git a/imgui.h b/imgui.h index 1156624f0..550768463 100644 --- a/imgui.h +++ b/imgui.h @@ -2171,26 +2171,26 @@ struct ImFontAtlas // ImFontAtlas automatically loads a default embedded font for you when you call GetTexDataAsAlpha8() or GetTexDataAsRGBA32(). struct ImFont { - // Members: Hot ~24/32 bytes (for CalcTextSize) - ImVector IndexAdvanceX; // 12/16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). - float FontSize; // 4 // in // // Height of characters, set during loading (don't change after loading) + // Members: Hot ~20/24 bytes (for CalcTextSize) + ImVector IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI). float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX - ImWchar FallbackChar; // 2 // in // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() + float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading) // Members: Hot ~36/48 bytes (for CalcTextSize + render loop) ImVector IndexLookup; // 12-16 // out // // Sparse. Index glyphs by Unicode code-point. ImVector Glyphs; // 12-16 // out // // All glyphs. - ImVec2 DisplayOffset; // 8 // in // = (0,0) // Offset font rendering by xx pixels const ImFontGlyph* FallbackGlyph; // 4-8 // out // = FindGlyph(FontFallbackChar) + ImVec2 DisplayOffset; // 8 // in // = (0,0) // Offset font rendering by xx pixels - // Members: Cold ~28/40 bytes + // Members: Cold ~32/40 bytes ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont. - bool DirtyLookupTables; // 1 // out // + ImWchar FallbackChar; // 2 // in // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar() float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale() - float Ascent, Descent; // 8 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] + float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs) + bool DirtyLookupTables; // 1 // out // // Methods IMGUI_API ImFont(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 6a9ee3bba..29991351c 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1846,15 +1846,14 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) { ImFontBuildSrcData& src_tmp = src_tmp_array[src_i]; ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; - ImFontConfig& cfg = atlas->ConfigData[src_i]; src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1); - if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty()) + if (dst_tmp.GlyphsSet.Storage.empty()) dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) { - if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite) + if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true) continue; if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint)) // It is actually in the font? continue; @@ -1863,8 +1862,7 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas) src_tmp.GlyphsCount++; dst_tmp.GlyphsCount++; src_tmp.GlyphsSet.SetBit(codepoint, true); - if (dst_tmp.SrcCount > 1) - dst_tmp.GlyphsSet.SetBit(codepoint, true); + dst_tmp.GlyphsSet.SetBit(codepoint, true); total_glyphs_count++; } } diff --git a/misc/freetype/README.md b/misc/freetype/README.md index 156e65110..4c53cd9cc 100644 --- a/misc/freetype/README.md +++ b/misc/freetype/README.md @@ -67,6 +67,7 @@ struct FreeTypeTest FontBuildMode BuildMode; bool WantRebuild; float FontsMultiply; + int FontsPadding; unsigned int FontsFlags; FreeTypeTest() @@ -74,6 +75,7 @@ struct FreeTypeTest BuildMode = FontBuildMode_FreeType; WantRebuild = true; FontsMultiply = 1.0f; + FontsPadding = 1; FontsFlags = 0; } @@ -85,8 +87,10 @@ struct FreeTypeTest ImGuiIO& io = ImGui::GetIO(); for (int n = 0; n < io.Fonts->Fonts.Size; n++) { - io.Fonts->Fonts[n]->ConfigData->RasterizerMultiply = FontsMultiply; - io.Fonts->Fonts[n]->ConfigData->RasterizerFlags = (BuildMode == FontBuildMode_FreeType) ? FontsFlags : 0x00; + ImFontConfig* font_config = (ImFontConfig*)io.Fonts->Fonts[n]->ConfigData; + io.Fonts->TexGlyphPadding = FontsPadding; + font_config->RasterizerMultiply = FontsMultiply; + font_config->RasterizerFlags = (BuildMode == FontBuildMode_FreeType) ? FontsFlags : 0x00; } if (BuildMode == FontBuildMode_FreeType) ImGuiFreeType::BuildFontAtlas(io.Fonts, FontsFlags); @@ -105,6 +109,7 @@ struct FreeTypeTest ImGui::SameLine(); WantRebuild |= ImGui::RadioButton("Stb (Default)", (int*)&BuildMode, FontBuildMode_Stb); WantRebuild |= ImGui::DragFloat("Multiply", &FontsMultiply, 0.001f, 0.0f, 2.0f); + WantRebuild |= ImGui::DragInt("Padding", &FontsPadding, 0.1f, 0, 16); if (BuildMode == FontBuildMode_FreeType) { WantRebuild |= ImGui::CheckboxFlags("NoHinting", &FontsFlags, ImGuiFreeType::NoHinting); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index f75236447..012eae75c 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -336,15 +336,14 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns { ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i]; ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; - ImFontConfig& cfg = atlas->ConfigData[src_i]; src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest + 1); - if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty()) + if (dst_tmp.GlyphsSet.Storage.empty()) dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest + 1); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++) { - if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite) + if (dst_tmp.GlyphsSet.GetBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite) continue; uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..) if (glyph_index == 0) @@ -354,8 +353,7 @@ bool ImFontAtlasBuildWithFreeType(FT_Library ft_library, ImFontAtlas* atlas, uns src_tmp.GlyphsCount++; dst_tmp.GlyphsCount++; src_tmp.GlyphsSet.SetBit(codepoint, true); - if (dst_tmp.SrcCount > 1) - dst_tmp.GlyphsSet.SetBit(codepoint, true); + dst_tmp.GlyphsSet.SetBit(codepoint, true); total_glyphs_count++; } }