mirror of
				https://github.com/ocornut/imgui.git
				synced 2025-11-04 09:44:29 +00:00 
			
		
		
		
	AddCircle, AddCircleFilled: Add auto-calculation of circle segment counts
This commit is contained in:
		@@ -988,6 +988,7 @@ ImGuiStyle::ImGuiStyle()
 | 
			
		||||
    AntiAliasedLines        = true;             // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
 | 
			
		||||
    AntiAliasedFill         = true;             // Enable anti-aliasing on 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   = 0.75f;            // 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.
 | 
			
		||||
 | 
			
		||||
    // Default theme
 | 
			
		||||
    ImGui::StyleColorsDark(this);
 | 
			
		||||
@@ -3560,6 +3561,7 @@ static void NewFrameSanityChecks()
 | 
			
		||||
    IM_ASSERT(g.IO.Fonts->Fonts.Size > 0                                && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
 | 
			
		||||
    IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()                          && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
 | 
			
		||||
    IM_ASSERT(g.Style.CurveTessellationTol > 0.0f                       && "Invalid style setting!");
 | 
			
		||||
    IM_ASSERT(g.Style.CircleSegmentMaxError > 0.0f                      && "Invalid style setting!");
 | 
			
		||||
    IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f            && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!");
 | 
			
		||||
    IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
 | 
			
		||||
    IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
 | 
			
		||||
@@ -3622,6 +3624,7 @@ void ImGui::NewFrame()
 | 
			
		||||
    IM_ASSERT(g.Font->IsLoaded());
 | 
			
		||||
    g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
 | 
			
		||||
    g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
 | 
			
		||||
    g.DrawListSharedData.CircleSegmentMaxError = g.Style.CircleSegmentMaxError;
 | 
			
		||||
    g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
 | 
			
		||||
    if (g.Style.AntiAliasedLines)
 | 
			
		||||
        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
 | 
			
		||||
@@ -3630,6 +3633,10 @@ void ImGui::NewFrame()
 | 
			
		||||
    if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
 | 
			
		||||
        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
 | 
			
		||||
 | 
			
		||||
    // Recalculate circle segment counts if the segment error has changed
 | 
			
		||||
    if (g.DrawListSharedData.CircleSegmentMaxError != g.DrawListSharedData.CircleSegmentCountsMaxCircleSegmentError)
 | 
			
		||||
        g.DrawListSharedData.RecalculateCircleSegmentCounts();
 | 
			
		||||
 | 
			
		||||
    g.BackgroundDrawList.Clear();
 | 
			
		||||
    g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID);
 | 
			
		||||
    g.BackgroundDrawList.PushClipRectFullScreen();
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								imgui.h
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								imgui.h
									
									
									
									
									
								
							@@ -1359,6 +1359,7 @@ struct ImGuiStyle
 | 
			
		||||
    bool        AntiAliasedLines;           // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU.
 | 
			
		||||
    bool        AntiAliasedFill;            // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
 | 
			
		||||
    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.
 | 
			
		||||
    ImVec4      Colors[ImGuiCol_COUNT];
 | 
			
		||||
 | 
			
		||||
    IMGUI_API ImGuiStyle();
 | 
			
		||||
@@ -1948,10 +1949,10 @@ struct ImDrawList
 | 
			
		||||
    IMGUI_API void  AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col);
 | 
			
		||||
    IMGUI_API void  AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f);
 | 
			
		||||
    IMGUI_API void  AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col);
 | 
			
		||||
    IMGUI_API void  AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f);
 | 
			
		||||
    IMGUI_API void  AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 12);
 | 
			
		||||
    IMGUI_API void  AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f);
 | 
			
		||||
    IMGUI_API void  AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments);
 | 
			
		||||
    IMGUI_API void  AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f); // Draw a circle - use num_segments <= 0 to automatically calculate tessellation (preferred). Use AddNgon() instead if you need a specific segment count.
 | 
			
		||||
    IMGUI_API void  AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 12); // Draw a filled circle - use num_segments <= 0 to automatically calculate tessellation (preferred). Use AddNgonFilled() instead if you need a specific segment count.
 | 
			
		||||
    IMGUI_API void  AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f); // Draw an n-gon with a specific number of sides. Use AddCircle() instead if you want an actual circle and don't care about the exact side count.
 | 
			
		||||
    IMGUI_API void  AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments); // Draw a filled n-gon with a specific number of sides. Use AddCircleFilled() instead if you want an actual circle and don't care about the exact side count.
 | 
			
		||||
    IMGUI_API void  AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
 | 
			
		||||
    IMGUI_API void  AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL);
 | 
			
		||||
    IMGUI_API void  AddPolyline(const ImVec2* points, int num_points, ImU32 col, bool closed, float thickness);
 | 
			
		||||
 
 | 
			
		||||
