Browse Source

Texture-based thick lines: Tweaks, fix for truetype builder.

omar 5 years ago
parent
commit
222b7ddbfa
5 changed files with 46 additions and 55 deletions
  1. 3 5
      imgui.cpp
  2. 2 2
      imgui.h
  3. 2 1
      imgui_demo.cpp
  4. 39 45
      imgui_draw.cpp
  5. 0 2
      imgui_internal.h

+ 3 - 5
imgui.cpp

@@ -935,7 +935,7 @@ ImGuiStyle::ImGuiStyle()
     DisplaySafeAreaPadding  = ImVec2(3,3);      // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
     MouseCursorScale        = 1.0f;             // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
     AntiAliasedLines        = true;             // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
-    TexturedAntiAliasedLines= true;             // Draw anti-aliased lines using textures where possible.
+    AntiAliasedLinesUseTexData = true;          // Draw anti-aliased lines using textures where possible.
     AntiAliasedFill         = true;             // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
     CurveTessellationTol    = 1.25f;            // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
     CircleSegmentMaxError   = 1.60f;            // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
@@ -3689,14 +3689,12 @@ void ImGui::NewFrame()
     g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
     if (g.Style.AntiAliasedLines)
         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
-    if (g.Style.TexturedAntiAliasedLines)
-        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_TexturedAALines;
+    if (g.Style.AntiAliasedLinesUseTexData && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoAALines))
+        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTexData;
     if (g.Style.AntiAliasedFill)
         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
     if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
-    if ((g.Style.TexturedAntiAliasedLines) && (!(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoAALines)))
-        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_TexturedAALines;
 
     g.BackgroundDrawList._ResetForNewFrame();
     g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID);

+ 2 - 2
imgui.h

@@ -1439,7 +1439,7 @@ struct ImGuiStyle
     ImVec2      DisplaySafeAreaPadding;     // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly!
     float       MouseCursorScale;           // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
     bool        AntiAliasedLines;           // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
-    bool        TexturedAntiAliasedLines;   // Draw anti-aliased lines using textures where possible.
+    bool        AntiAliasedLinesUseTexData; // Draw anti-aliased lines using textures where possible.
     bool        AntiAliasedFill;            // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU.
     float       CurveTessellationTol;       // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
     float       CircleSegmentMaxError;      // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
@@ -1999,7 +1999,7 @@ enum ImDrawListFlags_
     ImDrawListFlags_AntiAliasedLines        = 1 << 0,  // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough to be drawn using textures, otherwise *3 the number of triangles)
     ImDrawListFlags_AntiAliasedFill         = 1 << 1,  // Enable anti-aliased edge around filled shapes (rounded rectangles, circles).
     ImDrawListFlags_AllowVtxOffset          = 1 << 2,  // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled.
-    ImDrawListFlags_TexturedAALines         = 1 << 3   // Should anti-aliased lines be drawn using textures where possible?
+    ImDrawListFlags_AntiAliasedLinesUseTexData  = 1 << 3   // Should anti-aliased lines be drawn using textures where possible?
 };
 
 // Draw command list

+ 2 - 1
imgui_demo.cpp

@@ -3831,7 +3831,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
         {
             ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
             ImGui::SameLine(); HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
-            ImGui::Checkbox("Use textures for anti-aliased lines", &style.TexturedAntiAliasedLines);
+            ImGui::Checkbox("Anti-aliased lines use texture data", &style.AntiAliasedLinesUseTexData);
+            ImGui::SameLine(); HelpMarker("Faster lines using texture data. Requires texture to use bilinear sampling (not nearest).");
             ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
             ImGui::PushItemWidth(100);
             ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");

+ 39 - 45
imgui_draw.cpp

@@ -358,6 +358,7 @@ ImDrawListSharedData::ImDrawListSharedData()
         ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));
     }
     memset(CircleSegmentCounts, 0, sizeof(CircleSegmentCounts)); // This will be set by SetCircleSegmentMaxError()
+    TexUvAALines = NULL;
 }
 
 void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error)
@@ -680,18 +681,18 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
         const int integer_thickness = ImMax((int)(thickness - 0.5f), 1);
 
         // Do we want to draw this line using a texture?
