mirror of
https://github.com/Drezil/imgui.git
synced 2024-11-25 05:06:59 +00:00
Improve on automatic circle segment count calculation. (#3808) Amends
This commit is contained in:
parent
f107693d9b
commit
fb15d8c858
@ -35,8 +35,16 @@ HOW TO UPDATE?
|
|||||||
VERSION 1.82 WIP (In Progresss)
|
VERSION 1.82 WIP (In Progresss)
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Breaking Changes:
|
||||||
|
|
||||||
|
- Style: renamed rarely used style.CircleSegmentMaxError (old default = 1.60f)
|
||||||
|
to style.CircleTessellationMaxError (new default = 0.30f) as its meaning changed. (#3808) [@thedmd]
|
||||||
|
|
||||||
Other Changes:
|
Other Changes:
|
||||||
|
|
||||||
|
- ImDrawList: AddCircle, AddCircleFilled(): Tweaked default segment count calculation to honor MaxError
|
||||||
|
with more accuracy. Made default segment count always even for better looking result. (#3808) [@thedmd]
|
||||||
|
- ImDrawList: AddCircle, AddCircleFilled(): New default for style.
|
||||||
- CI: Use a dedicated "scheduled" workflow to trigger scheduled builds. Forks may disable this workflow if
|
- CI: Use a dedicated "scheduled" workflow to trigger scheduled builds. Forks may disable this workflow if
|
||||||
scheduled builds builds are not required. [@rokups]
|
scheduled builds builds are not required. [@rokups]
|
||||||
|
|
||||||
|
@ -375,6 +375,7 @@ CODE
|
|||||||
When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
|
When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
|
||||||
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
|
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
|
||||||
|
|
||||||
|
- 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed.
|
||||||
- 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete).
|
- 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete).
|
||||||
- removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete).
|
- removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete).
|
||||||
- renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete).
|
- renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete).
|
||||||
@ -986,7 +987,7 @@ ImGuiStyle::ImGuiStyle()
|
|||||||
AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering.
|
AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering.
|
||||||
AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
|
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.
|
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.
|
||||||
CircleTessellationMaxError = 0.25f; // 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.
|
CircleTessellationMaxError = 0.30f; // 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
|
// Default theme
|
||||||
ImGui::StyleColorsDark(this);
|
ImGui::StyleColorsDark(this);
|
||||||
|
@ -6034,41 +6034,39 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
|
|||||||
if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
|
if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
|
||||||
|
|
||||||
// When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
|
// When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
|
||||||
ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 10.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
|
ImGui::DragFloat("Circle Tessellation Max Error", &style.CircleTessellationMaxError , 0.005f, 0.10f, 5.0f, "%.2f", ImGuiSliderFlags_AlwaysClamp);
|
||||||
if (ImGui::IsItemActive())
|
if (ImGui::IsItemActive())
|
||||||
{
|
{
|
||||||
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
|
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
|
||||||
ImGui::BeginTooltip();
|
ImGui::BeginTooltip();
|
||||||
ImGui::TextUnformatted("N - number of segments");
|
ImGui::TextUnformatted("(R = radius, N = number of segments)");
|
||||||
ImGui::TextUnformatted("R - radius");
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
const float min_widget_width = ImGui::CalcTextSize("N: MM\nR: MM.MM").x;
|
const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x;
|
||||||
float RAD_MIN = 5.0f, RAD_MAX = 80.0f;
|
for (int n = 0; n < 8; n++)
|
||||||
for (int n = 0; n < 9; n++)
|
|
||||||
{
|
{
|
||||||
const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (9.0f - 1.0f);
|
const float RAD_MIN = 5.0f;
|
||||||
|
const float RAD_MAX = 70.0f;
|
||||||
const int segment_count = draw_list->_CalcCircleAutoSegmentCount(rad);
|
const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (8.0f - 1.0f);
|
||||||
|
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
ImGui::Text("R: %.f", rad);
|
|
||||||
ImGui::Text("N: %d", segment_count);
|
|
||||||
|
|
||||||
const float circle_diameter = rad * 2.0f;
|
ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
|
||||||
const float canvas_width = IM_MAX(min_widget_width, circle_diameter);
|
|
||||||
const float offset_x = floorf(canvas_width * 0.5f);
|
|
||||||
const float offset_y = floorf(RAD_MAX);
|
|
||||||
const ImVec2 p = ImGui::GetCursorScreenPos();
|
|
||||||
draw_list->AddCircle(ImVec2(p.x + offset_x, p.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
|
|
||||||
|
|
||||||
|
const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
|
||||||
|
const float offset_x = floorf(canvas_width * 0.5f);
|
||||||
|
const float offset_y = floorf(RAD_MAX);
|
||||||
|
|
||||||
|
const ImVec2 p1 = ImGui::GetCursorScreenPos();
|
||||||
|
draw_list->AddCircle(ImVec2(p1.x + offset_x, p1.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
|
||||||
ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
|
ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
|
||||||
ImGui::Text("N: %d", segment_count);
|
|
||||||
|
|
||||||
const ImVec2 p2 = ImGui::GetCursorScreenPos();
|
/*
|
||||||
|
const ImVec2 p2 = ImGui::GetCursorScreenPos();
|
||||||
draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
|
draw_list->AddCircleFilled(ImVec2(p2.x + offset_x, p2.y + offset_y), rad, ImGui::GetColorU32(ImGuiCol_Text));
|
||||||
|
|
||||||
ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
|
ImGui::Dummy(ImVec2(canvas_width, RAD_MAX * 2));
|
||||||
|
*/
|
||||||
|
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
}
|
}
|
||||||
|
@ -544,17 +544,12 @@ void ImDrawList::_OnChangedVtxOffset()
|
|||||||
|
|
||||||
int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
|
int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
|
||||||
{
|
{
|
||||||
int num_segments = 0;
|
|
||||||
|
|
||||||
const int radius_idx = (int)ImCeil(radius); // Use ceil to never reduce accuracy
|
|
||||||
|
|
||||||
// Automatic segment count
|
// Automatic segment count
|
||||||
|
const int radius_idx = (int)(radius + 0.999f); // ceil to never reduce accuracy
|
||||||
if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
|
if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
|
||||||
num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value
|
return _Data->CircleSegmentCounts[radius_idx]; // Use cached value
|
||||||
else
|
else
|
||||||
num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
|
return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
|
||||||
|
|
||||||
return num_segments;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
|
// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
|
||||||
|
@ -617,29 +617,20 @@ struct IMGUI_API ImChunkStream
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value.
|
// ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value.
|
||||||
//
|
// Estimation of number of circle segment based on error is derived using method described in https://stackoverflow.com/a/2244088/15194693
|
||||||
// Estimation of number of circle segment based on error is derived using method described in
|
|
||||||
// this post (https://stackoverflow.com/a/2244088/15194693).
|
|
||||||
// Number of segments (N) is calculated using equation:
|
// Number of segments (N) is calculated using equation:
|
||||||
//
|
// N = ceil ( pi / acos(1 - error / r) ) where r > 0, error <= r
|
||||||
// +- -+
|
// Our equation is significantly simpler that one in the post thanks for choosing segment that is
|
||||||
// | pi |
|
// perpendicular to X axis. Follow steps in the article from this starting condition and you will
|
||||||
// N = ceil | --------------------- | where r > 0, error <= r
|
// will get this result.
|
||||||
// | acos(1 - error / r) |
|
|
||||||
// +- -+
|
|
||||||
//
|
|
||||||
// Note:
|
|
||||||
// Equation is significantly simpler that one in the post thanks for choosing segment
|
|
||||||
// that is perpendicular to X axis. Follow steps in the article from this starting condition
|
|
||||||
// and you will get this result.
|
|
||||||
//
|
//
|
||||||
// Rendering circles with an odd number of segments, while mathematically correct will produce
|
// Rendering circles with an odd number of segments, while mathematically correct will produce
|
||||||
// asymmetrical results on the raster grid. Therefore we're rounding N to next even number.
|
// asymmetrical results on the raster grid. Therefore we're rounding N to next even number (7->8, 8->8, 9->10 etc.)
|
||||||
// (7 became 8, 11 became 12, but 8 will still be 8).
|
|
||||||
//
|
//
|
||||||
|
#define IM_ROUNDUP_TO_EVEN(_V) ((((_V) + 1) / 2) * 2)
|
||||||
#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 4
|
#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN 4
|
||||||
#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512
|
#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX 512
|
||||||
#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp((((int)ImCeil(IM_PI / ImAcos(1 - ImMin((_MAXERROR), (_RAD)) / (_RAD))) + 1) / 2) * 2, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX)
|
#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR) ImClamp(IM_ROUNDUP_TO_EVEN((int)ImCeil(IM_PI / ImAcos(1 - ImMin((_MAXERROR), (_RAD)) / (_RAD)))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX)
|
||||||
|
|
||||||
// ImDrawList: You may set this to higher values (e.g. 2 or 3) to increase tessellation of fast rounded corners path.
|
// ImDrawList: You may set this to higher values (e.g. 2 or 3) to increase tessellation of fast rounded corners path.
|
||||||
#ifndef IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER
|
#ifndef IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER
|
||||||
@ -660,8 +651,8 @@ struct IMGUI_API ImDrawListSharedData
|
|||||||
|
|
||||||
// [Internal] Lookup tables
|
// [Internal] Lookup tables
|
||||||
ImVec2 ArcFastVtx[12 * IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER]; // FIXME: Bake rounded corners fill/borders in atlas
|
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 before we calculate it dynamically (to avoid calculation overhead)
|
ImU8 CircleSegmentCounts[64]; // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead)
|
||||||
const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas
|
const ImVec4* TexUvLines; // UV of anti-aliased lines in the atlas
|
||||||
|
|
||||||
ImDrawListSharedData();
|
ImDrawListSharedData();
|
||||||
void SetCircleTessellationMaxError(float max_error);
|
void SetCircleTessellationMaxError(float max_error);
|
||||||
|
Loading…
Reference in New Issue
Block a user