Texture-based thick lines: Initial version of AA line drawing using textures (press SHIFT to enable)
diff --git a/imgui.cpp b/imgui.cpp
index d09d61e..34b6356 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -935,6 +935,7 @@
     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.
     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.
@@ -3688,10 +3689,14 @@
     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.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);
@@ -6158,6 +6163,7 @@
 
     ImFontAtlas* atlas = g.Font->ContainerAtlas;
     g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
+    g.DrawListSharedData.TexUvAALines = &atlas->TexUvAALines;
     g.DrawListSharedData.Font = g.Font;
     g.DrawListSharedData.FontSize = g.FontSize;
 }
diff --git a/imgui.h b/imgui.h
index adb2ab1..09d9230 100644
--- a/imgui.h
+++ b/imgui.h
@@ -1439,6 +1439,7 @@
     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        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.
@@ -1997,7 +1998,8 @@
     ImDrawListFlags_None                    = 0,
     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_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?
 };
 
 // Draw command list
@@ -2216,7 +2218,8 @@
 {
     ImFontAtlasFlags_None               = 0,
     ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0,   // Don't round the height to next power of two
-    ImFontAtlasFlags_NoMouseCursors     = 1 << 1    // Don't build software mouse cursors into the atlas (save a little texture memory)
+    ImFontAtlasFlags_NoMouseCursors     = 1 << 1,   // Don't build software mouse cursors into the atlas (save a little texture memory)
+    ImFontAtlasFlags_NoAALines          = 1 << 2    // Don't build anti-aliased line textures into the atlas
 };
 
 // Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding:
@@ -2320,6 +2323,9 @@
 
     // [Internal] Packing data
     int                         PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors
+    int                         AALineMaxWidth;     // Maximum line width to build anti-aliased textures for
+    ImVector<int>               AALineRectIds;      // Custom texture rectangle IDs for anti-aliased lines
+    ImVector<ImVec4>            TexUvAALines;       // UVs for anti-aliased line textures
 
 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     typedef ImFontAtlasCustomRect    CustomRect;         // OBSOLETED in 1.72+
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index b481c30..f06d852 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -297,6 +297,62 @@
     ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver);
     ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
 
+    // Test lines
+
+    if (ImGui::Begin("Lines"))
+    {
+        ImDrawList* draw_list = ImGui::GetWindowDrawList();
+
+        const int num_cols = 16;
+        const int num_rows = 3;
+        const float line_len = 64.0f;
+        const float line_spacing = 128.0f;
+
+        static float base_rot = 0.0f;
+        ImGui::SliderFloat("Base rotation", &base_rot, 0.0f, 360.0f);
+        static float line_width = 1.0f;
+        ImGui::SliderFloat("Line width", &line_width, 1.0f, 10.0f);
+
+        ImVec2 window_pos = ImGui::GetWindowPos();
+        ImVec2 cursor_pos = ImGui::GetCursorPos();
+        ImVec2 base_pos(window_pos.x + cursor_pos.x + (line_spacing * 0.5f), window_pos.y + cursor_pos.y);
+
+        for (int i = 0; i < num_rows; i++)
+        {
+            const char* name = "";
+            switch (i)
+            {
+            case 0: name = "No AA";  draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; break;
+            case 1: name = "AA no texturing"; draw_list->Flags |= ImDrawListFlags_AntiAliasedLines; draw_list->Flags &= ~ImDrawListFlags_TexturedAALines; break;
+            case 2: name = "AA with texturing"; draw_list->Flags |= ImDrawListFlags_AntiAliasedLines; draw_list->Flags |= ImDrawListFlags_TexturedAALines; break;
+            }
+
+            int initial_vtx_count = draw_list->VtxBuffer.Size;
+            int initial_idx_count = draw_list->IdxBuffer.Size;
+
+            for (int j = 0; j < num_cols; j++)
+            {
+                const float pi = 3.14159265359f;
+                float r = (base_rot * pi / 180.0f) + ((j * pi * 0.5f) / (num_cols - 1));
+
+                ImVec2 center = ImVec2(base_pos.x + (line_spacing * (j * 0.5f)), base_pos.y + (line_spacing * (i + 0.5f)));
+                ImVec2 start = ImVec2(center.x + (sinf(r) * line_len * 0.5f), center.y + (cosf(r) * line_len * 0.5f));
+                ImVec2 end = ImVec2(center.x - (sinf(r) * line_len * 0.5f), center.y - (cosf(r) * line_len * 0.5f));
+
+                draw_list->AddLine(start, end, IM_COL32(255, 255, 255, 255), line_width);
+            }
+
+            ImGui::SetCursorPosY(cursor_pos.y + (i * line_spacing));
+            ImGui::Text("%s - %d vertices, %d indices", name, draw_list->VtxBuffer.Size - initial_vtx_count, draw_list->IdxBuffer.Size - initial_idx_count);
+        }
+
+        ImGui::SetCursorPosY(cursor_pos.y + (num_rows * line_spacing));
+
+        //ImGui::Spacing(); ImGui::Spacing(); ImGui::Spacing();
+        //ImGui::Image(ImGui::GetFont()->ContainerAtlas->TexID, ImVec2((float)ImGui::GetFont()->ContainerAtlas->TexWidth, (float)ImGui::GetFont()->ContainerAtlas->TexHeight));
+    }
+    ImGui::End();
+
     // Main body of the Demo window starts here.
     if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
     {
@@ -3831,6 +3887,7 @@
         {
             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 fill", &style.AntiAliasedFill);
             ImGui::PushItemWidth(100);
             ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
diff --git a/imgui_draw.cpp b/imgui_draw.cpp
index 30b9b9f..7c845f9 100644
--- a/imgui_draw.cpp
+++ b/imgui_draw.cpp
@@ -667,6 +667,7 @@
 
     const ImVec2 opaque_uv = _Data->TexUvWhitePixel;
     const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw
+
     const bool thick_line = (thickness > 1.0f);
 
     if (Flags & ImDrawListFlags_AntiAliasedLines)
@@ -675,13 +676,24 @@
         const float AA_SIZE = 1.0f;
         const ImU32 col_trans = col & ~IM_COL32_A_MASK;
 
-        const int idx_count = thick_line ? count * 18 : count * 12;
-        const int vtx_count = thick_line ? points_count * 4 : points_count * 3;
+        const int integer_thickness = (int)thickness;
+
+        // Do we want to draw this line using a texture?
+        bool use_textures = (Flags & ImDrawListFlags_TexturedAALines) &&
+            (integer_thickness >= 1) &&
+            (integer_thickness <= _Data->Font->ContainerAtlas->AALineMaxWidth) &&
+            ImGui::GetIO().KeyShift; // FIXME-AALINES: Remove this debug code
+
+        // 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)));
+
+        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);
         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 ? 5 : 3) * sizeof(ImVec2)); //-V630