@@ -3502,6 +3502,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
 | 
			
		||||
            ImGui::PushItemWidth(100);
 | 
			
		||||
            ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, "%.2f", 2.0f);
 | 
			
		||||
            if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
 | 
			
		||||
            ImGui::DragFloat("Max circle segment error", &style.CircleSegmentMaxError, 0.01f, 0.1f, 10.0f, "%.2f", 1.0f);
 | 
			
		||||
            ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero.
 | 
			
		||||
            ImGui::PopItemWidth();
 | 
			
		||||
 | 
			
		||||
@@ -4471,7 +4472,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
 | 
			
		||||
                // First line uses a thickness of 1.0f, second line uses the configurable thickness
 | 
			
		||||
                float th = (n == 0) ? 1.0f : thickness;
 | 
			
		||||
                draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th);         x += sz + spacing;  // n-gon
 | 
			
		||||
                draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, 20, th);               x += sz + spacing;  // Circle
 | 
			
		||||
                draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, 0, th);                x += sz + spacing;  // Circle
 | 
			
		||||
                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f,  corners_none, th);     x += sz + spacing;  // Square
 | 
			
		||||
                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th);      x += sz + spacing;  // Square with all rounded corners
 | 
			
		||||
                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th);    x += sz + spacing;  // Square with two rounded corners
 | 
			
		||||
@@ -4485,7 +4486,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
 | 
			
		||||
                y += sz + spacing;
 | 
			
		||||
            }
 | 
			
		||||
            draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides);   x += sz + spacing;  // n-gon
 | 
			
		||||
            draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, 32);             x += sz + spacing;  // Circle
 | 
			
		||||
            draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, 0);              x += sz + spacing;  // Circle
 | 
			
		||||
            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col);                        x += sz + spacing;  // Square
 | 
			
		||||
            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f);                 x += sz + spacing;  // Square with all rounded corners
 | 
			
		||||
            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br);  x += sz + spacing;  // Square with two rounded corners
 | 
			
		||||
 
 | 
			
		||||
@@ -348,6 +348,8 @@ ImDrawListSharedData::ImDrawListSharedData()
 | 
			
		||||
    Font = NULL;
 | 
			
		||||
    FontSize = 0.0f;
 | 
			
		||||
    CurveTessellationTol = 0.0f;
 | 
			
		||||
    CircleSegmentMaxError = 0.0f;
 | 
			
		||||
    CircleSegmentCountsMaxCircleSegmentError = -FLT_MIN; // Impossible value to force recalculation
 | 
			
		||||
    ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f);
 | 
			
		||||
    InitialFlags = ImDrawListFlags_None;
 | 
			
		||||
 | 
			
		||||
