mirror of
https://github.com/Drezil/imgui.git
synced 2025-01-12 00:36:37 +00:00
Texture-based round corners: Store rounded corners in texture to use 1 quad per corner.
This commit is contained in:
parent
b6b8f6634e
commit
fbc6bce06b
74
imgui.cpp
74
imgui.cpp
@ -5519,13 +5519,14 @@ struct ImGuiResizeGripDef
|
||||
ImVec2 CornerPosN;
|
||||
ImVec2 InnerDir;
|
||||
int AngleMin12, AngleMax12;
|
||||
ImDrawFlags 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 (Unused)
|
||||
{ ImVec2(1, 0), ImVec2(-1, +1), 9, 12 } // Upper-right (Unused)
|
||||
{ ImVec2(1, 1), ImVec2(-1, -1), 0, 3, ImDrawFlags_RoundCornersBottomRight }, // Lower-right
|
||||
{ ImVec2(0, 1), ImVec2(+1, -1), 3, 6, ImDrawFlags_RoundCornersBottomLeft }, // Lower-left
|
||||
{ ImVec2(0, 0), ImVec2(+1, +1), 6, 9, ImDrawFlags_RoundCornersTopLeft }, // Upper-left (Unused)
|
||||
{ ImVec2(1, 0), ImVec2(-1, +1), 9,12, ImDrawFlags_RoundCornersTopRight }, // Upper-right (Unused)
|
||||
};
|
||||
|
||||
// Data for resizing from borders
|
||||
@ -5543,6 +5544,51 @@ static const ImGuiResizeBorderDef resize_border_def[4] =
|
||||
{ ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f } // Down
|
||||
};
|
||||
|
||||
static void AddResizeGrip(ImDrawList* dl, const ImVec2& corner, unsigned int rad, int 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 (corners_flags)
|
||||
{
|
||||
case ImDrawFlags_RoundCornersTopLeft:
|
||||
case ImDrawFlags_RoundCornersTopRight:
|
||||
case ImDrawFlags_RoundCornersBottomLeft:
|
||||
case ImDrawFlags_RoundCornersBottomRight:
|
||||
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 (corners_flags & (ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight))
|
||||
in_y.y += rad;
|
||||
else if (corners_flags & (ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight))
|
||||
in_y.y -= rad;
|
||||
if (corners_flags & (ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomLeft))
|
||||
in_x.x += rad;
|
||||
else if (corners_flags & (ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomRight))
|
||||
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();
|
||||
@ -5815,10 +5861,20 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6837,6 +6893,8 @@ void ImGui::SetCurrentFont(ImFont* font)
|
||||
ImFontAtlas* atlas = g.Font->ContainerAtlas;
|
||||
g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
|
||||
g.DrawListSharedData.TexUvLines = atlas->TexUvLines;
|
||||
g.DrawListSharedData.TexUvRoundCornerFilled = &atlas->TexUvRoundCornerFilled;
|
||||
g.DrawListSharedData.TexUvRoundCornerStroked = &atlas->TexUvRoundCornerStroked;
|
||||
g.DrawListSharedData.Font = g.Font;
|
||||
g.DrawListSharedData.FontSize = g.FontSize;
|
||||
}
|
||||
|
9
imgui.h
9
imgui.h
@ -2718,7 +2718,8 @@ enum ImFontAtlasFlags_
|
||||
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_NoBakedLines = 1 << 2 // Don't build thick line textures into the atlas (save a little texture memory). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU).
|
||||
ImFontAtlasFlags_NoBakedLines = 1 << 2, // Don't build thick line textures into the atlas (save a little texture memory). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU).
|
||||
ImFontAtlasFlags_NoBakedRoundCorners= 1 << 3 // Don't build round corners into the atlas.
|
||||
};
|
||||
|
||||
// Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding:
|
||||
@ -2832,6 +2833,12 @@ struct ImFontAtlas
|
||||
int PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors
|
||||
int PackIdLines; // Custom texture rectangle ID for baked anti-aliased lines
|
||||
|
||||
// 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
|
||||
|
||||
// [Obsolete]
|
||||
//typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+
|
||||
//typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
|
||||
|
109
imgui_demo.cpp
109
imgui_demo.cpp
@ -240,6 +240,113 @@ void ImGui::ShowUserGuide()
|
||||
ImGui::Unindent();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static void TestTextureBasedRender()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui::TextUnformatted("Press SHIFT to toggle quads (hold to see them).");
|
||||
ImGui::TextUnformatted(io.KeyShift ? "SHIFT ON -- Rasterized quad circle! w00t! OPTIMIZATION!"
|
||||
: "SHIFT OFF -- Regular, boring circle with PathArcToFast.");
|
||||
|
||||
static float radius = io.Fonts->RoundCornersMaxSize * 0.5f;
|
||||
ImGui::SliderFloat("radius", &radius, 0.0f, (float)io.Fonts->RoundCornersMaxSize, "%.0f");
|
||||
ImGui::BeginGroup();
|
||||
|
||||
static int segments = 20;
|
||||
ImGui::PushItemWidth(120);
|
||||
ImGui::SliderInt("segments", &segments, 3, 100);
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
int vtx = 0;
|
||||
int idx = 0;
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
|
||||
{
|
||||
ImGui::Button("##1", ImVec2(200, 200));
|
||||
GetVtxIdxDelta(dl, &vtx, &idx);
|
||||
ImVec2 min = ImGui::GetItemRectMin();
|
||||
ImVec2 size = ImGui::GetItemRectSize();
|
||||
dl->AddCircleFilled(ImVec2(min.x + size.x * 0.5f, min.y + size.y * 0.5f), radius, 0xFFFF00FF, segments);
|
||||
GetVtxIdxDelta(dl, &vtx, &idx);
|
||||
ImGui::Text("AddCircleFilled\n %d vtx, %d idx", vtx, idx);
|
||||
}
|
||||
{
|
||||
ImGui::Button("##2", ImVec2(200, 200));
|
||||
GetVtxIdxDelta(dl, &vtx, &idx);
|
||||
ImVec2 min = ImGui::GetItemRectMin();
|
||||
ImVec2 size = ImGui::GetItemRectSize();
|
||||
dl->AddCircle(ImVec2(min.x + size.x * 0.5f, min.y + size.y * 0.5f), radius, 0xFFFF00FF, segments);
|
||||
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;
|
||||
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);
|
||||
|
||||
ImDrawFlags flags = 0;
|
||||
flags |= tl ? ImDrawFlags_RoundCornersTopLeft : 0;
|
||||
flags |= tr ? ImDrawFlags_RoundCornersTopRight : 0;
|
||||
flags |= bl ? ImDrawFlags_RoundCornersBottomLeft : 0;
|
||||
flags |= br ? ImDrawFlags_RoundCornersBottomRight : 0;
|
||||
if (flags == 0)
|
||||
flags |= ImDrawFlags_RoundCornersNone;
|
||||
|
||||
{
|
||||
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, radius, 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, radius, 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));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Demo Window / ShowDemoWindow()
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -409,6 +516,8 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION);
|
||||
ImGui::Spacing();
|
||||
|
||||
TestTextureBasedRender();
|
||||
|
||||
IMGUI_DEMO_MARKER("Help");
|
||||
if (ImGui::CollapsingHeader("Help"))
|
||||
{
|
||||
|
385
imgui_draw.cpp
385
imgui_draw.cpp
@ -1388,12 +1388,199 @@ void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float th
|
||||
PathStroke(col, 0, thickness);
|
||||
}
|
||||
|
||||
inline void AddRoundCornerRect(ImDrawList* draw_list, const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, ImDrawFlags flags, bool fill)
|
||||
{
|
||||
#if 1
|
||||
flags = FixRectCornerFlags(flags);
|
||||
rounding = ImMin(rounding, ImFabs(b.x - a.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f);
|
||||
rounding = ImMin(rounding, ImFabs(b.y - a.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f);
|
||||
#endif
|
||||
|
||||
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 = (flags & ImDrawFlags_RoundCornersTopLeft) != 0;
|
||||
const bool bb = (flags & ImDrawFlags_RoundCornersTopRight) != 0;
|
||||
const bool bc = (flags & ImDrawFlags_RoundCornersBottomRight) != 0;
|
||||
const bool bd = (flags & ImDrawFlags_RoundCornersBottomLeft) != 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
|
||||
}
|
||||
|
||||
// p_min = upper-left, p_max = lower-right
|
||||
// Note we don't render 1 pixels sized rectangles properly.
|
||||
void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawFlags flags, float thickness)
|
||||
{
|
||||
if ((col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
#if 1
|
||||
flags = FixRectCornerFlags(flags);
|
||||
rounding = ImMin(rounding, ImFabs(p_max.x - p_min.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f);
|
||||
rounding = ImMin(rounding, ImFabs(p_max.y - p_min.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f);
|
||||
#endif
|
||||
|
||||
// FIXME-ROUND-SHAPES: NOTE HACK TODO figure out why it's broken on small rounding
|
||||
if (ImGui::GetIO().KeyShift && rounding > 3)
|
||||
return AddRoundCornerRect(this, p_min, p_max, col, rounding, flags, /* fill */ false);
|
||||
|
||||
if (Flags & ImDrawListFlags_AntiAliasedLines)
|
||||
PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, flags);
|
||||
else
|
||||
@ -1405,6 +1592,13 @@ void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 c
|
||||
{
|
||||
if ((col & IM_COL32_A_MASK) == 0)
|
||||
return;
|
||||
|
||||
#if 1
|
||||
flags = FixRectCornerFlags(flags);
|
||||
rounding = ImMin(rounding, ImFabs(p_max.x - p_min.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f);
|
||||
rounding = ImMin(rounding, ImFabs(p_max.y - p_min.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f);
|
||||
#endif
|
||||
|
||||
if (rounding <= 0.0f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
|
||||
{
|
||||
PrimReserve(6, 4);
|
||||
@ -1412,8 +1606,17 @@ void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 c
|
||||
}
|
||||
else
|
||||
{
|
||||
PathRect(p_min, p_max, rounding, 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, p_min, p_max, col, rounding, flags, /* fill */ true);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PathRect(p_min, p_max, rounding, flags);
|
||||
PathFillConvex(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1479,11 +1682,86 @@ void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImV
|
||||
PathFillConvex(col);
|
||||
}
|
||||
|
||||
inline void AddRoundCornerCircle(ImDrawList* draw_list, const ImVec2& center, 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 = center;
|
||||
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& center, float radius, ImU32 col, int num_segments, float thickness)
|
||||
{
|
||||
if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f)
|
||||
return;
|
||||
|
||||
if (ImGui::GetIO().KeyShift)
|
||||
{
|
||||
AddRoundCornerCircle(this, center, radius, col, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtain segment count
|
||||
if (num_segments <= 0)
|
||||
{
|
||||
// Use arc with automatic segment count
|
||||
@ -1545,6 +1823,12 @@ void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, in
|
||||
if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
|
||||
return;
|
||||
|
||||
if (ImGui::GetIO().KeyShift)
|
||||
{
|
||||
AddRoundCornerCircle(this, center, 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(center, radius, 0.0f, a_max, num_segments - 1);
|
||||
@ -1977,6 +2261,8 @@ ImFontAtlas::ImFontAtlas()
|
||||
memset(this, 0, sizeof(*this));
|
||||
TexGlyphPadding = 1;
|
||||
PackIdMouseCursors = PackIdLines = -1;
|
||||
|
||||
RoundCornersMaxSize = 60;
|
||||
}
|
||||
|
||||
ImFontAtlas::~ImFontAtlas()
|
||||
@ -2005,6 +2291,7 @@ void ImFontAtlas::ClearInputData()
|
||||
ConfigData.clear();
|
||||
CustomRects.clear();
|
||||
PackIdMouseCursors = PackIdLines = -1;
|
||||
RoundCornersRectIds.clear();
|
||||
// Important: we leave TexReady untouched
|
||||
}
|
||||
|
||||
@ -2018,6 +2305,8 @@ void ImFontAtlas::ClearTexData()
|
||||
TexPixelsAlpha8 = NULL;
|
||||
TexPixelsRGBA32 = NULL;
|
||||
TexPixelsUseColors = false;
|
||||
TexUvRoundCornerFilled.clear();
|
||||
TexUvRoundCornerStroked.clear();
|
||||
// Important: we leave TexReady untouched
|
||||
}
|
||||
|
||||
@ -2755,6 +3044,8 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas)
|
||||
}
|
||||
}
|
||||
|
||||
static void ImFontAtlasBuildRegisterRoundCornersCustomRects(ImFontAtlas* atlas);
|
||||
|
||||
// Note: this is called / shared by both the stb_truetype and the FreeType builder
|
||||
void ImFontAtlasBuildInit(ImFontAtlas* atlas)
|
||||
{
|
||||
@ -2774,6 +3065,93 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas)
|
||||
if (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines))
|
||||
atlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1);
|
||||
}
|
||||
|
||||
ImFontAtlasBuildRegisterRoundCornersCustomRects(atlas);
|
||||
}
|
||||
|
||||
const int FONT_ATLAS_ROUNDED_CORNER_TEX_PADDING = 2;
|
||||
|
||||
static void ImFontAtlasBuildRegisterRoundCornersCustomRects(ImFontAtlas* atlas)
|
||||
{
|
||||
if (atlas->RoundCornersRectIds.size() > 0)
|
||||
return;
|
||||
|
||||
if ((atlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners))
|
||||
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(n + 1 + pad * 2, n + 1 + pad * 2));
|
||||
|
||||
// Stroked
|
||||
for (int n = 0; n < max; n++)
|
||||
atlas->RoundCornersRectIds.push_back(atlas->AddCustomRectRegular(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_NoBakedRoundCorners))
|
||||
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);
|
||||
ImFontAtlasCustomRect& r = atlas->CustomRects[atlas->RoundCornersRectIds[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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is called/shared by both the stb_truetype and the FreeType builder.
|
||||
@ -2784,6 +3162,9 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
|
||||
ImFontAtlasBuildRenderDefaultTexData(atlas);
|
||||
ImFontAtlasBuildRenderLinesTexData(atlas);
|
||||
|
||||
// Render into our rounded corner data block
|
||||
ImFontAtlasBuildRenderRoundCornersTexData(atlas);
|
||||
|
||||
// Register custom rectangle glyphs
|
||||
for (int i = 0; i < atlas->CustomRects.Size; i++)
|
||||
{
|
||||
|
@ -725,6 +725,10 @@ struct IMGUI_API ImDrawListSharedData
|
||||
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
|
||||
|
||||
// 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();
|
||||
void SetCircleTessellationMaxError(float max_error);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user