Draw list 1.93: baked round corners in the font atlas (ImFontAtlasBuildUpdateTexDataCorners, fill radii 1..16 + 3 stroke thicknesses) used by AddRect/AddRectFilled when pixel-aligned (_AddRectBaked/_AddRectFilledBaked)
This commit is contained in:
+380
-7
@@ -446,7 +446,10 @@ local ImFontAtlasBakedGetClosestMatch
|
||||
local ImFontAtlasBuildInit
|
||||
local ImFontAtlasBuildSetTexture
|
||||
local ImFontAtlasBuildUpdateTexDataLines
|
||||
local ImFontAtlasBuildUpdateTexDataCorners
|
||||
local ImFontAtlasBuildUpdateTexDataBasic
|
||||
local IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC -- [Luau] forward declared, defined in [SECTION] ImDrawList
|
||||
local CalcCornerArcStepAndCount -- [Luau] forward declared, defined in [SECTION] ImDrawList
|
||||
local ImFontAtlasBuildSetupFontLoader
|
||||
local ImFontAtlasBuildSetupFontSpecialGlyphs
|
||||
local ImFontAtlasBuildSetupFontBakedBlanks
|
||||
@@ -1952,7 +1955,7 @@ end
|
||||
function ImFontAtlasBuildUpdateTexData(atlas)
|
||||
ImFontAtlasBuildUpdateTexDataBasic(atlas)
|
||||
ImFontAtlasBuildUpdateTexDataLines(atlas)
|
||||
-- [Port] TODO baked round corners: ImFontAtlasBuildUpdateTexDataCorners(atlas)
|
||||
ImFontAtlasBuildUpdateTexDataCorners(atlas)
|
||||
end
|
||||
|
||||
-- Create a new texture, discard previous one
|
||||
@@ -2076,6 +2079,176 @@ function ImFontAtlasPackInit(atlas)
|
||||
end
|
||||
|
||||
--- @param atlas ImFontAtlas
|
||||
-- #define IM_DRAWLIST_CORNER_POINTS_MAX (IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4 + 3) // Max number of points in corner profiles
|
||||
-- [Luau] ImVec2 line_normals[] / float line_distances[] / ImVec2 points[] are flat 1-based scratch arrays (x, y, distance).
|
||||
local corner_points_x, corner_points_y = {}, {}
|
||||
local corner_normals_x, corner_normals_y, corner_distances = {}, {}, {}
|
||||
|
||||
-- [Luau] line_normals is passed as two arrays (line_normals_x, line_normals_y), 1-based.
|
||||
local function InitCornerGeometry(cx, cy, rounding, circle_segment_max_error, line_normals_x, line_normals_y, line_distances)
|
||||
-- This tries to quite faithfully replicate how we render the corners using tessellation.
|
||||
-- Older code sampled a circle SDF directly, but it had clearly visible discrepancy between the baked corners
|
||||
-- and tessellated corners due to circle_segment_max_error.
|
||||
|
||||
local auto_seg_count = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(rounding, circle_segment_max_error)
|
||||
local arc_step, arc_step_count = CalcCornerArcStepAndCount(auto_seg_count)
|
||||
local arc_point_count = arc_step_count + 1
|
||||
|
||||
-- Build arc of points, with straight segments at each end.
|
||||
-- . [n-2]..[n-1]
|
||||
-- .`
|
||||
-- .
|
||||
-- [1] x (cx,cy)
|
||||
-- :
|
||||
-- [0]
|
||||
local points_x, points_y = corner_points_x, corner_points_y
|
||||
local num_points = 0
|
||||
|
||||
num_points = num_points + 1; points_x[num_points] = cx - rounding; points_y[num_points] = cy + 1.0
|
||||
|
||||
local da = (arc_step / IM_DRAWLIST_ARCFAST_TABLE_SIZE) * IM_PI * 2.0
|
||||
local a = IM_PI
|
||||
for _ = 0, arc_point_count - 1 do
|
||||
local dx = ImCos(a)
|
||||
local dy = ImSin(a)
|
||||
num_points = num_points + 1; points_x[num_points] = cx + dx * rounding; points_y[num_points] = cy + dy * rounding
|
||||
a = a + da
|
||||
end
|
||||
|
||||
num_points = num_points + 1; points_x[num_points] = cx + 1.0; points_y[num_points] = cy - rounding
|
||||
|
||||
-- Turn segments to half spaces.
|
||||
for i = 1, num_points - 1 do
|
||||
local diff_x = points_x[i + 1] - points_x[i]
|
||||
local diff_y = points_y[i + 1] - points_y[i]
|
||||
local d2 = diff_x * diff_x + diff_y * diff_y
|
||||
local inv_d = ImRsqrtPrecise(d2)
|
||||
line_normals_x[i] = diff_y * inv_d -- Normal points outwards
|
||||
line_normals_y[i] = -diff_x * inv_d
|
||||
line_distances[i] = -(points_x[i] * line_normals_x[i] + points_y[i] * line_normals_y[i]) -- -ImDot()
|
||||
end
|
||||
|
||||
return num_points - 1
|
||||
end
|
||||
|
||||
-- Returns distance to convex shape limited by lines.
|
||||
local function SampleConvex(x, y, line_normals_x, line_normals_y, line_distances, num_lines)
|
||||
local result = -FLT_MAX
|
||||
for i = 1, num_lines do
|
||||
local d = line_normals_x[i] * x + line_normals_y[i] * y + line_distances[i]
|
||||
if d > result then
|
||||
result = d
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function SampleCornerFillOrStroke(x, y, thickness, line_normals_x, line_normals_y, line_distances, num_lines)
|
||||
local d = SampleConvex(x, y, line_normals_x, line_normals_y, line_distances, num_lines)
|
||||
local aa_width = 1.0
|
||||
if thickness == 0.0 then
|
||||
-- Fill
|
||||
return math.floor(ImClamp(1.0 - (d + aa_width * 0.5) / aa_width, 0.0, 1.0) * 255.0) -- (ImU8)
|
||||
else
|
||||
-- Stroke
|
||||
local outer = 1.0 - (d + aa_width * 0.5) / aa_width
|
||||
local inner = (d + thickness + aa_width * 0.5) / aa_width
|
||||
return math.floor(ImClamp(ImMin(inner, outer), 0.0, 1.0) * 255.0) -- (ImU8)
|
||||
end
|
||||
end
|
||||
|
||||
-- [Port] #if 0 DEBUG_TEX_CORNER_U8/DEBUG_TEX_CORNER_U32 coverage visualization not ported (always 0xFF/0xFFFFFFFF).
|
||||
|
||||
function ImFontAtlasBuildUpdateTexDataCorners(atlas)
|
||||
if bit32.band(atlas.Flags, ImFontAtlasFlags.NoBakedRoundCorners) ~= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
-- Pack and store identifier so we can refresh UV coordinates on texture resize.
|
||||
local tex = atlas.TexData
|
||||
local builder = atlas.Builder
|
||||
|
||||
-- FIXME-TEXCORNERS: Ideally we should pick up the max error from the styles, but it does not seem be to set by the time we build the data the first time.
|
||||
local circle_segment_max_error = 0.30 -- Default matching ImGuiStyle::CircleTessellationMaxError.
|
||||
-- if (atlas->OwnerContext)
|
||||
-- circle_segment_max_error = atlas->OwnerContext->DrawListSharedData.CircleSegmentMaxError;
|
||||
|
||||
-- Calculate size and pack
|
||||
local r = ImFontAtlasRect()
|
||||
local add_and_draw = (atlas:GetCustomRect(builder.PackIdCornersTexData, r) == false)
|
||||
if add_and_draw then
|
||||
-- (thickness 0 for filled, thickness >0 for strokes)
|
||||
local pack_size_x, pack_size_y = 0, 0 -- ImVec2i
|
||||
for thickness = 0, IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX - 1 do
|
||||
local is_filled = (thickness == 0)
|
||||
local row_width = 0
|
||||
local row_height = 0
|
||||
for n = 0, IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX - 1 do
|
||||
local rounding = n + 1
|
||||
local size = is_filled and (rounding + 1) or ImMax(rounding, thickness)
|
||||
row_width = row_width + size + 2
|
||||
row_height = ImMax(row_height, size + 2)
|
||||
end
|
||||
pack_size_x = ImMax(pack_size_x, row_width)
|
||||
pack_size_y = pack_size_y + row_height
|
||||
end
|
||||
builder.PackIdCornersTexData = atlas:AddCustomRect(pack_size_x, pack_size_y, r)
|
||||
IM_ASSERT(builder.PackIdCornersTexData ~= ImFontAtlasRectId_Invalid)
|
||||
end
|
||||
|
||||
-- Render
|
||||
local y = r.y
|
||||
local line_normals_x, line_normals_y, line_distances = corner_normals_x, corner_normals_y, corner_distances
|
||||
for thickness = 0, IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX - 1 do
|
||||
local is_filled = (thickness == 0)
|
||||
local x = r.x
|
||||
local row_height = 0
|
||||
for n = 0, IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX - 1 do
|
||||
-- Filled: Always add 1px to the fill side of the rounded corner to prevent the corner AA to bleed into the rectangle edges.
|
||||
local rounding = n + 1
|
||||
local size = is_filled and (rounding + 1) or ImMax(rounding, thickness)
|
||||
local w = size + 2
|
||||
local h = size + 2
|
||||
|
||||
-- Corner circle
|
||||
local cx = 1.0 + (n + 1)
|
||||
local cy = 1.0 + (n + 1)
|
||||
IM_ASSERT((x + w) <= (r.x + r.w) and (y + h) <= (r.y + r.h)) -- Make sure we're inside the texture bounds
|
||||
local num_lines = InitCornerGeometry(cx, cy, rounding, circle_segment_max_error, line_normals_x, line_normals_y, line_distances)
|
||||
|
||||
-- Write each slice
|
||||
if add_and_draw and tex.Format == ImTextureFormat.Alpha8 then
|
||||
local write_ptr, write_ptr_base = tex:GetPixelsAt(x, y)
|
||||
local pitch = tex.Width
|
||||
for ly = 0, h - 1 do
|
||||
for lx = 0, w - 1 do
|
||||
write_ptr[write_ptr_base + lx] = SampleCornerFillOrStroke(lx + 0.5, ly + 0.5, thickness, line_normals_x, line_normals_y, line_distances, num_lines)
|
||||
end
|
||||
write_ptr_base = write_ptr_base + pitch
|
||||
end
|
||||
elseif add_and_draw and tex.Format == ImTextureFormat.RGBA32 then
|
||||
local write_ptr, write_ptr_base = tex:GetPixelsAt(x, y)
|
||||
local pitch = tex.Width * 4
|
||||
for ly = 0, h - 1 do
|
||||
for lx = 0, w - 1 do
|
||||
write_u32(write_ptr, write_ptr_base + lx * 4, IM_COL32(255, 255, 255, SampleCornerFillOrStroke(lx + 0.5, ly + 0.5, thickness, line_normals_x, line_normals_y, line_distances, num_lines)))
|
||||
end
|
||||
write_ptr_base = write_ptr_base + pitch
|
||||
end
|
||||
end
|
||||
|
||||
-- Refresh UV coordinates
|
||||
local uv0_x, uv0_y = (x + 1) * atlas.TexUvScale.x, (y + 1) * atlas.TexUvScale.y
|
||||
local uv1_x, uv1_y = (x + 1 + size) * atlas.TexUvScale.x, (y + 1 + size) * atlas.TexUvScale.y
|
||||
builder.TexUvCorners[n + thickness * IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX] = ImVec4(uv0_x, uv0_y, uv1_x, uv1_y)
|
||||
|
||||
x = x + w
|
||||
row_height = ImMax(row_height, h)
|
||||
end
|
||||
y = y + row_height
|
||||
end
|
||||
end
|
||||
|
||||
function ImFontAtlasBuildUpdateTexDataLines(atlas)
|
||||
if bit32.band(atlas.Flags, ImFontAtlasFlags.NoBakedLines) ~= 0 then
|
||||
return
|
||||
@@ -2283,6 +2456,7 @@ function ImFontAtlasUpdateDrawListsSharedData(atlas)
|
||||
if (shared_data.FontAtlas == atlas) then
|
||||
shared_data.TexUvWhitePixel = atlas.TexUvWhitePixel
|
||||
shared_data.TexUvLines = atlas.Builder.TexUvLines
|
||||
shared_data.TexUvCorners = atlas.Builder.TexUvCorners
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3714,13 +3888,13 @@ end
|
||||
local IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN = 4
|
||||
local IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX = 512
|
||||
|
||||
local function IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD, _MAXERROR) return ImClamp(IM_ROUNDUP_TO_EVEN(ImCeil(IM_PI / ImAcos(1 - ImMin(_MAXERROR, _RAD) / _RAD))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) end
|
||||
function IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD, _MAXERROR) return ImClamp(IM_ROUNDUP_TO_EVEN(ImCeil(IM_PI / ImAcos(1 - ImMin(_MAXERROR, _RAD) / _RAD))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX) end
|
||||
local function IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(_N, _MAXERROR) return (_MAXERROR / (1 - ImCos(IM_PI / ImMax(_N, IM_PI)))) end
|
||||
local function IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_ERROR(_N, _RAD) return ((1 - ImCos(IM_PI / ImMax(_N, IM_PI))) / _RAD) end
|
||||
|
||||
-- Calculates arc step and step count for 90 degree arc. The calculated arc step will complete a 90 degree arc when stepped arc_step_count times.
|
||||
-- [Luau] returns arc_step, arc_step_count (C++ out-references)
|
||||
local function CalcCornerArcStepAndCount(segment_count)
|
||||
function CalcCornerArcStepAndCount(segment_count)
|
||||
local quarter = IM_DRAWLIST_ARCFAST_TABLE_SIZE / 4
|
||||
local arc_step = ImClamp(math.floor(IM_DRAWLIST_ARCFAST_SAMPLE_MAX / segment_count), 1, quarter)
|
||||
local arc_step_count = math.floor(quarter / arc_step)
|
||||
@@ -5329,7 +5503,122 @@ function MT.ImDrawList:AddLineV(x, min_y, max_y, col, thickness, flags)
|
||||
end
|
||||
end
|
||||
|
||||
-- [Port] TODO baked round corners: _AddRectBaked() (UseTexForRoundCorners) not ported yet, AddRect() falls back to the geometry path.
|
||||
-- [Luau] IM_APPEND_VTX() x4 + IM_APPEND_TRI(idx + 0, idx + 1, idx + 2) + IM_APPEND_TRI(idx + 0, idx + 2, idx + 3)
|
||||
local function AppendQuadUV(self, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, col)
|
||||
local vb = self.VtxBuffer.Buf
|
||||
local ib = self.IdxBuffer.Data
|
||||
local vw = self._VtxWritePtr
|
||||
local iw = self._IdxWritePtr
|
||||
local idx = self._VtxCurrentIdx
|
||||
WV(vb, vw + 0, x0, y0, u0, v0, col)
|
||||
WV(vb, vw + 1, x1, y1, u1, v1, col)
|
||||
WV(vb, vw + 2, x2, y2, u2, v2, col)
|
||||
WV(vb, vw + 3, x3, y3, u3, v3, col)
|
||||
ib[iw + 0] = idx + 0; ib[iw + 1] = idx + 1; ib[iw + 2] = idx + 2
|
||||
ib[iw + 3] = idx + 0; ib[iw + 4] = idx + 2; ib[iw + 5] = idx + 3
|
||||
self._VtxWritePtr = vw + 4
|
||||
self._IdxWritePtr = iw + 6
|
||||
self._VtxCurrentIdx = idx + 4
|
||||
end
|
||||
|
||||
-- [Luau] _AddRectBaked() taking p_min/p_max as scalars
|
||||
@native
|
||||
local function _AddRectBakedXY(self, p_min_x, p_min_y, p_max_x, p_max_y, col, r, t, tex_uvs, flags)
|
||||
local uv_l, uv_t, uv_r, uv_b = tex_uvs.x, tex_uvs.y, tex_uvs.z, tex_uvs.w -- uv_tl = (l,t), uv_tr = (r,t), uv_br = (r,b), uv_bl = (l,b)
|
||||
|
||||
local idx_allocated = 8 * 2 * 3
|
||||
local vtx_allocated = 8 * 4
|
||||
PrimReserve(self, idx_allocated, vtx_allocated)
|
||||
local start_vtx_ptr = self._VtxWritePtr
|
||||
local start_idx_ptr = self._IdxWritePtr
|
||||
|
||||
local round_tl = bit32.band(flags, ImDrawFlags.RoundTopLeft) ~= 0
|
||||
local round_tr = bit32.band(flags, ImDrawFlags.RoundTopRight) ~= 0
|
||||
local round_br = bit32.band(flags, ImDrawFlags.RoundBottomRight) ~= 0
|
||||
local round_bl = bit32.band(flags, ImDrawFlags.RoundBottomLeft) ~= 0
|
||||
|
||||
if round_tl then
|
||||
AppendQuadUV(self,
|
||||
p_min_x, p_min_y, uv_l, uv_t,
|
||||
p_min_x + r, p_min_y, uv_r, uv_t,
|
||||
p_min_x + r, p_min_y + r, uv_r, uv_b,
|
||||
p_min_x, p_min_y + r, uv_l, uv_b, col)
|
||||
end
|
||||
|
||||
if round_tr then
|
||||
AppendQuadUV(self,
|
||||
p_max_x - r, p_min_y, uv_r, uv_t,
|
||||
p_max_x, p_min_y, uv_l, uv_t,
|
||||
p_max_x, p_min_y + r, uv_l, uv_b,
|
||||
p_max_x - r, p_min_y + r, uv_r, uv_b, col)
|
||||
end
|
||||
|
||||
if round_br then
|
||||
AppendQuadUV(self,
|
||||
p_max_x - r, p_max_y - r, uv_r, uv_b,
|
||||
p_max_x, p_max_y - r, uv_l, uv_b,
|
||||
p_max_x, p_max_y, uv_l, uv_t,
|
||||
p_max_x - r, p_max_y, uv_r, uv_t, col)
|
||||
end
|
||||
|
||||
if round_bl then
|
||||
AppendQuadUV(self,
|
||||
p_min_x, p_max_y - r, uv_l, uv_b,
|
||||
p_min_x + r, p_max_y - r, uv_r, uv_b,
|
||||
p_min_x + r, p_max_y, uv_r, uv_t,
|
||||
p_min_x, p_max_y, uv_l, uv_t, col)
|
||||
end
|
||||
|
||||
local r_tl = round_tl and r or 0
|
||||
local r_tr = round_tr and r or 0
|
||||
local r_br = round_br and r or 0
|
||||
local r_bl = round_bl and r or 0
|
||||
local opaque_uv = self._Data.TexUvWhitePixel
|
||||
local ou, ov = opaque_uv.x, opaque_uv.y
|
||||
|
||||
do
|
||||
-- Top
|
||||
local x0 = p_min_x + r_tl
|
||||
local x1 = p_max_x - r_tr
|
||||
AppendQuadUV(self, x0, p_min_y, ou, ov, x1, p_min_y, ou, ov, x1, p_min_y + t, ou, ov, x0, p_min_y + t, ou, ov, col)
|
||||
end
|
||||
do
|
||||
-- Left
|
||||
local y0 = p_min_y + ImMax(r_tl, t)
|
||||
local y1 = p_max_y - ImMax(r_bl, t)
|
||||
AppendQuadUV(self, p_min_x, y0, ou, ov, p_min_x + t, y0, ou, ov, p_min_x + t, y1, ou, ov, p_min_x, y1, ou, ov, col)
|
||||
end
|
||||
do
|
||||
-- Right
|
||||
local y0 = p_min_y + ImMax(r_tr, t)
|
||||
local y1 = p_max_y - ImMax(r_br, t)
|
||||
AppendQuadUV(self, p_max_x - t, y0, ou, ov, p_max_x, y0, ou, ov, p_max_x, y1, ou, ov, p_max_x - t, y1, ou, ov, col)
|
||||
end
|
||||
do
|
||||
-- Bottom
|
||||
local x0 = p_min_x + r_bl
|
||||
local x1 = p_max_x - r_br
|
||||
AppendQuadUV(self, x0, p_max_y - t, ou, ov, x1, p_max_y - t, ou, ov, x1, p_max_y, ou, ov, x0, p_max_y, ou, ov, col)
|
||||
end
|
||||
|
||||
local idx_used = self._IdxWritePtr - start_idx_ptr
|
||||
local vtx_used = self._VtxWritePtr - start_vtx_ptr
|
||||
IM_ASSERT_PARANOID(idx_used <= idx_allocated and vtx_used <= vtx_allocated)
|
||||
if idx_used < idx_allocated or vtx_used < vtx_allocated then
|
||||
self:PrimUnreserve(idx_allocated - idx_used, vtx_allocated - vtx_used)
|
||||
end
|
||||
end
|
||||
|
||||
--- @param p_min ImVec2
|
||||
--- @param p_max ImVec2
|
||||
--- @param col ImU32
|
||||
--- @param r float
|
||||
--- @param t float
|
||||
--- @param tex_uvs ImVec4
|
||||
--- @param flags ImDrawFlags
|
||||
function MT.ImDrawList:_AddRectBaked(p_min, p_max, col, r, t, tex_uvs, flags)
|
||||
_AddRectBakedXY(self, p_min.x, p_min.y, p_max.x, p_max.y, col, r, t, tex_uvs, flags)
|
||||
end
|
||||
|
||||
local corner_offset_x = { 1, -1, -1, 1 } -- static const ImVec2 corner_offset[4] = { {1,1}, {-1,1}, {-1,-1}, {1,-1} };
|
||||
local corner_offset_y = { 1, 1, -1, -1 }
|
||||
@@ -5585,7 +5874,18 @@ function MT.ImDrawList:AddRect(p_min, p_max, col, rounding, thickness, flags)
|
||||
return
|
||||
end
|
||||
-- Textured corners are baked with AA, do not use them if no-AA is requested.
|
||||
-- [Port] TODO baked round corners: allow_tex_corners -> _AddRectBaked(), falls back to the geometry path below.
|
||||
local allow_tex_corners_mask = bit32.bor(ImDrawFlags.AALines, ImDrawFlags.UseTexForRoundCorners, ImDrawFlags.AllowTexForRoundCorners_)
|
||||
local allow_tex_corners = bit32.band(flags, allow_tex_corners_mask) == allow_tex_corners_mask
|
||||
if allow_tex_corners and s_thickness < IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX and s_rounding <= IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX then
|
||||
-- Pixel aligned rect with round corners rendered using baked textures.
|
||||
IM_ASSERT_PARANOID(s_thickness > 0 and s_rounding > 0)
|
||||
local size = ImMax(s_rounding, s_thickness) -- This is matching the baking calculations.
|
||||
local idx = (s_thickness * IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX) + s_rounding - 1
|
||||
-- IM_ASSERT_PARANOID((_Data->Font->OwnerAtlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners) == 0) -- [Luau] not evaluated (arguments are not compiled out)
|
||||
IM_ASSERT_PARANOID(idx >= 0 and idx < IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX * IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX)
|
||||
_AddRectBakedXY(self, outer_min_x, outer_min_y, outer_max_x, outer_max_y, col, size * fringe_scale, thickness, self._Data.TexUvCorners[idx], flags)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if not has_rounding or bit32.band(flags, ImDrawFlags.RoundMask_) == ImDrawFlags.RoundNone then
|
||||
@@ -5619,7 +5919,67 @@ function MT.ImDrawList:AddRect(p_min, p_max, col, rounding, thickness, flags)
|
||||
end
|
||||
end
|
||||
|
||||
-- [Port] TODO baked round corners: _AddRectFilledBaked() (UseTexForRoundCorners) not ported yet, AddRectFilled() falls back to the geometry path.
|
||||
-- [Luau] _AddRectFilledBaked() taking p_min/p_max as scalars
|
||||
@native
|
||||
local function _AddRectFilledBakedXY(self, p_min_x, p_min_y, p_max_x, p_max_y, col, r, tex_uvs, flags)
|
||||
-- 9-slice with corner mirroring
|
||||
local uv_l, uv_t, uv_r, uv_b = tex_uvs.x, tex_uvs.y, tex_uvs.z, tex_uvs.w -- uv_tl = (l,t), uv_tr = (r,t), uv_br = (r,b), uv_bl = (l,b)
|
||||
|
||||
PrimReserve(self, 9 * 2 * 3, 4 * 4)
|
||||
|
||||
local r_tl = (bit32.band(flags, ImDrawFlags.RoundTopLeft) ~= 0) and r or 0.0
|
||||
local r_tr = (bit32.band(flags, ImDrawFlags.RoundTopRight) ~= 0) and r or 0.0
|
||||
local r_br = (bit32.band(flags, ImDrawFlags.RoundBottomRight) ~= 0) and r or 0.0
|
||||
local r_bl = (bit32.band(flags, ImDrawFlags.RoundBottomLeft) ~= 0) and r or 0.0
|
||||
|
||||
local vb = self.VtxBuffer.Buf
|
||||
local ib = self.IdxBuffer.Data
|
||||
local vw = self._VtxWritePtr
|
||||
local iw = self._IdxWritePtr
|
||||
local idx = self._VtxCurrentIdx
|
||||
WV(vb, vw + 0, p_min_x, p_min_y, uv_l, uv_t, col)
|
||||
WV(vb, vw + 1, p_min_x + r_tl, p_min_y, uv_r, uv_t, col)
|
||||
WV(vb, vw + 2, p_max_x - r_tr, p_min_y, uv_r, uv_t, col)
|
||||
WV(vb, vw + 3, p_max_x, p_min_y, uv_l, uv_t, col)
|
||||
|
||||
WV(vb, vw + 4, p_min_x, p_min_y + r_tl, uv_l, uv_b, col)
|
||||
WV(vb, vw + 5, p_min_x + r_tl, p_min_y + r_tl, uv_r, uv_b, col)
|
||||
WV(vb, vw + 6, p_max_x - r_tr, p_min_y + r_tr, uv_r, uv_b, col)
|
||||
WV(vb, vw + 7, p_max_x, p_min_y + r_tr, uv_l, uv_b, col)
|
||||
|
||||
WV(vb, vw + 8, p_min_x, p_max_y - r_bl, uv_l, uv_b, col)
|
||||
WV(vb, vw + 9, p_min_x + r_bl, p_max_y - r_bl, uv_r, uv_b, col)
|
||||
WV(vb, vw + 10, p_max_x - r_br, p_max_y - r_br, uv_r, uv_b, col)
|
||||
WV(vb, vw + 11, p_max_x, p_max_y - r_br, uv_l, uv_b, col)
|
||||
|
||||
WV(vb, vw + 12, p_min_x, p_max_y, uv_l, uv_t, col)
|
||||
WV(vb, vw + 13, p_min_x + r_bl, p_max_y, uv_r, uv_t, col)
|
||||
WV(vb, vw + 14, p_max_x - r_br, p_max_y, uv_r, uv_t, col)
|
||||
WV(vb, vw + 15, p_max_x, p_max_y, uv_l, uv_t, col)
|
||||
|
||||
for _ = 0, 2 do
|
||||
for _ = 0, 2 do
|
||||
ib[iw + 0] = idx + 4; ib[iw + 1] = idx + 0; ib[iw + 2] = idx + 1
|
||||
ib[iw + 3] = idx + 4; ib[iw + 4] = idx + 1; ib[iw + 5] = idx + 5
|
||||
iw = iw + 6
|
||||
idx = idx + 1
|
||||
end
|
||||
idx = idx + 1
|
||||
end
|
||||
self._VtxWritePtr = vw + 16
|
||||
self._IdxWritePtr = iw
|
||||
self._VtxCurrentIdx = self._VtxCurrentIdx + 16
|
||||
end
|
||||
|
||||
--- @param p_min ImVec2
|
||||
--- @param p_max ImVec2
|
||||
--- @param col ImU32
|
||||
--- @param r float
|
||||
--- @param tex_uvs ImVec4
|
||||
--- @param flags ImDrawFlags
|
||||
function MT.ImDrawList:_AddRectFilledBaked(p_min, p_max, col, r, tex_uvs, flags)
|
||||
_AddRectFilledBakedXY(self, p_min.x, p_min.y, p_max.x, p_max.y, col, r, tex_uvs, flags)
|
||||
end
|
||||
|
||||
--- @param p_min ImVec2
|
||||
--- @param p_max ImVec2
|
||||
@@ -5696,7 +6056,20 @@ function MT.ImDrawList:AddRectFilled(p_min, p_max, col, rounding, flags)
|
||||
return
|
||||
end
|
||||
-- Textured corners are baked with AA, do not use them if no-AA is requested.
|
||||
-- [Port] TODO baked round corners: allow_tex_corners -> _AddRectFilledBaked(), falls back to the geometry path below.
|
||||
local allow_tex_corners_mask = bit32.bor(ImDrawFlags.AAFill, ImDrawFlags.UseTexForRoundCorners, ImDrawFlags.AllowTexForRoundCorners_)
|
||||
local allow_tex_corners = bit32.band(flags, allow_tex_corners_mask) == allow_tex_corners_mask
|
||||
if allow_tex_corners and s_rounding <= IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX then
|
||||
-- IM_ASSERT_PARANOID((_Data->Font->OwnerAtlas->Flags & ImFontAtlasFlags_NoBakedRoundCorners) == 0) -- [Luau] not evaluated (arguments are not compiled out)
|
||||
-- This is matching the baking calculations. The rounding clamping above makes sure that there's enough space for the extra pixel.
|
||||
local corner_size = s_rounding + 1
|
||||
-- Check that the baked corners do not overlap (this could be made more accurate if tested for x and y separately).
|
||||
if corner_size * 2.0 * fringe_scale < min_dim then
|
||||
local idx = (s_rounding - 1)
|
||||
IM_ASSERT_PARANOID(idx >= 0 and idx < IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX)
|
||||
_AddRectFilledBakedXY(self, ax, ay, bx, by, col, corner_size * fringe_scale, self._Data.TexUvCorners[idx], flags)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not has_rounding then
|
||||
|
||||
Reference in New Issue
Block a user