+        ImVec2* temp_normals = (ImVec2*)alloca(points_count * ((thick_line && !use_textures) ? 5 : 3) * sizeof(ImVec2)); //-V630
         ImVec2* temp_points = temp_normals + points_count;
 
         // Calculate normals (tangents) for each line segment
@@ -697,14 +709,19 @@
         if (!closed)
             temp_normals[points_count - 1] = temp_normals[points_count - 2];
 
-        if (!thick_line)
+        // 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))
         {
+            // The width of the geometry we need to draw
+            const float half_draw_size = (!thick_line) ? AA_SIZE : (AA_SIZE + (thickness * 0.5f));
+
+            // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
             if (!closed)
             {
-                temp_points[0] = points[0] + temp_normals[0] * AA_SIZE;
-                temp_points[1] = points[0] - temp_normals[0] * AA_SIZE;
-                temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * AA_SIZE;
-                temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * AA_SIZE;
+                temp_points[0] = points[0] + temp_normals[0] * half_draw_size;
+                temp_points[1] = points[0] - temp_normals[0] * half_draw_size;
+                temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size;
+                temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size;
             }
 
             // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges
@@ -713,15 +730,15 @@
             unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
             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;
-                const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : idx1 + 3;
+                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
 
                 // Average normals
                 float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
                 float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
                 IM_FIXNORMAL2F(dm_x, dm_y);
-                dm_x *= AA_SIZE;
-                dm_y *= AA_SIZE;
+                dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area
+                dm_y *= half_draw_size;
 
                 // Add temporary vertexes for the outer edges
                 ImVec2* out_vtx = &temp_points[i2 * 2];
@@ -730,28 +747,54 @@
                 out_vtx[1].x = points[i2].x - dm_x;
                 out_vtx[1].y = points[i2].y - dm_y;
 
-                // Add indexes for four triangles
-                _IdxWritePtr[0] = (ImDrawIdx)(idx2+0); _IdxWritePtr[1] = (ImDrawIdx)(idx1+0); _IdxWritePtr[2] = (ImDrawIdx)(idx1+2);
-                _IdxWritePtr[3] = (ImDrawIdx)(idx1+2); _IdxWritePtr[4] = (ImDrawIdx)(idx2+2); _IdxWritePtr[5] = (ImDrawIdx)(idx2+0);
-                _IdxWritePtr[6] = (ImDrawIdx)(idx2+1); _IdxWritePtr[7] = (ImDrawIdx)(idx1+1); _IdxWritePtr[8] = (ImDrawIdx)(idx1+0);
-                _IdxWritePtr[9] = (ImDrawIdx)(idx1+0); _IdxWritePtr[10]= (ImDrawIdx)(idx2+0); _IdxWritePtr[11]= (ImDrawIdx)(idx2+1);
-                _IdxWritePtr += 12;
+                if (use_textures)
+                {
+                    // Add indices for two triangles
+                    _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri
+                    _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri
+                    _IdxWritePtr += 6;
+                }
+                else
+                {
+                    // Add indexes for four triangles
+                    _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1
+                    _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2
+                    _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1
+                    _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2
+                    _IdxWritePtr += 12;
+                }
 
                 idx1 = idx2;
             }
 
             // Add vertexes for each point on the line