-        bool use_textures = (Flags & ImDrawListFlags_TexturedAALines) && (integer_thickness <= IM_DRAWLIST_TEX_AA_LINES_WIDTH_MAX);
+        const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTexData) && (integer_thickness <= IM_DRAWLIST_TEX_AA_LINES_WIDTH_MAX);
 
-        // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_TexturedAALines unless ImFontAtlasFlags_NoAALines is off
-        IM_ASSERT_PARANOID((!use_textures) || (!(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoAALines)));
+        // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTexData unless ImFontAtlasFlags_NoAALines is off
+        IM_ASSERT_PARANOID((!use_texture) || (!(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoAALines)));
 
-        const int idx_count = use_textures ? (count * 6) : (thick_line ? count * 18 : count * 12);
-        const int vtx_count = use_textures ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3);
+        const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12);
+        const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3);
         PrimReserve(idx_count, vtx_count);
 
         // Temporary buffer
         // The first <points_count> items are normals at each line point, then after that there are either 2 or 4 temp points for each line point
-        ImVec2* temp_normals = (ImVec2*)alloca(points_count * ((thick_line && !use_textures) ? 5 : 3) * sizeof(ImVec2)); //-V630
+        ImVec2* temp_normals = (ImVec2*)alloca(points_count * ((thick_line && !use_texture) ? 5 : 3) * sizeof(ImVec2)); //-V630
         ImVec2* temp_points = temp_normals + points_count;
 
         // Calculate normals (tangents) for each line segment
@@ -708,7 +709,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
             temp_normals[points_count - 1] = temp_normals[points_count - 2];
 
         // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point
-        if ((!thick_line) || (use_textures))
+        if (!thick_line || use_texture)
         {
             // The width of the geometry we need to draw
             const float half_draw_size = (!thick_line) ? AA_SIZE : (AA_SIZE + (thickness * 0.5f));
@@ -729,7 +730,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
             for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
             {
                 const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment
-                unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_textures ? 2 : 3)); // Vertex index for end of segment
+                unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment
 
                 // Average normals
                 float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
@@ -745,7 +746,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
                 out_vtx[1].x = points[i2].x - dm_x;
                 out_vtx[1].y = points[i2].y - dm_y;
 
-                if (use_textures)
+                if (use_texture)
                 {
                     // Add indices for two triangles
                     _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri
@@ -766,7 +767,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
             }
 
             // Add vertexes for each point on the line
-            if (use_textures)
+            if (use_texture)
             {
                 // If we're using textures we only need to emit the left/right edge vertices
                 const ImVec4 tex_uvs = (*_Data->TexUvAALines)[integer_thickness - 1];
@@ -2051,7 +2052,6 @@ bool    ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
     IM_ASSERT(atlas->ConfigData.Size > 0);
 
     ImFontAtlasBuildInit(atlas);
-    ImFontAtlasBuildRegisterAALineCustomRects(atlas);
 
     // Clear atlas
     atlas->TexID = (ImTextureID)NULL;
@@ -2373,68 +2373,49 @@ static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
     atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y);
 }
 
-// Note: this is called / shared by both the stb_truetype and the FreeType builder
-void ImFontAtlasBuildInit(ImFontAtlas* atlas)
-{
-    // Register texture region for mouse cursors or standard white pixels
-    if (atlas->PackIdMouseCursors < 0)
-    {
-        if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
-            atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
-        else
-            atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2);
-    }
-}
-
 // This is called/shared by both the stb_truetype and the FreeType builder.
 const unsigned int FONT_ATLAS_AA_LINE_TEX_HEIGHT = 1; // Technically we only need 1 pixel in the ideal case but this can be increased if necessary to give a border to avoid sampling artifacts
 
