mirror of
https://github.com/Drezil/imgui.git
synced 2024-11-26 13:37:00 +00:00
Texture-based round corners: Using ImFabs() + Minor coding style fixes for consistency
This commit is contained in:
parent
054c87fc4f
commit
edb797538d
@ -1489,14 +1489,13 @@ inline bool AddRoundCornerRect(ImDrawList* draw_list, const ImVec2& a, const ImV
|
|||||||
const ImVec2 mdy2(mdy.x, mdy.y - line_width), mcy2(mcy.x, mcy.y - line_width);
|
const ImVec2 mdy2(mdy.x, mdy.y - line_width), mcy2(mcy.x, mcy.y - line_width);
|
||||||
const ImVec2 id(cd.x + rad_d, cd.y - rad_d), ic(cc.x - rad_c, cc.y - rad_c);
|
const ImVec2 id(cd.x + rad_d, cd.y - rad_d), ic(cc.x - rad_c, cc.y - rad_c);
|
||||||
|
|
||||||
// Generate points CA2-CD2, which are the corner points but inset towards the centre by the line width
|
// Generate points CA2-CD2, which are the corner points but inset towards the center by the line width
|
||||||
// These are used as edge line end points when rendering un-rounded corners in non-filled mode
|
// These are used as edge line end points when rendering un-rounded corners in non-filled mode
|
||||||
|
|
||||||
const ImVec2 ca2(ca.x + line_width, ca.y + line_width), cb2(cb.x - line_width, cb.y + line_width);
|
const ImVec2 ca2(ca.x + line_width, ca.y + line_width), cb2(cb.x - line_width, cb.y + line_width);
|
||||||
const ImVec2 cc2(cc.x - line_width, cc.y - line_width), cd2(cd.x + line_width, cd.y - line_width);
|
const ImVec2 cc2(cc.x - line_width, cc.y - line_width), cd2(cd.x + line_width, cd.y - line_width);
|
||||||
|
|
||||||
// Reserve enough space for the worse-case vertex/index count
|
// Reserve enough space for the worse-case vertex/index count (we give back any left over space later)
|
||||||
// (we give back any left over space later)
|
|
||||||
const int vtcs = 48;
|
const int vtcs = 48;
|
||||||
const int idcs = 32 * 3;
|
const int idcs = 32 * 3;
|
||||||
draw_list->PrimReserve(idcs, vtcs);
|
draw_list->PrimReserve(idcs, vtcs);
|
||||||
@ -1536,10 +1535,8 @@ inline bool AddRoundCornerRect(ImDrawList* draw_list, const ImVec2& a, const ImV
|
|||||||
ImVec2(ImLerp(corner_uv[0].x, corner_uv[b##corner ? 2 : 1].x, px), ImLerp(corner_uv[0].y, corner_uv[b##corner ? 2 : 1].y, py)); \
|
ImVec2(ImLerp(corner_uv[0].x, corner_uv[b##corner ? 2 : 1].x, px), ImLerp(corner_uv[0].y, corner_uv[b##corner ? 2 : 1].y, py)); \
|
||||||
draw_list->_VtxWritePtr[d].col = col
|
draw_list->_VtxWritePtr[d].col = col
|
||||||
|
|
||||||
// Set up the outer corners (vca-vcd being the four outermost
|
// Set up the outer corners (vca-vcd being the four outermost corners)
|
||||||
// corners)
|
// If the corner is rounded we use the "empty" corner UV, if not we use the "filled" one.
|
||||||
// If the corner is rounded we use the "empty" corner UV, if not we use
|
|
||||||
// the "filled" one
|
|
||||||
const int vca = 0, vcb = 1, vcc = 2, vcd = 3;
|
const int vca = 0, vcb = 1, vcc = 2, vcd = 3;
|
||||||
VTX_WRITE(vca, ca, ba ? 2 : 1);
|
VTX_WRITE(vca, ca, ba ? 2 : 1);
|
||||||
VTX_WRITE(vcb, cb, bb ? 2 : 1);
|
VTX_WRITE(vcb, cb, bb ? 2 : 1);
|
||||||
@ -2044,19 +2041,13 @@ inline bool AddRoundCornerCircle(ImDrawList* draw_list, const ImVec2& center, fl
|
|||||||
IM_ASSERT(tex_id == draw_list->_TextureIdStack.back()); // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
|
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;
|
const int rad = (int)radius;
|
||||||
|
|
||||||
if ((rad < 1) || // Radius 0 will cause issues with the UV lookup below
|
if ((rad < 1) || // Radius 0 will cause issues with the UV lookup below
|
||||||
(rad > data->Font->ContainerAtlas->RoundCornersMaxSize))
|
(rad > data->Font->ContainerAtlas->RoundCornersMaxSize))
|
||||||
{
|
return false; // We can't handle this
|
||||||
// We can't handle this
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Debug command to force this render path to only execute when shift is held
|
// Debug command to force this render path to only execute when shift is held
|
||||||
if (!ImGui::GetIO().KeyShift)
|
if (!ImGui::GetIO().KeyShift)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate UVs for the three points we are interested in from the texture
|
// Calculate UVs for the three points we are interested in from the texture
|
||||||
// corner_uv[0] is the innermost point of the circle (solid for filled circles)
|
// corner_uv[0] is the innermost point of the circle (solid for filled circles)
|
||||||
@ -2086,7 +2077,7 @@ inline bool AddRoundCornerCircle(ImDrawList* draw_list, const ImVec2& center, fl
|
|||||||
const float sqrt_two_minus_one = 0.41421356f; // sqrt(2.0f) - 1.0f
|
const float sqrt_two_minus_one = 0.41421356f; // sqrt(2.0f) - 1.0f
|
||||||
|
|
||||||
// The positions of our intermediate vertices
|
// The positions of our intermediate vertices
|
||||||
// These are organised by quadrant (TL = top-left, etc),
|
// These are organized by quadrant (TL = top-left, etc),
|
||||||
// with A being the first point encountered when walking clockwise
|
// with A being the first point encountered when walking clockwise
|
||||||
// around the circle within that quadrant, B the second and C the third.
|
// around the circle within that quadrant, B the second and C the third.
|
||||||
// These points form a tight fit around the outer edge of the circle.
|
// These points form a tight fit around the outer edge of the circle.
|
||||||
@ -2129,9 +2120,9 @@ inline bool AddRoundCornerCircle(ImDrawList* draw_list, const ImVec2& center, fl
|
|||||||
draw_list->PrimReserve(num_indices, num_verts);
|
draw_list->PrimReserve(num_indices, num_verts);
|
||||||
|
|
||||||
// Write a vertex
|
// Write a vertex
|
||||||
// d is the vertex index to write to
|
// - d is the vertex index to write to
|
||||||
// vert_pos is the vertex position
|
// - vert_pos is the vertex position
|
||||||
// uv_coord is the UV coordinate
|
// - uv_coord is the UV coordinate
|
||||||
#define VTX_WRITE(d, vert_pos, uv_coord) \
|
#define VTX_WRITE(d, vert_pos, uv_coord) \
|
||||||
draw_list->_VtxWritePtr[d].pos = vert_pos; \
|
draw_list->_VtxWritePtr[d].pos = vert_pos; \
|
||||||
draw_list->_VtxWritePtr[d].uv = uv_coord; \
|
draw_list->_VtxWritePtr[d].uv = uv_coord; \
|
||||||
@ -2157,13 +2148,12 @@ inline bool AddRoundCornerCircle(ImDrawList* draw_list, const ImVec2& center, fl
|
|||||||
|
|
||||||
if (fill)
|
if (fill)
|
||||||
{
|
{
|
||||||
// The centre
|
// The center
|
||||||
VTX_WRITE(16, c, corner_uv[0]);
|
VTX_WRITE(16, c, corner_uv[0]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Inside vertices, offset from the "B" vertices by the line width
|
// Inside vertices, offset from the "B" vertices by the line width
|
||||||
|
|
||||||
const ImVec2 tlbi = ImVec2(ImLerp(c.x, tl.x, half_sqrt_two - width_offset_parametric), ImLerp(c.y, tl.y, half_sqrt_two - width_offset_parametric));
|
const ImVec2 tlbi = ImVec2(ImLerp(c.x, tl.x, half_sqrt_two - width_offset_parametric), ImLerp(c.y, tl.y, half_sqrt_two - width_offset_parametric));
|
||||||
const ImVec2 trbi = ImVec2(ImLerp(c.x, br.x, half_sqrt_two - width_offset_parametric), ImLerp(c.y, tl.y, half_sqrt_two - width_offset_parametric));
|
const ImVec2 trbi = ImVec2(ImLerp(c.x, br.x, half_sqrt_two - width_offset_parametric), ImLerp(c.y, tl.y, half_sqrt_two - width_offset_parametric));
|
||||||
const ImVec2 brbi = ImVec2(ImLerp(c.x, br.x, half_sqrt_two - width_offset_parametric), ImLerp(c.y, br.y, half_sqrt_two - width_offset_parametric));
|
const ImVec2 brbi = ImVec2(ImLerp(c.x, br.x, half_sqrt_two - width_offset_parametric), ImLerp(c.y, br.y, half_sqrt_two - width_offset_parametric));
|
||||||
@ -2196,7 +2186,7 @@ inline bool AddRoundCornerCircle(ImDrawList* draw_list, const ImVec2& center, fl
|
|||||||
|
|
||||||
if (fill)
|
if (fill)
|
||||||
{
|
{
|
||||||
// A simple fan of tris from the centre
|
// A simple fan of tris from the center
|
||||||
IDX_WRITE_TRI(0, 16, 0, 1);
|
IDX_WRITE_TRI(0, 16, 0, 1);
|
||||||
IDX_WRITE_TRI(3, 16, 1, 2);
|
IDX_WRITE_TRI(3, 16, 1, 2);
|
||||||
IDX_WRITE_TRI(6, 16, 2, 3);
|
IDX_WRITE_TRI(6, 16, 2, 3);
|
||||||
@ -2268,11 +2258,8 @@ void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int nu
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// First try the fast texture-based renderer, and only if that can't handle this fall back to paths
|
// First try the fast texture-based renderer, and only if that can't handle this fall back to paths
|
||||||
|
|
||||||
if (AddRoundCornerCircle(this, center, radius, col, false))
|
if (AddRoundCornerCircle(this, center, radius, col, false))
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain segment count
|
// Obtain segment count
|
||||||
if (num_segments <= 0)
|
if (num_segments <= 0)
|
||||||
@ -3582,7 +3569,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas)
|
|||||||
const int FONT_ATLAS_ROUNDED_CORNER_TEX_PADDING = 2;
|
const int FONT_ATLAS_ROUNDED_CORNER_TEX_PADDING = 2;
|
||||||
// Padding applied to the Y axis to separate the two halves of the image
|
// Padding applied to the Y axis to separate the two halves of the image
|
||||||
// This must be a multiple of two
|
// This must be a multiple of two
|
||||||
const int FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING = 4;
|
const int FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING = 4;
|
||||||
|
|
||||||
// Register the rectangles we need for the rounded corner images
|
// Register the rectangles we need for the rounded corner images
|
||||||
static void ImFontAtlasBuildRegisterRoundCornersCustomRects(ImFontAtlas* atlas)
|
static void ImFontAtlasBuildRegisterRoundCornersCustomRects(ImFontAtlas* atlas)
|
||||||
@ -3594,9 +3581,8 @@ static void ImFontAtlasBuildRegisterRoundCornersCustomRects(ImFontAtlas* atlas)
|
|||||||
|
|
||||||
const int pad = FONT_ATLAS_ROUNDED_CORNER_TEX_PADDING;
|
const int pad = FONT_ATLAS_ROUNDED_CORNER_TEX_PADDING;
|
||||||
const int max = atlas->RoundCornersMaxSize;
|
const int max = atlas->RoundCornersMaxSize;
|
||||||
|
|
||||||
for (int n = 0; n < max; n++)
|
for (int n = 0; n < max; n++)
|
||||||
atlas->RoundCornersRectIds.push_back(atlas->AddCustomRectRegular(n + 1 + pad * 2, n + 1 + FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING + pad * 2));
|
atlas->RoundCornersRectIds.push_back(atlas->AddCustomRectRegular(n + 1 + pad * 2, n + 1 + FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING + pad * 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the actual pixel data for rounded corners in the atlas
|
// Generate the actual pixel data for rounded corners in the atlas
|
||||||
@ -3618,20 +3604,19 @@ static void ImFontAtlasBuildRenderRoundCornersTexData(ImFontAtlas* atlas)
|
|||||||
IM_ASSERT((int)n < atlas->RoundCornersRectIds.Size);
|
IM_ASSERT((int)n < atlas->RoundCornersRectIds.Size);
|
||||||
ImFontAtlasCustomRect& r = atlas->CustomRects[atlas->RoundCornersRectIds[id]];
|
ImFontAtlasCustomRect& r = atlas->CustomRects[atlas->RoundCornersRectIds[id]];
|
||||||
IM_ASSERT(r.IsPacked());
|
IM_ASSERT(r.IsPacked());
|
||||||
IM_ASSERT(r.Width == n + 1 + pad * 2 && r.Height == n + 1 + FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING + pad * 2);
|
IM_ASSERT(r.Width == n + 1 + pad * 2 && r.Height == n + 1 + FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING + pad * 2);
|
||||||
|
|
||||||
// What we're doing here is generating a rectangular image that contains the data for both the filled and
|
// What we're doing here is generating a rectangular image that contains the data for both the filled and
|
||||||
// stroked variants of the corner with the radius specified. We do it like this because we only need 45 degrees
|
// stroked variants of the corner with the radius specified. We do it like this because we only need 45 degrees
|
||||||
// worth of curve (as each corner mirrors the texture to get the full 90 degrees), and hence with a little care
|
// worth of curve (as each corner mirrors the texture to get the full 90 degrees), and hence with a little care
|
||||||
// we can put both variants into one texture by using two triangular regions. In practice this is a little more
|
// we can put both variants into one texture by using two triangular regions. In practice this is a little more
|
||||||
// tricky than it first looks because if the two regions are packed tightly you get filtering errors where they meet,
|
// tricky than it first looks because if the two regions are packed tightly you get filtering errors where they meet,
|
||||||
// so we offset one vertically from the other by FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING pixels.
|
// so we offset one vertically from the other by FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING pixels.
|
||||||
// The stroked version is at the top-right of the texture, and the filled version at the bottom-left.
|
// The stroked version is at the top-right of the texture, and the filled version at the bottom-left.
|
||||||
|
|
||||||
const int radius = (int)(r.Width - pad * 2);
|
const int radius = (int)(r.Width - pad * 2);
|
||||||
const float stroke_width = 1.0f;
|
const float stroke_width = 1.0f;
|
||||||
|
|
||||||
for (int y = -pad; y < (int)(radius + FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING); y++)
|
for (int y = -pad; y < (int)(radius + FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING); y++)
|
||||||
for (int x = -pad; x < (int)(radius); x++)
|
for (int x = -pad; x < (int)(radius); x++)
|
||||||
{
|
{
|
||||||
// We want the pad area to essentially contain a clamped version of the 0th row/column, so
|
// We want the pad area to essentially contain a clamped version of the 0th row/column, so
|
||||||
@ -3640,14 +3625,13 @@ static void ImFontAtlasBuildRenderRoundCornersTexData(ImFontAtlas* atlas)
|
|||||||
int cy = ImMax(y, 0);
|
int cy = ImMax(y, 0);
|
||||||
|
|
||||||
// The X<Y region of the texture contains the data for filled corners, the X>Y region
|
// The X<Y region of the texture contains the data for filled corners, the X>Y region
|
||||||
// the data for stroked ones. We add half of FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING so that
|
// the data for stroked ones. We add half of FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING so that
|
||||||
// each side gets a buffer zone to avoid filtering artifacts.
|
// each side gets a buffer zone to avoid filtering artifacts.
|
||||||
bool filled = x < (y - (FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING >> 1));
|
const bool filled = x < (y - (FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING >> 1));
|
||||||
|
|
||||||
if (filled)
|
if (filled)
|
||||||
{
|
{
|
||||||
// The filled version starts a little further down the texture to give us the padding in the middle.
|
// The filled version starts a little further down the texture to give us the padding in the middle.
|
||||||
cy = ImMax(y - FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING, 0);
|
cy = ImMax(y - FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const float dist = ImSqrt((float)(cx*cx+cy*cy)) - (float)(radius - (filled ? 0 : stroke_width));
|
const float dist = ImSqrt((float)(cx*cx+cy*cy)) - (float)(radius - (filled ? 0 : stroke_width));
|
||||||
@ -3668,21 +3652,19 @@ static void ImFontAtlasBuildRenderRoundCornersTexData(ImFontAtlas* atlas)
|
|||||||
atlas->TexPixelsAlpha8[offset] = (unsigned char)(0xFF * ImSaturate(alpha));
|
atlas->TexPixelsAlpha8[offset] = (unsigned char)(0xFF * ImSaturate(alpha));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We generate two sets of UVs for each rectangle, one for the filled portion and one for the
|
// We generate two sets of UVs for each rectangle, one for the filled portion and one for the unfilled bit.
|
||||||
// unfilled bit
|
|
||||||
|
|
||||||
for (unsigned int stage = 0; stage < 2; stage++)
|
for (unsigned int stage = 0; stage < 2; stage++)
|
||||||
{
|
{
|
||||||
ImFontAtlasCustomRect stageRect = r;
|
ImFontAtlasCustomRect stage_rect = r;
|
||||||
|
|
||||||
|
const bool filled = (stage == 0);
|
||||||
|
stage_rect.X += pad;
|
||||||
|
stage_rect.Y += pad + (filled ? FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING : 0);
|
||||||
|
stage_rect.Width -= (pad * 2);
|
||||||
|
stage_rect.Height -= (pad * 2) + FONT_ATLAS_ROUNDED_CORNER_TEX_CENTER_PADDING;
|
||||||
|
|
||||||
bool filled = stage == 0;
|
|
||||||
ImVec2 uv0, uv1;
|
ImVec2 uv0, uv1;
|
||||||
stageRect.X += pad;
|
atlas->CalcCustomRectUV(&stage_rect, &uv0, &uv1);
|
||||||
stageRect.Y += pad + (filled ? FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING : 0);
|
|
||||||
stageRect.Width -= (pad * 2);
|
|
||||||
stageRect.Height -= (pad * 2) + FONT_ATLAS_ROUNDED_CORNER_TEX_CENTRE_PADDING;
|
|
||||||
|
|
||||||
atlas->CalcCustomRectUV(&stageRect, &uv0, &uv1);
|
|
||||||
ImVector<ImVec4>& uvs = (filled ? atlas->TexUvRoundCornerFilled : atlas->TexUvRoundCornerStroked);
|
ImVector<ImVec4>& uvs = (filled ? atlas->TexUvRoundCornerFilled : atlas->TexUvRoundCornerStroked);
|
||||||
uvs.push_back(ImVec4(uv0.x, uv0.y, uv1.x, uv1.y));
|
uvs.push_back(ImVec4(uv0.x, uv0.y, uv1.x, uv1.y));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user