WIP: Rendering optimization: store rounded corners in texture to use 1 quad per corner (#1962) @franciscod
diff --git a/examples/example_sdl_opengl3/Makefile b/examples/example_sdl_opengl3/Makefile
index 76601a1..9ac59b0 100644
--- a/examples/example_sdl_opengl3/Makefile
+++ b/examples/example_sdl_opengl3/Makefile
@@ -22,7 +22,7 @@
 UNAME_S := $(shell uname -s)
 
 CXXFLAGS = -I../ -I../../
-CXXFLAGS += -g -Wall -Wformat
+CXXFLAGS += -g -Wall -Wformat -std=c++03
 LIBS =
 
 ##---------------------------------------------------------------------
diff --git a/examples/example_sdl_opengl3/main.cpp b/examples/example_sdl_opengl3/main.cpp
index 38b9ebd..6aaf12c 100644
--- a/examples/example_sdl_opengl3/main.cpp
+++ b/examples/example_sdl_opengl3/main.cpp
@@ -22,6 +22,20 @@
 #include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
 #endif
 
+void GetVtxIdxDelta(ImDrawList* dl, int* vtx, int *idx)
+{
+    static int vtx_n, idx_n;
+    static int vtx_o, idx_o;
+    vtx_n = dl->VtxBuffer.Size;
+    idx_n = dl->IdxBuffer.Size;
+
+    *vtx = vtx_n - vtx_o;
+    *idx = idx_n - idx_o;
+
+    vtx_o = vtx_n;
+    idx_o = idx_n;
+}
+
 int main(int, char**)
 {
     // Setup SDL
@@ -83,6 +97,8 @@
 
     // Setup Dear ImGui style
     ImGui::StyleColorsDark();
+
+    ImGuiStyle& style = ImGui::GetStyle();
     //ImGui::StyleColorsClassic();
 
     // Setup Platform/Renderer bindings
@@ -96,6 +112,8 @@
     // - 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 'misc/fonts/README.txt' 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->RoundCornersMaxSize = 60;
+    style.WindowRounding = io.Fonts->RoundCornersMaxSize;
     //io.Fonts->AddFontDefault();
     //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf", 16.0f);
     //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf", 15.0f);
@@ -143,6 +161,95 @@
 
             ImGui::Begin("Hello, world!");                          // Create a window called "Hello, world!" and append into it.
 
+            // Rounded corners demo start
+
+            ImGui::TextUnformatted("Press alt to toggle quads (hold to see them).");
+            ImGui::TextUnformatted(io.KeyAlt ? "ALT ON  -- Rasterized quad circle! w00t! OPTIMIZATION!"
+                                             : "ALT OFF -- Regular, boring circle with PathArcToFast.");
+
+            static int r = io.Fonts->RoundCornersMaxSize / 2;
+            ImGui::SliderInt("radius", &r, 0, io.Fonts->RoundCornersMaxSize);
+
+            ImGui::BeginGroup();
+
+            static int s = 20;
+            ImGui::PushItemWidth(120);
+            ImGui::SliderInt("segments", &s, 3, 100);
+            ImGui::PopItemWidth();
+
+            int vtx = 0, idx = 0;
+            ImDrawList* dl = ImGui::GetWindowDrawList();
+
+            {
+                ImGui::Button("", ImVec2(200, 200));
+                GetVtxIdxDelta(dl, &vtx, &idx);
+                ImVec2 min = ImGui::GetItemRectMin();
+                ImVec2 size = ImGui::GetItemRectSize();
+                dl->AddCircleFilled(ImVec2(min.x + size.x / 2, min.y + size.y / 2), r, 0xFFFF00FF, s);
+                GetVtxIdxDelta(dl, &vtx, &idx);
+                ImGui::Text("AddCircleFilled\n %d vtx, %d idx", vtx, idx);
+            }
+            {
+              ImGui::Button("", ImVec2(200, 200));
+              GetVtxIdxDelta(dl, &vtx, &idx);
+              ImVec2 min = ImGui::GetItemRectMin();
+              ImVec2 size = ImGui::GetItemRectSize();
+              dl->AddCircle(ImVec2(min.x + size.x / 2, min.y + size.y / 2), r, 0xFFFF00FF, s);
+              GetVtxIdxDelta(dl, &vtx, &idx);
+              ImGui::Text("AddCircle\n %d vtx, %d idx", vtx, idx);
+            }
+
+            ImGui::EndGroup();
+
+            ImGui::SameLine();
+
+            ImGui::BeginGroup();
+
+            static bool tl = true, tr = true, bl = true, br = true;
+            int flags = 0;
+            ImGui::Checkbox("TL", &tl);
+            ImGui::SameLine(0, 12);
+            ImGui::Checkbox("TR", &tr);
+            ImGui::SameLine(0, 12);
+            ImGui::Checkbox("BL", &bl);
+            ImGui::SameLine(0, 12);
+            ImGui::Checkbox("BR", &br);
+
+            flags |= tl ? ImDrawCornerFlags_TopLeft : 0;
+            flags |= tr ? ImDrawCornerFlags_TopRight : 0;
+            flags |= bl ? ImDrawCornerFlags_BotLeft : 0;
+            flags |= br ? ImDrawCornerFlags_BotRight : 0;
+
+            {
+              ImGui::Button("", ImVec2(200, 200));
+              ImVec2 r_min = ImGui::GetItemRectMin();
+              ImVec2 r_max = ImGui::GetItemRectMax();
+
+              GetVtxIdxDelta(dl, &vtx, &idx);
+              dl->AddRectFilled(r_min, r_max, 0xFFFF00FF, r, flags);
+              GetVtxIdxDelta(dl, &vtx, &idx);
+              ImGui::Text("AddRectFilled\n %d vtx, %d idx", vtx, idx);
+            }
+            {
+              ImGui::Button("", ImVec2(200, 200));
+              ImVec2 r_min = ImGui::GetItemRectMin();
+              ImVec2 r_max = ImGui::GetItemRectMax();
+
+              GetVtxIdxDelta(dl, &vtx, &idx);
+              dl->AddRect(r_min, r_max, 0xFFFF00FF, r, flags);
+              GetVtxIdxDelta(dl, &vtx, &idx);
+              ImGui::Text("AddRect\n %d vtx, %d idx", vtx, idx);
+            }
+
+            ImGui::EndGroup();
+
+            ImGui::Separator();
+
+            ImFontAtlas* atlas = ImGui::GetIO().Fonts;
+            ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0,0), ImVec2(1,1), ImColor(255,255,255,255), ImColor(255,255,255,128));
+
+            // Rounded corners demo end
+
             ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
             ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
             ImGui::Checkbox("Another Window", &show_another_window);