-void ImFontAtlasBuildRegisterAALineCustomRects(ImFontAtlas* atlas)
+static void ImFontAtlasBuildRegisterAALineCustomRects(ImFontAtlas* atlas)
 {
-    if (atlas->AALineRectIds.size() > 0)
+    if (atlas->AALineRectIds.Size > 0)
         return;
 
     if ((atlas->Flags & ImFontAtlasFlags_NoAALines))
         return;
 
-    const int max = IM_DRAWLIST_TEX_AA_LINES_WIDTH_MAX;
-
-    for (int n = 0; n < max; n++)
+    for (int n = 0; n < IM_DRAWLIST_TEX_AA_LINES_WIDTH_MAX; n++)
     {
+        // The "width + 3" here is interesting. +2 is to give space for the end caps, but the remaining +1 is
+        // because (empirically) to match the behavior of the untextured render path we need to draw lines one pixel wider.
         const int width = n + 1; // The line width this entry corresponds to
-        // The "width + 3" here is interesting - +2 is to give space for the end caps, but the remaining +1 is because (empirically) to match the behaviour of the untextured render path we need to draw lines one pixel wider
         atlas->AALineRectIds.push_back(atlas->AddCustomRectRegular(width + 3, FONT_ATLAS_AA_LINE_TEX_HEIGHT));
     }
 }
 
-void ImFontAtlasBuildAALinesTexData(ImFontAtlas* atlas)
+static void ImFontAtlasBuildRenderAALinesTexData(ImFontAtlas* atlas)
 {
     IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
-    IM_ASSERT(atlas->TexUvAALines.size() == 0);
+    IM_ASSERT(atlas->TexUvAALines.Size == 0);
 
     if (atlas->Flags & ImFontAtlasFlags_NoAALines)
         return;
 
     const int w = atlas->TexWidth;
-    const unsigned int max = IM_DRAWLIST_TEX_AA_LINES_WIDTH_MAX;
-
-    for (unsigned int n = 0; n < max; n++)
+    for (unsigned int n = 0; n < IM_DRAWLIST_TEX_AA_LINES_WIDTH_MAX; n++)
     {
-        IM_ASSERT(atlas->AALineRectIds.size() > (int)n);
-        ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->AALineRectIds[n]];
+        IM_ASSERT(atlas->AALineRectIds.Size > (int)n);
+        ImFontAtlasCustomRect& r = atlas->CustomRects[atlas->AALineRectIds[n]];
         IM_ASSERT(r.IsPacked());
 
         // We fill as many lines as we were given, to allow for >1 lines being used to work around sampling weirdness
         for (unsigned int y = 0; y < r.Height; y++)
         {
-            unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r.X + ((r.Y + y) * w)];
-
             // Each line consists of two empty pixels at the ends, with a line of solid pixels in the middle
+            unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r.X + ((r.Y + y) * w)];
             *(write_ptr++) = 0;
             for (unsigned short x = 0; x < (r.Width - 2U); x++)
-            {
                 *(write_ptr++) = 0xFF;
-            }
             *(write_ptr++) = 0;
         }
 
@@ -2445,14 +2426,27 @@ void ImFontAtlasBuildAALinesTexData(ImFontAtlas* atlas)
     }
 }
 
+// Note: this is called / shared by both the stb_truetype and the FreeType builder
+void ImFontAtlasBuildInit(ImFontAtlas* atlas)
+{
+    // Register texture region for mouse cursors or standard white pixels
+    if (atlas->PackIdMouseCursors < 0)
+    {
+        if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
+            atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
+        else
+            atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2);
+    }
+
+    ImFontAtlasBuildRegisterAALineCustomRects(atlas);
+}
+
+// This is called/shared by both the stb_truetype and the FreeType builder.
 void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
 {
     // Render into our custom data blocks
-    IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
     ImFontAtlasBuildRenderDefaultTexData(atlas);
-
-    // Render anti-aliased line textures
-    ImFontAtlasBuildAALinesTexData(atlas);
+    ImFontAtlasBuildRenderAALinesTexData(atlas);
 
     // Register custom rectangle glyphs
     for (int i = 0; i < atlas->CustomRects.Size; i++)

+ 0 - 2
imgui_internal.h

@@ -2023,10 +2023,8 @@ namespace ImGui
 // ImFontAtlas internals
 IMGUI_API bool              ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas);
 IMGUI_API void              ImFontAtlasBuildInit(ImFontAtlas* atlas);
-IMGUI_API void              ImFontAtlasBuildRegisterAALineCustomRects(ImFontAtlas* atlas);
 IMGUI_API void              ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
 IMGUI_API void              ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque);
-IMGUI_API void              ImFontAtlasBuildAALinesTexData(ImFontAtlas* atlas);
 IMGUI_API void              ImFontAtlasBuildFinish(ImFontAtlas* atlas);
 IMGUI_API void              ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
 IMGUI_API void              ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);