@@ -1083,11 +1085,34 @@ void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImV
 | 
			
		||||
    PathFillConvex(col);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ImDrawListSharedData::RecalculateCircleSegmentCounts()
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; i < NumCircleSegmentCounts; i++)
 | 
			
		||||
    {
 | 
			
		||||
        const float radius = i + 1.0f;
 | 
			
		||||
        CircleSegmentCounts[i] = ImClamp((int)((IM_PI * 2.0f) / ImAcos((radius - CircleSegmentMaxError) / radius)), 3, 10000);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CircleSegmentCountsMaxCircleSegmentError = CircleSegmentMaxError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
 | 
			
		||||
{
 | 
			
		||||
    if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
 | 
			
		||||
    if ((col & IM_COL32_A_MASK) == 0 || (radius <= 0.0f))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // Calculate number of segments if required
 | 
			
		||||
    if (num_segments <= 0)
 | 
			
		||||
    {
 | 
			
		||||
        int radius_int = (int)radius;
 | 
			
		||||
        if (radius_int <= ImDrawListSharedData::NumCircleSegmentCounts)
 | 
			
		||||
            num_segments = _Data->CircleSegmentCounts[radius_int - 1]; // Use cached value
 | 
			
		||||
        else
 | 
			
		||||
            num_segments = ImClamp((int)((IM_PI * 2.0f) / ImAcos((radius - _Data->CircleSegmentMaxError) / radius)), 3, 10000);
 | 
			
		||||
    }
 | 
			
		||||
    else    
 | 
			
		||||
        num_segments = ImClamp(num_segments, 3, 10000); // Clamp to avoid drawing insanely tessellated shapes
 | 
			
		||||
 | 
			
		||||
    // 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(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
 | 
			
		||||
@@ -1096,9 +1121,21 @@ void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int nu
 | 
			
		||||
 | 
			
		||||
void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
 | 
			
		||||
{
 | 
			
		||||
    if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
 | 
			
		||||
    if ((col & IM_COL32_A_MASK) == 0 || (radius <= 0.0f))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // Calculate number of segments if required
 | 
			
		||||
    if (num_segments <= 0)
 | 
			
		||||
    {
 | 
			
		||||
        int radius_int = (int)radius;
 | 
			
		||||
        if (radius_int <= ImDrawListSharedData::NumCircleSegmentCounts)
 | 
			
		||||
            num_segments = _Data->CircleSegmentCounts[radius_int - 1]; // Use cached value
 | 
			
		||||
        else
 | 
			
		||||
            num_segments = ImClamp((int)((IM_PI * 2.0f) / ImAcos((radius - _Data->CircleSegmentMaxError) / radius)), 3, 10000);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        num_segments = ImClamp(num_segments, 3, 10000); // Clamp to avoid drawing insanely tessellated shapes
 | 
			
		||||
 | 
			
		||||
    // 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(center, radius, 0.0f, a_max, num_segments - 1);
 | 
			
		||||
 
 | 
			
		||||
@@ -855,6 +855,7 @@ struct IMGUI_API ImDrawListSharedData
 | 
			
		||||
    ImFont*         Font;                       // Current/default font (optional, for simplified AddText overload)
 | 
			
		||||
    float           FontSize;                   // Current/default font size (optional, for simplified AddText overload)
 | 
			
		||||
    float           CurveTessellationTol;       // Tessellation tolerance when using PathBezierCurveTo()
 | 
			
		||||
    float           CircleSegmentMaxError;      // Number of circle segments to use per pixel of radius for AddCircle() etc
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
@@ -862,6 +863,13 @@ struct IMGUI_API ImDrawListSharedData
 | 
			
		||||
    // FIXME: Bake rounded corners fill/borders in atlas
 | 
			
		||||
    ImVec2          CircleVtx12[12];
 | 
			
		||||
 | 
			
		||||
    // Cached circle segment counts for the first <n> radii (to avoid calculation overhead)
 | 
			
		||||
    static const int NumCircleSegmentCounts = 64;// Number of circle segment counts to cache (i.e. the maximum radius before we calculate dynamically)
 | 
			
		||||
    int             CircleSegmentCounts[NumCircleSegmentCounts]; // The segment count for radius (array index + 1)
 | 
			
		||||
    float           CircleSegmentCountsMaxCircleSegmentError; // The MaxCircleSegmentError used to calculate these counts
 | 
			
		||||
 | 
			
		||||
    void RecalculateCircleSegmentCounts();      // Recalculate circle segment counts based on the current MaxCircleSegmentError
 | 
			
		||||
 | 
			
		||||
    ImDrawListSharedData();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user