diff --git a/examples/imgui_examples.sln b/examples/imgui_examples.sln
index 49b2ff8..d4c05eb 100644
--- a/examples/imgui_examples.sln
+++ b/examples/imgui_examples.sln
@@ -21,14 +21,6 @@
 		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|Win32.ActiveCfg = Debug|Win32
-		{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|Win32.Build.0 = Debug|Win32
-		{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|x64.ActiveCfg = Debug|x64
-		{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|x64.Build.0 = Debug|x64
-		{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|Win32.ActiveCfg = Release|Win32
-		{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|Win32.Build.0 = Release|Win32
-		{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|x64.ActiveCfg = Release|x64
-		{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|x64.Build.0 = Release|x64
 		{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Debug|Win32.ActiveCfg = Debug|Win32
 		{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Debug|Win32.Build.0 = Debug|Win32
 		{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Debug|x64.ActiveCfg = Debug|x64
@@ -37,22 +29,6 @@
 		{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Release|Win32.Build.0 = Release|Win32
 		{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Release|x64.ActiveCfg = Release|x64
 		{4165A294-21F2-44CA-9B38-E3F935ABADF5}.Release|x64.Build.0 = Release|x64
-		{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|Win32.ActiveCfg = Debug|Win32
-		{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|Win32.Build.0 = Debug|Win32
-		{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|x64.ActiveCfg = Debug|x64
-		{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|x64.Build.0 = Debug|x64
-		{9F316E83-5AE5-4939-A723-305A94F48005}.Release|Win32.ActiveCfg = Release|Win32
-		{9F316E83-5AE5-4939-A723-305A94F48005}.Release|Win32.Build.0 = Release|Win32
-		{9F316E83-5AE5-4939-A723-305A94F48005}.Release|x64.ActiveCfg = Release|x64
-		{9F316E83-5AE5-4939-A723-305A94F48005}.Release|x64.Build.0 = Release|x64
-		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Debug|Win32.ActiveCfg = Debug|Win32
-		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Debug|Win32.Build.0 = Debug|Win32
-		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Debug|x64.ActiveCfg = Debug|x64
-		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Debug|x64.Build.0 = Debug|x64
-		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Release|Win32.ActiveCfg = Release|Win32
-		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Release|Win32.Build.0 = Release|Win32
-		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Release|x64.ActiveCfg = Release|x64
-		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Release|x64.Build.0 = Release|x64
 		{345A953E-A004-4648-B442-DC5F9F11068C}.Debug|Win32.ActiveCfg = Debug|Win32
 		{345A953E-A004-4648-B442-DC5F9F11068C}.Debug|Win32.Build.0 = Debug|Win32
 		{345A953E-A004-4648-B442-DC5F9F11068C}.Debug|x64.ActiveCfg = Debug|x64
@@ -61,6 +37,30 @@
 		{345A953E-A004-4648-B442-DC5F9F11068C}.Release|Win32.Build.0 = Release|Win32
 		{345A953E-A004-4648-B442-DC5F9F11068C}.Release|x64.ActiveCfg = Release|x64
 		{345A953E-A004-4648-B442-DC5F9F11068C}.Release|x64.Build.0 = Release|x64
+		{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|Win32.ActiveCfg = Debug|Win32
+		{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|Win32.Build.0 = Debug|Win32
+		{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|x64.ActiveCfg = Debug|x64
+		{9F316E83-5AE5-4939-A723-305A94F48005}.Debug|x64.Build.0 = Debug|x64
+		{9F316E83-5AE5-4939-A723-305A94F48005}.Release|Win32.ActiveCfg = Release|Win32
+		{9F316E83-5AE5-4939-A723-305A94F48005}.Release|Win32.Build.0 = Release|Win32
+		{9F316E83-5AE5-4939-A723-305A94F48005}.Release|x64.ActiveCfg = Release|x64
+		{9F316E83-5AE5-4939-A723-305A94F48005}.Release|x64.Build.0 = Release|x64
+		{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|Win32.ActiveCfg = Debug|Win32
+		{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|Win32.Build.0 = Debug|Win32
+		{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|x64.ActiveCfg = Debug|x64
+		{9CDA7840-B7A5-496D-A527-E95571496D18}.Debug|x64.Build.0 = Debug|x64
+		{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|Win32.ActiveCfg = Release|Win32
+		{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|Win32.Build.0 = Release|Win32
+		{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|x64.ActiveCfg = Release|x64
+		{9CDA7840-B7A5-496D-A527-E95571496D18}.Release|x64.Build.0 = Release|x64
+		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Debug|Win32.ActiveCfg = Debug|Win32
+		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Debug|Win32.Build.0 = Debug|Win32
+		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Debug|x64.ActiveCfg = Debug|x64
+		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Debug|x64.Build.0 = Debug|x64
+		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Release|Win32.ActiveCfg = Release|Win32
+		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Release|Win32.Build.0 = Release|Win32
+		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Release|x64.ActiveCfg = Release|x64
+		{4A1FB5EA-22F5-42A8-AB92-1D2DF5D47FB9}.Release|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/imgui.cpp b/imgui.cpp
index 72ea25e..425c63f 100644
--- a/imgui.cpp
+++ b/imgui.cpp
@@ -4876,16 +4876,62 @@
     ImVec2  CornerPosN;
     ImVec2  InnerDir;
     int     AngleMin12, AngleMax12;
+    ImDrawCornerFlags CornerFlags;
 };
 
 static const ImGuiResizeGripDef resize_grip_def[4] =
 {
-    { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right
-    { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left
-    { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left
-    { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right
+    { ImVec2(1,1), ImVec2(-1,-1), 0, 3, ImDrawCornerFlags_BotRight  }, // Lower right
+    { ImVec2(0,1), ImVec2(+1,-1), 3, 6, ImDrawCornerFlags_BotLeft   }, // Lower left
+    { ImVec2(0,0), ImVec2(+1,+1), 6, 9, ImDrawCornerFlags_TopLeft   }, // Upper left
+    { ImVec2(1,0), ImVec2(-1,+1), 9,12, ImDrawCornerFlags_TopRight  }, // Upper right
 };
 
+static void AddResizeGrip(ImDrawList* dl, const ImVec2& corner, unsigned int rad, int rounding_corners_flags, ImU32 col)
+{
+    ImTextureID tex = dl->_Data->Font->ContainerAtlas->TexID;
+    IM_ASSERT(tex == dl->_TextureIdStack.back());  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
+
+    switch (rounding_corners_flags)
+    {
+    case ImDrawCornerFlags_TopLeft:
+    case ImDrawCornerFlags_TopRight:
+    case ImDrawCornerFlags_BotRight:
+    case ImDrawCornerFlags_BotLeft:
+        break;
+    default:
+    {
+        IM_ASSERT("Invalid ImDrawCornerFlags for corner quad. {Top,Bot}{Left,Right} pick exactly one of each!");
+        return;
+    }
+    }
+
+    const ImVec4& uvs = (*dl->_Data->TexUvRoundCornerFilled)[rad - 1];
+
+    // NOTE: test performance using locals instead of array
+    const ImVec2 uv[] =
+    {
+        ImVec2(ImLerp(uvs.x, uvs.z, 0.5f), ImLerp(uvs.y, uvs.w, 0.5f)),
+        ImVec2(uvs.x, uvs.w),
+        ImVec2(uvs.z, uvs.w),
+    };
+
+    ImVec2 in_x = corner, in_y = corner;
+    if (rounding_corners_flags & ImDrawCornerFlags_Top)
+        in_y.y += rad;
+    else if (rounding_corners_flags & ImDrawCornerFlags_Bot)
+        in_y.y -= rad;
+    if (rounding_corners_flags & ImDrawCornerFlags_Left)
+        in_x.x += rad;
+    else if (rounding_corners_flags & ImDrawCornerFlags_Right)
+        in_x.x -= rad;
+
+    const ImVec2 mid = ImVec2(ImLerp(in_x.x, in_y.x, 0.5f), ImLerp(in_x.y, in_y.y, 0.5f));
+
+    dl->PrimReserve(6, 4);
+    dl->PrimQuadUV(mid, in_y, corner, in_x, uv[0], uv[1], uv[2], uv[1], col);
+}
+
 static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
 {
     ImRect rect = window->Rect();
@@ -5129,10 +5175,20 @@
             {
                 const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
                 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
-                window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));
-                window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));
-                window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
-                window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
+                if (g.IO.KeyAlt)
+                {
+                    ImVec2 grip_corner = corner;
+                    grip_corner.x += grip.InnerDir.x * window_border_size;
+                    grip_corner.y += grip.InnerDir.y * window_border_size;
+                    AddResizeGrip(window->DrawList, grip_corner, (unsigned int)window_rounding, grip.CornerFlags, resize_grip_col[resize_grip_n]);
+                }
+                else
+                {
+                    //window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));
+                    window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));
+                    window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
+                    window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
+                }
             }
         }
 
@@ -6085,6 +6141,8 @@
 
     ImFontAtlas* atlas = g.Font->ContainerAtlas;
     g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
+    g.DrawListSharedData.TexUvRoundCornerFilled = &atlas->TexUvRoundCornerFilled;
+    g.DrawListSharedData.TexUvRoundCornerStroked = &atlas->TexUvRoundCornerStroked;
     g.DrawListSharedData.Font = g.Font;
     g.DrawListSharedData.FontSize = g.FontSize;
 }
diff --git a/imgui.h b/imgui.h
index d5de110..6d79c77 100644
--- a/imgui.h
+++ b/imgui.h
@@ -1961,6 +1961,7 @@
     inline    void  PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col)     { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); }
     IMGUI_API void  UpdateClipRect();
     IMGUI_API void  UpdateTextureID();
+
 };
 
 // All draw data to render a Dear ImGui frame
@@ -2043,7 +2044,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
+    ImFontAtlasFlags_NoMouseCursors     = 1 << 1,   // Don't build software mouse cursors into the atlas
+    ImFontAtlasFlags_NoRoundCorners     = 1 << 2    // Don't use software rendered quads for round corners
 };
 
 // Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding:
@@ -2156,6 +2158,12 @@
     ImVector<ImFontConfig>      ConfigData;         // Internal data
     int                         CustomRectIds[1];   // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList
 
+    // FIXME-ROUND-SHAPES: WIP
+    int                     RoundCornersMaxSize;    // Max pixel size of round corner textures to generate
+    ImVector<int>           RoundCornersRectIds;    // Ids of custom rects for round corners indexed by size [0] is 1px, [n] is (n+1)px (index up to RoundCornersMaxSize - 1).
+    ImVector<ImVec4>        TexUvRoundCornerFilled; // Texture coordinates to filled round corner quads
+    ImVector<ImVec4>        TexUvRoundCornerStroked;// Texture coordinates to stroked round corner quads
+
 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
 #endif
diff --git a/imgui_draw.cpp b/imgui_draw.cpp
index 8d0c31d..021db91 100644
--- a/imgui_draw.cpp
+++ b/imgui_draw.cpp
@@ -978,15 +978,193 @@
     PathStroke(col, false, thickness);
 }
 
+inline void AddRoundCornerRect(ImDrawList* draw_list, const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, bool fill)
+{
+    const ImDrawListSharedData* data = draw_list->_Data;
+    const int rad = (int)rounding;
+    IM_ASSERT(rad <= data->Font->ContainerAtlas->RoundCornersMaxSize);
+
+    ImTextureID tex_id = data->Font->ContainerAtlas->TexID;
+    IM_ASSERT(tex_id == draw_list->_TextureIdStack.back());  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
+
+    const ImVec4& uvs = (*(fill ? data->TexUvRoundCornerFilled : data->TexUvRoundCornerStroked))[rad - 1];
+    const ImVec2 corner_uv[3] =
+    {
+        ImVec2(uvs.x, uvs.y),
+        fill ? ImVec2(uvs.x, uvs.w) : ImVec2(uvs.z, uvs.y),
+        ImVec2(uvs.z, uvs.w),
+    };
+
+    const bool ba = (rounding_corners_flags & ImDrawCornerFlags_TopLeft) != 0;
+    const bool bb = (rounding_corners_flags & ImDrawCornerFlags_TopRight) != 0;
+    const bool bc = (rounding_corners_flags & ImDrawCornerFlags_BotRight) != 0;
+    const bool bd = (rounding_corners_flags & ImDrawCornerFlags_BotLeft) != 0;
+
+    // TODO: fix "D" shaped stroked rects
+
+    const int rad_l = (ba || bd) ? rad : 0;
+    const int rad_t = (ba || bb) ? rad : 0;
+    const int rad_r = (bc || bb) ? rad : 0;
+    const int rad_b = (bc || bd) ? rad : 0;
+
+    const ImVec2 ca(a.x, a.y), cb(b.x, a.y);
+    const ImVec2 ma1(ca.x + rad_l, ca.y), mb1(cb.x - rad_r, cb.y);
+    const ImVec2 ma2(ca.x, ca.y + rad_t), mb2(cb.x, cb.y + rad_t);
+    const ImVec2 ia(ma1.x, ma2.y), ib(mb1.x, mb2.y);
+
+    const ImVec2 cc(b.x, b.y), cd(a.x, b.y);
+    const ImVec2 md3(cd.x, cd.y - rad_b), mc3(cc.x, cc.y - rad_b);
+    const ImVec2 md4(cd.x + rad_l, cd.y), mc4(cc.x - rad_r, cc.y);
+    const ImVec2 id(md4.x, md3.y), ic(mc4.x, mc3.y);
+
+    const int vtcs = 16;
+    const int idcs = 54;
+    draw_list->PrimReserve(idcs, vtcs);
+
+    const ImDrawIdx idx = (ImDrawIdx)draw_list->_VtxCurrentIdx;
+
+    #define VTX_WRITE(d, p, i)                          \
+        draw_list->_VtxWritePtr[d].pos = (p);           \
+        draw_list->_VtxWritePtr[d].uv = corner_uv[(i)]; \
+        draw_list->_VtxWritePtr[d].col = col
+
+    const int vca = 0, vcb = 1, vcc = 2, vcd = 3;
+    VTX_WRITE(vca, ca, ba ? 2 : 1);
+    VTX_WRITE(vcb, cb, bb ? 2 : 1);
+    VTX_WRITE(vcc, cc, bc ? 2 : 1);
+    VTX_WRITE(vcd, cd, bd ? 2 : 1);
+
+    int dv = 4;
+
+    int vya = vca, vxa = vca, via = vca;
+    int vyb = vcb, vxb = vcb, vib = vcb;
+    int vyc = vcc, vxc = vcc, vic = vcc;
+    int vyd = vcd, vxd = vcd, vid = vcd;
+
+    // FIXME-ROUND_SHAPES: TODO: find a way of saving vertices/triangles here?
+    // currently it's the same cost regardless of how many corners are rounded
+
+    if (ba || 1)
+    {
+        vya = dv;
+        vxa = dv + 1;
+        via = dv + 2;
+        VTX_WRITE(vya, ma1, 1);
+        VTX_WRITE(vxa, ma2, 1);
+        VTX_WRITE(via, ia, 0);
+        dv += 3;
+    }
+
+    if (bb || 1) 
+    {
+        vyb = dv;
+        vxb = dv + 1;
+        vib = dv + 2;
+        VTX_WRITE(vyb, mb1, 1);
+        VTX_WRITE(vxb, mb2, 1);
+        VTX_WRITE(vib, ib, 0);
+        dv += 3;
+    }
+
+    if (bc || 1) 
+    {
+        vyc = dv;
+        vxc = dv + 1;
+        vic = dv + 2;
+        VTX_WRITE(vyc, mc4, 1);
+        VTX_WRITE(vxc, mc3, 1);
+        VTX_WRITE(vic, ic, 0);
+        dv += 3;
+    }
+
+    if (bd || 1)
+    {
+        vyd = dv;
+        vxd = dv + 1;
+        vid = dv + 2;
+        VTX_WRITE(vyd, md4, 1);
+        VTX_WRITE(vxd, md3, 1);
+        VTX_WRITE(vid, id, 0);
+        dv += 3;
+    }
+
+    int di = 0;
+    #define IDX_WRITE_TRI(idx0, idx1, idx2)                      \
+        draw_list->_IdxWritePtr[di]   = (ImDrawIdx)(idx+(idx0)); \
+        draw_list->_IdxWritePtr[di+1] = (ImDrawIdx)(idx+(idx1)); \
+        draw_list->_IdxWritePtr[di+2] = (ImDrawIdx)(idx+(idx2)); \
+        di += 3
+
+    // Inner
+    if (fill)
+    {
+      IDX_WRITE_TRI(via, vic, vib);
+      IDX_WRITE_TRI(via, vic, vid);
+    }
+
+    if (ba || 1)
+    {
+        IDX_WRITE_TRI(vca, vya, via);
+        IDX_WRITE_TRI(vca, vxa, via);
+
+        IDX_WRITE_TRI(vib, vya, via);
+        IDX_WRITE_TRI(vid, vxa, via);
+    }
+
+    if (bb || 1)
+    {
+        IDX_WRITE_TRI(vcb, vyb, vib);
+        IDX_WRITE_TRI(vcb, vxb, vib);
+
+        IDX_WRITE_TRI(vya, vyb, vib);
+        IDX_WRITE_TRI(vic, vxb, vib);
+    }
+
+    if (bc || 1)
+    {
+        IDX_WRITE_TRI(vcc, vyc, vic);
+        IDX_WRITE_TRI(vcc, vxc, vic);
+
+        IDX_WRITE_TRI(vxb, vxc, vic);
+        IDX_WRITE_TRI(vyd, vyc, vic);
+    }
+
+    if (bd || 1)
+    {
+        IDX_WRITE_TRI(vcd, vyd, vid);
+        IDX_WRITE_TRI(vcd, vxd, vid);
+
+        IDX_WRITE_TRI(vic, vyd, vid);
+        IDX_WRITE_TRI(vxa, vxd, vid);
+    }
+
+    draw_list->_VtxWritePtr += dv;
+    draw_list->_VtxCurrentIdx += dv;
+    draw_list->_IdxWritePtr += di;
+
+    draw_list->PrimReserve(di - idcs, dv - vtcs);   // FIXME-OPT
+
+    #undef IDX_WRITE_TRI
+    #undef VTX_WRITE
+}
+
 // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly.
 void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness)
 {
     if ((col & IM_COL32_A_MASK) == 0)
         return;
+
+    rounding = ImMin(rounding, ImFabs(b.x - a.x) * (((rounding_corners_flags & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners_flags & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f) - 1.0f);
+    rounding = ImMin(rounding, ImFabs(b.y - a.y) * (((rounding_corners_flags & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners_flags & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f) - 1.0f);
+
+    // FIXME-ROUND-SHAPES: NOTE HACK TODO figure out why it's broken on small rounding
+    if (ImGui::GetIO().KeyShift && rounding > 3)
+        return AddRoundCornerRect(this, a, b, col, rounding, rounding_corners_flags, /* fill */ false);
+
     if (Flags & ImDrawListFlags_AntiAliasedLines)
-        PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.50f,0.50f), rounding, rounding_corners_flags);
+        PathRect(a + ImVec2(0.5f, 0.5f), b - ImVec2(0.50f, 0.50f), rounding, rounding_corners_flags);
     else
-        PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.49f,0.49f), rounding, rounding_corners_flags); // Better looking lower-right corner and rounded non-AA shapes.
+        PathRect(a + ImVec2(0.5f, 0.5f), b - ImVec2(0.49f, 0.49f), rounding, rounding_corners_flags); // Better looking lower-right corner and rounded non-AA shapes.
     PathStroke(col, true, thickness);
 }
 
@@ -994,10 +1172,23 @@
 {
     if ((col & IM_COL32_A_MASK) == 0)
         return;
-    if (rounding > 0.0f)
+
+    rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((rounding_corners_flags & ImDrawCornerFlags_Top)  == ImDrawCornerFlags_Top)  || ((rounding_corners_flags & ImDrawCornerFlags_Bot)   == ImDrawCornerFlags_Bot)   ? 0.5f : 1.0f ) - 1.0f);
+    rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((rounding_corners_flags & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners_flags & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f);
+
+    if (rounding > 0.0f && rounding_corners_flags != 0)
     {
-        PathRect(a, b, rounding, rounding_corners_flags);
-        PathFillConvex(col);
+        // // FIXME-ROUND-SHAPES: NOTE HACK TODO figure out why it's broken on small rounding
+        if (ImGui::GetIO().KeyShift && rounding > 3)
+        {
+            AddRoundCornerRect(this, a, b, col, rounding, rounding_corners_flags, /* fill */ true);
+            return;
+        }
+        else
+        {
+            PathRect(a, b, rounding, rounding_corners_flags);
+            PathFillConvex(col);
+        }
     }
     else
     {
@@ -1067,11 +1258,85 @@
     PathFillConvex(col);
 }
 
+inline void AddRoundCornerCircle(ImDrawList* draw_list, const ImVec2& centre, float radius, ImU32 col, bool fill)
+{
+    const ImDrawListSharedData* data = draw_list->_Data;
+    ImTextureID tex_id = data->Font->ContainerAtlas->TexID;
+    IM_ASSERT(tex_id == draw_list->_TextureIdStack.back());  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
+
+    const int rad = (int)radius;
+    IM_ASSERT(rad <= data->Font->ContainerAtlas->RoundCornersMaxSize);
+
+    const ImVec4& uvs = (*(fill ? data->TexUvRoundCornerFilled : data->TexUvRoundCornerStroked))[rad - 1];
+    const ImVec2 corner_uv[3] = 
+    {
+        ImVec2(uvs.x, uvs.y),
+        fill ? ImVec2(uvs.x, uvs.w) : ImVec2(uvs.z, uvs.y),
+        ImVec2(uvs.z, uvs.w),
+    };
+
+    const ImVec2& c = centre;
+    ImVec2 tl = ImVec2(c.x - rad, c.y - rad);
+    ImVec2 br = ImVec2(c.x + rad, c.y + rad);
+
+    // NOTE: test performance using locals instead of array
+    const ImVec2 circle_vt[9] = 
+    {
+        c,
+        tl,
+        ImVec2(c.x, tl.y),
+        ImVec2(br.x, tl.y),
+        ImVec2(br.x, c.y),
+        br,
+        ImVec2(c.x, br.y),
+        ImVec2(tl.x, br.y),
+        ImVec2(tl.x, c.y),
+    };
+
+    #define IDX_WRITE_TRI(d, idx0, idx1, idx2)                  \
+        draw_list->_IdxWritePtr[d+0] = (ImDrawIdx)(idx+idx0);   \
+        draw_list->_IdxWritePtr[d+1] = (ImDrawIdx)(idx+idx1);   \
+        draw_list->_IdxWritePtr[d+2] = (ImDrawIdx)(idx+idx2)
+
+    #define VTX_WRITE(d, i)                                     \
+        draw_list->_VtxWritePtr[d].pos = circle_vt[d];          \
+        draw_list->_VtxWritePtr[d].uv = corner_uv[i];           \
+        draw_list->_VtxWritePtr[d].col = col
+
+    draw_list->PrimReserve(24, 9);
+    ImDrawIdx idx = (ImDrawIdx)draw_list->_VtxCurrentIdx;
+    IDX_WRITE_TRI( 0, 0, 1, 2);
+    IDX_WRITE_TRI( 3, 0, 3, 2);
+    IDX_WRITE_TRI( 6, 0, 3, 4);
+    IDX_WRITE_TRI( 9, 0, 5, 4);
+    IDX_WRITE_TRI(12, 0, 5, 6);
+    IDX_WRITE_TRI(15, 0, 7, 6);
+    IDX_WRITE_TRI(18, 0, 7, 8);
+    IDX_WRITE_TRI(21, 0, 1, 8);
+
+    VTX_WRITE(1, 2); VTX_WRITE(2, 1); VTX_WRITE(3, 2);
+    VTX_WRITE(8, 1); VTX_WRITE(0, 0); VTX_WRITE(4, 1);
+    VTX_WRITE(7, 2); VTX_WRITE(6, 1); VTX_WRITE(5, 2);
+
+    draw_list->_VtxWritePtr += 9;
+    draw_list->_VtxCurrentIdx += 9;
+    draw_list->_IdxWritePtr += 24;
+
+#undef IDX_WRITE_TRI
+#undef VTX_WRITE
+}
+
 void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
 {
     if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
         return;
 
+    if (ImGui::GetIO().KeyShift)
+    {
+        AddRoundCornerCircle(this, centre, radius, col, false);
+        return;
+    }
+
     // Because we are filling a closed shape we remove 1 from the count of segments/points
     const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
     PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments - 1);
@@ -1083,6 +1348,12 @@
     if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
         return;
 
+    if (ImGui::GetIO().KeyShift)
+    {
+        AddRoundCornerCircle(this, centre, radius, col, true);
+        return;
+    }
+
     // Because we are filling a closed shape we remove 1 from the count of segments/points
     const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
     PathArcTo(centre, radius, 0.0f, a_max, num_segments - 1);
@@ -1495,6 +1766,8 @@
     TexWidth = TexHeight = 0;
     TexUvScale = ImVec2(0.0f, 0.0f);
     TexUvWhitePixel = ImVec2(0.0f, 0.0f);
+
+    RoundCornersMaxSize = 60;
     for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)
         CustomRectIds[n] = -1;
 }
@@ -1526,6 +1799,7 @@
     CustomRects.clear();
     for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)
         CustomRectIds[n] = -1;
+    RoundCornersRectIds.clear();
 }
 
 void    ImFontAtlas::ClearTexData()
@@ -1537,6 +1811,8 @@
         IM_FREE(TexPixelsRGBA32);
     TexPixelsAlpha8 = NULL;
     TexPixelsRGBA32 = NULL;
+    TexUvRoundCornerFilled.clear();
+    TexUvRoundCornerStroked.clear();
 }
 
 void    ImFontAtlas::ClearFonts()
@@ -1840,6 +2116,7 @@
     IM_ASSERT(atlas->ConfigData.Size > 0);
 
     ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
+    ImFontAtlasBuildRegisterRoundCornersCustomRects(atlas);
 
     // Clear atlas
     atlas->TexID = (ImTextureID)NULL;
@@ -2173,11 +2450,103 @@
     atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * atlas->TexUvScale.x, (r.Y + 0.5f) * atlas->TexUvScale.y);
 }
 
+const unsigned int FONT_ATLAS_ROUNDED_CORNER_TEX_DATA_ID = 0x80000001;
+const int          FONT_ATLAS_ROUNDED_CORNER_TEX_PADDING = 2;
+
+void ImFontAtlasBuildRegisterRoundCornersCustomRects(ImFontAtlas* atlas)
+{
+    if (atlas->RoundCornersRectIds.size() > 0)
+        return;
+
+    if ((atlas->Flags & ImFontAtlasFlags_NoRoundCorners))
+        return;
+
+    const int pad = FONT_ATLAS_ROUNDED_CORNER_TEX_PADDING;
+    const int max = atlas->RoundCornersMaxSize;
+
+    // Filled
+    for (int n = 0; n < max; n++)
+        atlas->RoundCornersRectIds.push_back(atlas->AddCustomRectRegular(FONT_ATLAS_ROUNDED_CORNER_TEX_DATA_ID + n,
+            n + 1 + pad * 2, n + 1 + pad * 2));
+
+    // Stroked
+    for (int n = 0; n < max; n++)
+        atlas->RoundCornersRectIds.push_back(atlas->AddCustomRectRegular(FONT_ATLAS_ROUNDED_CORNER_TEX_DATA_ID + max + n,
+            n + 1 + pad * 2, n + 1 + pad * 2));
+}
+
+static void ImFontAtlasBuildRenderRoundCornersTexData(ImFontAtlas* atlas)
+{
+    IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
+    IM_ASSERT(atlas->TexUvRoundCornerFilled.size() == 0);
+    IM_ASSERT(atlas->TexUvRoundCornerStroked.size() == 0);
+
+    if ((atlas->Flags & ImFontAtlasFlags_NoRoundCorners))
+        return;
+
+    const int w = atlas->TexWidth;
+    const unsigned int max = atlas->RoundCornersMaxSize;
+
+    // Filled
+    for (unsigned int stage = 0; stage < 2; stage++)
+    {
+        bool filled = stage == 0;
+        for (unsigned int n = 0; n < max; n++)
+        {
+            const unsigned int id = (filled ? 0 : max) + n;
+            IM_ASSERT(atlas->RoundCornersRectIds.size() > (int) n);
+            ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->RoundCornersRectIds[id]];
+            IM_ASSERT(r.ID == FONT_ATLAS_ROUNDED_CORNER_TEX_DATA_ID + id);
+            IM_ASSERT(r.IsPacked());
+
+            const int pad = FONT_ATLAS_ROUNDED_CORNER_TEX_PADDING;
+
+            IM_ASSERT(r.Width == n + 1 + pad * 2 && r.Height == n + 1 + pad * 2);
+
+            const int radius = (int)(r.Width - pad * 2);
+            const float stroke_width = 1.0f;
+
+            for (int y = -pad; y < (int) (radius); y++)
+                for (int x = (filled ? -pad : y); x < (int)(filled ? y + pad : radius); x++)
+                {
+                    const float dist = ImSqrt((float)(x*x+y*y)) - (float)(radius - (filled ? 0 : stroke_width));
+
+                    float alpha = 0.0f;
+                    if (filled)
+                    {
+                        alpha = ImClamp(-dist, 0.0f, 1.0f);
+                    }
+                    else
+                    {
+                        const float alpha1 = ImClamp(dist + stroke_width, 0.0f, 1.0f);
+                        const float alpha2 = ImClamp(dist, 0.0f, 1.0f);
+                        alpha = alpha1 - alpha2;
+                    }
+
+                    const unsigned int offset = (int)(r.X + pad + x) + (int)(r.Y + pad + y) * w;
+                    atlas->TexPixelsAlpha8[offset] = (unsigned char)(0xFF * ImSaturate(alpha));
+                }
+
+            ImVec2 uv0, uv1;
+            r.X += pad;
+            r.Y += pad;
+            r.Width -= pad * 2;
+            r.Height -= pad * 2;
+            atlas->CalcCustomRectUV(&r, &uv0, &uv1);
+            ImVector<ImVec4>& uvs = (filled ? atlas->TexUvRoundCornerFilled : atlas->TexUvRoundCornerStroked);
+            uvs.push_back(ImVec4(uv0.x, uv0.y, uv1.x, uv1.y));
+        }
+    }
+}
+
 void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
 {
     // Render into our custom data block
     ImFontAtlasBuildRenderDefaultTexData(atlas);
 
+    // Render into our rounded corner data block
+    ImFontAtlasBuildRenderRoundCornersTexData(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 f82225e..66e06ff 100644
--- a/imgui_internal.h
+++ b/imgui_internal.h
@@ -726,17 +726,21 @@
 // Data shared between all ImDrawList instances
 struct IMGUI_API ImDrawListSharedData
 {
-    ImVec2          TexUvWhitePixel;            // UV of white pixel in the atlas
-    ImFont*         Font;                       // Current/default font (optional, for simplified AddText overload)
-    float           FontSize;                   // Current/default font size (optional, for simplified AddText overload)
+    ImVec2          TexUvWhitePixel;          // UV of white pixel in the atlas
+    ImFont*         Font;                     // Current/default font (optional, for simplified AddText overload)
+    float           FontSize;                 // Current/default font size (optional, for simplified AddText overload)
     float           CurveTessellationTol;
-    ImVec4          ClipRectFullscreen;         // Value for PushClipRectFullscreen()
-    ImDrawListFlags InitialFlags;               // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)
+    ImVec4          ClipRectFullscreen;       // Value for PushClipRectFullscreen()
+    ImDrawListFlags InitialFlags;             // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)
 
     // Const data
     // FIXME: Bake rounded corners fill/borders in atlas
     ImVec2          CircleVtx12[12];
 
+    // FIXME-ROUNDSHAPES: WIP + need to remove CircleVtx12 before PR
+    ImVector<ImVec4>* TexUvRoundCornerFilled;   // UV of filled round corner quad in the atlas
+    ImVector<ImVec4>* TexUvRoundCornerStroked;  // UV of stroked round corner quad in the atlas
+
     ImDrawListSharedData();
 };
 
@@ -1654,6 +1658,7 @@
 // ImFontAtlas internals
 IMGUI_API bool              ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas);
 IMGUI_API void              ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas);
+IMGUI_API void              ImFontAtlasBuildRegisterRoundCornersCustomRects(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              ImFontAtlasBuildFinish(ImFontAtlas* atlas);