-            for (int i = 0; i < points_count; i++)
+            if (use_textures)
             {
-                _VtxWritePtr[0].pos = points[i];          _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;
-                _VtxWritePtr[1].pos = temp_points[i*2+0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans;
-                _VtxWritePtr[2].pos = temp_points[i*2+1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans;
-                _VtxWritePtr += 3;
+                // If we're using textures we only need to emit the left/right edge vertices
+                const ImVec4 tex_uvs = (*_Data->TexUvAALines)[integer_thickness - 1];
+
+                for (int i = 0; i < points_count; i++)
+                {
+                    _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = ImVec2(tex_uvs.x, tex_uvs.y); _VtxWritePtr[0].col = col; // Left-side outer edge
+                    _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = ImVec2(tex_uvs.z, tex_uvs.y); _VtxWritePtr[1].col = col; // Right-side outer edge
+                    _VtxWritePtr += 2;
+                }
+            }
+            else
+            {
+                // If we're not using a texture, we need the centre vertex as well
+                for (int i = 0; i < points_count; i++)
+                {
+                    _VtxWritePtr[0].pos = points[i];              _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col; // Centre of line
+                    _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge
+                    _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge
+                    _VtxWritePtr += 3;
+                }
             }
         }
         else
         {
-            // Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point
+            // For untextured lines that are greater than a pixel in width, we need to draw the solid line core and thus require four vertices per point
             const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
 
             // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
@@ -1664,6 +1707,8 @@
     TexUvScale = ImVec2(0.0f, 0.0f);
     TexUvWhitePixel = ImVec2(0.0f, 0.0f);
     PackIdMouseCursors = -1;
+
+    AALineMaxWidth = 8;
 }
 
 ImFontAtlas::~ImFontAtlas()
@@ -2010,6 +2055,7 @@
     IM_ASSERT(atlas->ConfigData.Size > 0);
 
     ImFontAtlasBuildInit(atlas);
+    ImFontAtlasBuildRegisterAALineCustomRects(atlas);
 
     // Clear atlas
     atlas->TexID = (ImTextureID)NULL;
@@ -2331,7 +2377,6 @@
     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)
 {
@@ -2346,12 +2391,73 @@
 }
 
 // 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)
+{
+    if (atlas->AALineRectIds.size() > 0)
+        return;
+
+    if ((atlas->Flags & ImFontAtlasFlags_NoAALines))
+        return;
+
+    const int max = atlas->AALineMaxWidth;
+
+    for (int n = 0; n < max; n++)
+    {
+        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)
+{
+    IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
+    IM_ASSERT(atlas->TexUvAALines.size() == 0);
+
+    if (atlas->Flags & ImFontAtlasFlags_NoAALines)
+        return;
+
+    const int w = atlas->TexWidth;
+    const unsigned int max = atlas->AALineMaxWidth;
+
+    for (unsigned int n = 0; n < max; n++)
+    {
+        IM_ASSERT(atlas->AALineRectIds.size() > (int)n);
+        ImFontAtlas::CustomRect& 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
+            *(write_ptr++) = 0;
+            for (unsigned short x = 0; x < (r.Width - 2U); x++)
+            {
+                *(write_ptr++) = 0xFF;
+            }
+            *(write_ptr++) = 0;
+        }
+
+        ImVec2 uv0, uv1;
+        atlas->CalcCustomRectUV(&r, &uv0, &uv1);
+        float halfV = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the texture as we want a horizontal slice (with some padding either side to avoid sampling artifacts)
+        atlas->TexUvAALines.push_back(ImVec4(uv0.x, halfV, uv1.x, halfV));
+    }
+}
+
 void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
 {
     // Render into our custom data blocks
     IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
     ImFontAtlasBuildRenderDefaultTexData(atlas);
 
+    // Render anti-aliased line textures
+    ImFontAtlasBuildAALinesTexData(atlas);
+
     // Register custom rectangle glyphs
     for (int i = 0; i < atlas->CustomRects.Size; i++)
     {
diff --git a/imgui_internal.h b/imgui_internal.h
index b57b01b..2035f32 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -545,6 +545,8 @@
     ImVec2          ArcFastVtx[12 * IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER];  // FIXME: Bake rounded corners fill/borders in atlas
     ImU8            CircleSegmentCounts[64];    // Precomputed segment count for given radius (array index + 1) before we calculate it dynamically (to avoid calculation overhead)
 
+    ImVector<ImVec4>* TexUvAALines;             // UV of anti-aliased lines in the atlas
+
     ImDrawListSharedData();
     void SetCircleSegmentMaxError(float max_error);
 };
@@ -2018,8 +2020,10 @@
 // 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);