Port ImTriangulator + upstream AddConcavePolyFilled (AA fringe, no per-triangle seams); [Luau] handles CCW winding and duplicate/collinear points that upstream mis-triangulates

This commit is contained in:
4DBug
2026-10-15 07:43:21 -05:00
parent 93a3c4faf5
commit f2c694bac5
7 changed files with 1164 additions and 242 deletions
+1 -1
View File
@@ -1 +1 @@
[[46, "imgui.lua"], [21466, "imgui_demo.lua"], [33318, "imgui_draw.lua"], [40827, "imgui_h.lua"], [43733, "imgui_impl_roblox.lua"], [45381, "imgui_impl_roblox_fonts.lua"], [51784, "imgui_internal.lua"], [55494, "imgui_tables.lua"], [60553, "imgui_widgets.lua"], [72529, "imstb_rectpack.lua"], [73193, "imstb_textedit.lua"], [74735, "imstb_truetype.lua"], [77523, "imstd_minstdio.lua"]]
[[46, "imgui.lua"], [21466, "imgui_demo.lua"], [33318, "imgui_draw.lua"], [41121, "imgui_h.lua"], [44027, "imgui_impl_roblox.lua"], [45675, "imgui_impl_roblox_fonts.lua"], [52078, "imgui_internal.lua"], [55800, "imgui_tables.lua"], [60859, "imgui_widgets.lua"], [72835, "imstb_rectpack.lua"], [73499, "imstb_textedit.lua"], [75041, "imstb_truetype.lua"], [77829, "imstd_minstdio.lua"]]
+344 -36
View File
@@ -1,7 +1,7 @@
--!optimize 2
-- GENERATED by tools/bundle.py from *.lua, backends/, fonts/ - do not edit
local ImGui, ImVec2, ImVec4, ImRect, HelpMarker, ImVec2_Copy, IMGUI_DEMO_MARKER, ImGuiTableFlags, ImStd, ImVector, ImDrawFlags, ImGuiInputFlags, ImRect_Copy, ImGuiDataType, ImStb, IM_TRUNC, ImGuiKey, ImVec2_CopyV, ImGuiStyleVarInfo, IM_ASSERT_USER_ERROR, ImGuiHoveredFlags, ImFormatString, IM_ASSERT_USER_ERROR_RET, ImHashStr, ImS32, ImGuiColorEditFlags, ImIsPowerOfTwo, ImAbs, ImVec4_Copy, ExampleAppConsoleMT, IM_ROUND, ImGuiTableColumnFlags, ImGuiTreeNodeFlags, PopStyleCompact, PushStyleCompact, IM_ASSERT_PARANOID, ImU16, ExampleNames, ImGuiWindowFlags, ImGuiItemFlags, ImGui_ImplRoblox_GetBackendData, stbte, ImColor, ImCos, ImGuiButtonFlags, ImGuiDebugLogFlags, ImGuiLocKey, ImU32, ExampleTreeFuncs, ImGuiListClipper, ImS16, _PathArcToFastExXY, ImGuiMultiSelectFlags, ImSin, ImGuiTabBarFlags, ImUpperPowerOfTwo, IM_F32_TO_INT8_SAT, ImFontAtlasPackGetRect, DockSettingsRenameNodeReferences, ExampleDualListBoxMT, IM_DRAWLIST_TEX_LINES_WIDTH_MAX, ImCeil, ImGuiCol, ImGuiSelectionBasicStorage, ImLengthSqr, ImS8, ImU8, ExampleAppPropertyEditorMT, ImFabs, ImGuiChildFlags, ImGuiLastItemData_Copy, ImGuiScrollFlags, ImLog, ImMemchr, ImStrByte, ExampleSelectionWithDeletionMT, IMGUI_DEBUG_LOG_VIEWPORT, ImGuiInputEvent, ImGuiTextBuffer, ImPow, ImTrunc64, CustomConstraints, ExampleAppLogMT, IMGUI_DEBUG_LOG_FONT, IMGUI_DEBUG_LOG_SELECTION, ImAddClampOverflow, ImFontAtlasBuildInit, ImFontCalcWordWrapPositionEx, ImGuiComboFlags, ImGuiLastItemData, ImGuiPayload_IsDataType, ImGuiPopupFlags, ImGuiSliderFlags, ImGuiTextFilter, ImRotate, ImSqrt, ImSubClampOverflow, ImTextClassifierSetCharClass, MyDocument, ShowExampleMenuFile, CalcCornerArcStepAndCount, CalcNextScrollFromScrollTargetAndClamp, IMGUI_PAYLOAD_TYPE_WINDOW, IMGUI_VERSION, ImCharIsBlankW, ImCharIsSeparatorW, ImFmod, ImFontAtlasBakedAddFontGlyph, ImFontAtlasPackAddRect, ImFontBaked_BuildLoadGlyph, ImGuiInputTextFlags, ImGuiNavMoveFlags, ImGuiStyle_Copy, ImHashData, ImVec1_Copy, ExampleAsset_s_current_sort_specs, ExampleMemberInfo, ExampleTree_CreateNode, IMGUI_PAYLOAD_TYPE_COLOR_4F, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC, IM_F32_TO_INT8_UNBOUND, IM_PI, ImCharIsBlankA, ImFontAtlasBuildRenderBitmapFromString, ImFontAtlasFontDestroyOutput, ImFontAtlasFontDiscardBakes, ImFontAtlasFontSourceAddToFont, ImFontAtlasFontSourceInit, ImFontAtlasRectId_GetIndex, ImFontAtlasTextureAdd, ImFontAtlasTextureBlockQueueUpload, ImFontAtlasTextureGrow, ImFontBaked_BuildGrowIndex, ImFontConfig, ImFontGlyph, ImGuiTableColumn, ImGuiWindowClass, ImGui_ImplRoblox_RenderDrawData, ImParseFormatFindStart, ImRect_CopyFromV4, ImTextureRect, ImTextureRef, MyItem_s_current_sort_specs, stb_textedit_key, stbtt_GetGlyphBitmapBoxSubpixel, DockSettingsHandler_ClearAll, EditTableSizingFlags, ExampleSelectionWithDeletion, IMGUI_DEBUG_LOG_TABLE, IMGUI_PAYLOAD_TYPE_COLOR_3F, IM_FREE, ImDrawListSplitter, ImFontAtlasBakedDiscard, ImFontAtlasBuildDestroy, ImFontAtlasBuildNotifySetFont, ImFontAtlasBuildSetTexture, ImFontAtlasBuildSetupFontBakedFallback, ImFontAtlasFontDestroySourceData, ImFontAtlasPackInit, ImFontAtlasRect
local ImGui, ImVec2, ImVec4, ImRect, HelpMarker, ImVec2_Copy, IMGUI_DEMO_MARKER, ImGuiTableFlags, ImStd, ImVector, ImDrawFlags, ImGuiInputFlags, ImRect_Copy, ImGuiDataType, ImStb, IM_TRUNC, ImGuiKey, ImVec2_CopyV, ImGuiStyleVarInfo, IM_ASSERT_USER_ERROR, ImGuiHoveredFlags, ImFormatString, IM_ASSERT_USER_ERROR_RET, ImHashStr, ImS32, ImGuiColorEditFlags, ImIsPowerOfTwo, ImAbs, ImVec4_Copy, ExampleAppConsoleMT, IM_ROUND, ImGuiTableColumnFlags, ImGuiTreeNodeFlags, PopStyleCompact, PushStyleCompact, IM_ASSERT_PARANOID, ImU16, ExampleNames, ImGuiWindowFlags, ImGuiItemFlags, ImGui_ImplRoblox_GetBackendData, stbte, ImColor, ImCos, ImGuiButtonFlags, ImGuiDebugLogFlags, ImGuiLocKey, ImU32, ExampleTreeFuncs, ImGuiListClipper, ImS16, _PathArcToFastExXY, ImGuiMultiSelectFlags, ImSin, ImGuiTabBarFlags, ImUpperPowerOfTwo, IM_F32_TO_INT8_SAT, ImFontAtlasPackGetRect, DockSettingsRenameNodeReferences, ExampleDualListBoxMT, IM_DRAWLIST_TEX_LINES_WIDTH_MAX, ImCeil, ImFabs, ImGuiCol, ImGuiSelectionBasicStorage, ImLengthSqr, ImS8, ImU8, ExampleAppPropertyEditorMT, ImGuiChildFlags, ImGuiLastItemData_Copy, ImGuiScrollFlags, ImLog, ImMemchr, ImStrByte, ExampleSelectionWithDeletionMT, IMGUI_DEBUG_LOG_VIEWPORT, ImGuiInputEvent, ImGuiTextBuffer, ImPow, ImTrunc64, CustomConstraints, ExampleAppLogMT, IMGUI_DEBUG_LOG_FONT, IMGUI_DEBUG_LOG_SELECTION, ImAddClampOverflow, ImFontAtlasBuildInit, ImFontCalcWordWrapPositionEx, ImGuiComboFlags, ImGuiLastItemData, ImGuiPayload_IsDataType, ImGuiPopupFlags, ImGuiSliderFlags, ImGuiTextFilter, ImRotate, ImSqrt, ImSubClampOverflow, ImTextClassifierSetCharClass, MyDocument, ShowExampleMenuFile, CalcCornerArcStepAndCount, CalcNextScrollFromScrollTargetAndClamp, IMGUI_PAYLOAD_TYPE_WINDOW, IMGUI_VERSION, ImCharIsBlankW, ImCharIsSeparatorW, ImFmod, ImFontAtlasBakedAddFontGlyph, ImFontAtlasPackAddRect, ImFontBaked_BuildLoadGlyph, ImGuiInputTextFlags, ImGuiNavMoveFlags, ImGuiStyle_Copy, ImHashData, ImVec1_Copy, ExampleAsset_s_current_sort_specs, ExampleMemberInfo, ExampleTree_CreateNode, IMGUI_PAYLOAD_TYPE_COLOR_4F, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC, IM_F32_TO_INT8_UNBOUND, IM_PI, ImCharIsBlankA, ImFontAtlasBuildRenderBitmapFromString, ImFontAtlasFontDestroyOutput, ImFontAtlasFontDiscardBakes, ImFontAtlasFontSourceAddToFont, ImFontAtlasFontSourceInit, ImFontAtlasRectId_GetIndex, ImFontAtlasTextureAdd, ImFontAtlasTextureBlockQueueUpload, ImFontAtlasTextureGrow, ImFontBaked_BuildGrowIndex, ImFontConfig, ImFontGlyph, ImGuiTableColumn, ImGuiWindowClass, ImGui_ImplRoblox_RenderDrawData, ImParseFormatFindStart, ImRect_CopyFromV4, ImTextureRect, ImTextureRef, MyItem_s_current_sort_specs, stb_textedit_key, stbtt_GetGlyphBitmapBoxSubpixel, DockSettingsHandler_ClearAll, EditTableSizingFlags, ExampleSelectionWithDeletion, IMGUI_DEBUG_LOG_TABLE, IMGUI_PAYLOAD_TYPE_COLOR_3F, IM_FREE, ImDrawListSplitter, ImFontAtlasBakedDiscard, ImFontAtlasBuildDestroy, ImFontAtlasBuildNotifySetFont, ImFontAtlasBuildSetTexture, ImFontAtlasBuildSetupFontBakedFallback, ImFontAtlasFontDestroySourceData, ImFontAtlasPackInit, ImFontAtlasRect
local type, mathMin, mathMax, mathFloor, mathCeil, bitOr, bitLShift = type, math.min, math.max, math.floor, math.ceil, bit32.bor, bit32.lshift
local function IM_COL32(R, G, B, A) return (bitOr(bitLShift(A, 24 --[[IM_COL32_A_SHIFT]]), bitLShift(B, 16 --[[IM_COL32_B_SHIFT]]), bitLShift(G, 8 --[[IM_COL32_G_SHIFT]]), bitLShift(R, 0 --[[IM_COL32_R_SHIFT]]))) end
@native
@@ -40772,47 +40772,341 @@ function MT.ImDrawList:PathBezierQuadraticCurveTo(p2, p3, num_segments)
end
end
-- ponytail: ear-clipping, no anti-aliased fringe (upstream's AA triangulator not ported). O(n^2) is fine for UI polygons.
--------------------------------------------------------------------------------
-- [SECTION] ImTriangulator, ImDrawList concave polygon fill
--------------------------------------------------------------------------------
-- Triangulate concave polygons. Based on "Triangulation by Ear Clipping" paper, O(N^2) complexity.
-- Reference: https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
-- Provided as a convenience for user but not used by main library.
--------------------------------------------------------------------------------
-- - ImTriangulator [Internal]
-- - AddConcavePolyFilled()
--------------------------------------------------------------------------------
local ImTriangulatorNodeType =
{
Convex = 0,
Ear = 1,
Reflex = 2,
}
-- [Luau] No pointers: a node is an int handle (1-based slot) into the parallel arrays of its ImTriangulator
-- (tri.Type[n], tri.Index[n], tri.Pos[n], tri.Next[n], tri.Prev[n]). node->Index (0-based, as upstream) == n - 1.
local function ImTriangulatorNode_Unlink(tri, n) tri.Prev[tri.Next[n]] = tri.Prev[n]; tri.Next[tri.Prev[n]] = tri.Next[n] end
-- [Luau] Deviation: upstream classifies a node as reflex when '!ImTriangleIsClockwise()', i.e. also when its corner is
-- degenerate (collinear or duplicate points). A duplicate point then sits as a reflex on top of every candidate ear's vertex
-- and blocks it, ending in the degenerate fallback with overlapping triangles. Only strictly counter-clockwise corners are
-- reflex here: degenerate corners are clipped as zero-area ears.
local function ImTriangulator_IsReflex(a, b, c) return ((b.x - a.x) * (c.y - b.y)) - ((c.x - b.x) * (b.y - a.y)) < 0.0 end
local function ImTriangulatorNodeSpan()
return { Data = {}, Size = 0 } -- Data: node handles, 1-based
end
MT.ImTriangulatorNodeSpan = {}
MT.ImTriangulatorNodeSpan.__index = MT.ImTriangulatorNodeSpan
function MT.ImTriangulatorNodeSpan:push_back(node) self.Size = self.Size + 1; self.Data[self.Size] = node end
function MT.ImTriangulatorNodeSpan:find_erase_unsorted(idx) for i = self.Size, 1, -1 do if self.Data[i] - 1 == idx then self.Data[i] = self.Data[self.Size]; self.Size = self.Size - 1; return end end end
-- [Luau] The node/ears/reflexes storage (upstream: carved out of _Data->TempBuffer via scratch_buffer) is owned by the
-- triangulator itself and only ever grows. AddConcavePolyFilled() reuses a single module-level instance (no per-call allocations).
local function ImTriangulator()
return setmetatable({
_TrianglesLeft = 0,
_Nodes = 0, -- node handle (head of the circular list)
_Ears = setmetatable(ImTriangulatorNodeSpan(), MT.ImTriangulatorNodeSpan),
_Reflexes = setmetatable(ImTriangulatorNodeSpan(), MT.ImTriangulatorNodeSpan),
Type = {}, Index = {}, Pos = {}, Next = {}, Prev = {}, -- [Luau] ImTriangulatorNode fields, one array each
}, MT.ImTriangulator)
end
MT.ImTriangulator = {}
MT.ImTriangulator.__index = MT.ImTriangulator
function MT.ImTriangulator.EstimateTriangleCount(points_count) return (points_count < 3) and 0 or points_count - 2 end
-- [Luau] In elements (nodes + ears + reflexes) rather than bytes. Unused by the port: arrays grow on demand.
function MT.ImTriangulator.EstimateScratchBufferSize(points_count) return points_count + points_count * 2 end
-- Distribute storage for nodes, ears and reflexes.
-- FIXME-OPT: if everything is convex, we could report it to caller and let it switch to an convex renderer
-- (this would require first building reflexes to bail to convex if empty, without even building nodes)
--- @param points ImVec2[] # 1-based
function MT.ImDrawList:AddConcavePolyFilled(points, points_count, col)
if points_count < 3 or bit32.band(col, 4278190080 --[[IM_COL32_A_MASK]]) == 0 then return end
local idx = {}
local area = 0.0
function MT.ImTriangulator:Init(points, points_count)
assert(points_count >= 3)
self._TrianglesLeft = MT.ImTriangulator.EstimateTriangleCount(points_count)
self._Nodes = 1
self._Ears.Size = 0
self._Reflexes.Size = 0
self:BuildNodes(points, points_count)
-- [Luau] Deviation: upstream only flips the node list when no ear is found, so a counter-clockwise *concave* polygon
-- (whose reflex corners look like ears) yields triangles outside of it. Normalize to clockwise order up-front (O(N)).
local area2 = 0.0
local p0 = points[points_count]
for i = 1, points_count do
idx[i] = i
local a, b = points[i], points[i % points_count + 1]
area = area + (a.x * b.y - b.x * a.y)
local p1 = points[i]
area2 = area2 + (p0.x * p1.y - p1.x * p0.y)
p0 = p1
end
local sign = (area >= 0) and 1 or -1
local function cross(o, a, b) return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x) end
local guard = 0
while #idx > 3 and guard < points_count * points_count do
guard = guard + 1
local n = #idx
local clipped = false
for i = 1, n do
local ia, ib, ic = idx[(i - 2) % n + 1], idx[i], idx[i % n + 1]
local a, b, c = points[ia], points[ib], points[ic]
if cross(a, b, c) * sign > 0 then
local inside = false
for j = 1, n do
local p = idx[j]
if p ~= ia and p ~= ib and p ~= ic then
local q = points[p]
if cross(a, b, q) * sign >= 0 and cross(b, c, q) * sign >= 0 and cross(c, a, q) * sign >= 0 then inside = true; break end
end
end
if not inside then
self:AddTriangleFilled(a, b, c, col)
table.remove(idx, i)
clipped = true
break
end
if area2 < 0.0 then
self:FlipNodeList()
end
self:BuildReflexes()
self:BuildEars()
end
function MT.ImTriangulator:BuildNodes(points, points_count)
local Type, Index, Pos, Next, Prev = self.Type, self.Index, self.Pos, self.Next, self.Prev
for i = 1, points_count do
Type[i] = ImTriangulatorNodeType.Convex
Index[i] = i - 1
Pos[i] = points[i] -- [Luau] reference, not a copy (points are not modified while triangulating)
Next[i] = i + 1
Prev[i] = i - 1
end
Prev[1] = points_count
Next[points_count] = 1
end
function MT.ImTriangulator:BuildReflexes()
local Pos, Next, Prev = self.Pos, self.Next, self.Prev
local n1 = self._Nodes
for _ = self._TrianglesLeft, 0, -1 do
if ImTriangulator_IsReflex(Pos[Prev[n1]], Pos[n1], Pos[Next[n1]]) then
self.Type[n1] = ImTriangulatorNodeType.Reflex
self._Reflexes:push_back(n1)
end
n1 = Next[n1]
end
end
function MT.ImTriangulator:BuildEars()
local Index, Pos, Next, Prev = self.Index, self.Pos, self.Next, self.Prev
local n1 = self._Nodes
for _ = self._TrianglesLeft, 0, -1 do
if self.Type[n1] == ImTriangulatorNodeType.Convex then
local n0, n2 = Prev[n1], Next[n1]
if self:IsEar(Index[n0], Index[n1], Index[n2], Pos[n0], Pos[n1], Pos[n2]) then
self.Type[n1] = ImTriangulatorNodeType.Ear
self._Ears:push_back(n1)
end
end
if not clipped then break end
n1 = Next[n1]
end
end
-- [Luau] out_triangle[3] is returned as 3 values (relative 0-based indexes)
function MT.ImTriangulator:GetNextTriangle()
if self._Ears.Size == 0 then
self:FlipNodeList()
local node = self._Nodes
for _ = self._TrianglesLeft, 0, -1 do
self.Type[node] = ImTriangulatorNodeType.Convex
node = self.Next[node]
end
self._Reflexes.Size = 0
self:BuildReflexes()
self:BuildEars()
-- If we still don't have ears, it means geometry is degenerated.
if self._Ears.Size == 0 then
-- Return first triangle available, mimicking the behavior of convex fill.
assert(self._TrianglesLeft > 0) -- Geometry is degenerated
self._Ears.Data[1] = self._Nodes
self._Ears.Size = 1
end
end
local ear = self._Ears.Data[self._Ears.Size]
self._Ears.Size = self._Ears.Size - 1
local Index, Next, Prev = self.Index, self.Next, self.Prev
local t0, t1, t2 = Index[Prev[ear]], Index[ear], Index[Next[ear]]
ImTriangulatorNode_Unlink(self, ear)
if ear == self._Nodes then
self._Nodes = Next[ear]
end
self:ReclassifyNode(Prev[ear])
self:ReclassifyNode(Next[ear])
self._TrianglesLeft = self._TrianglesLeft - 1
return t0, t1, t2
end
function MT.ImTriangulator:FlipNodeList()
local Next, Prev = self.Next, self.Prev
local nodes = self._Nodes
local prev = nodes
local temp = nodes
local current = Next[nodes]
Next[prev] = prev
Prev[prev] = prev
while current ~= nodes do
temp = Next[current]
Next[current] = prev
Prev[prev] = current
Next[nodes] = current
Prev[current] = nodes
prev = current
current = temp
end
self._Nodes = prev
end
-- A triangle is an ear is no other vertex is inside it. We can test reflexes vertices only (see reference algorithm)
function MT.ImTriangulator:IsEar(i0, i1, i2, v0, v1, v2)
local Index, Pos = self.Index, self.Pos
local data = self._Reflexes.Data
for p = 1, self._Reflexes.Size do
local reflex = data[p]
local idx = Index[reflex]
if idx ~= i0 and idx ~= i1 and idx ~= i2 then
if ImStd.ImTriangleContainsPoint(v0, v1, v2, Pos[reflex]) then
return false
end
end
end
return true
end
function MT.ImTriangulator:ReclassifyNode(n1)
-- Classify node
local type
local n0 = self.Prev[n1]
local n2 = self.Next[n1]
local Index, Pos = self.Index, self.Pos
if ImTriangulator_IsReflex(Pos[n0], Pos[n1], Pos[n2]) then
type = ImTriangulatorNodeType.Reflex
elseif self:IsEar(Index[n0], Index[n1], Index[n2], Pos[n0], Pos[n1], Pos[n2]) then
type = ImTriangulatorNodeType.Ear
else
type = ImTriangulatorNodeType.Convex
end
-- Update lists when a type changes
local n1_type = self.Type[n1]
if type == n1_type then
return
end
if n1_type == ImTriangulatorNodeType.Reflex then
self._Reflexes:find_erase_unsorted(Index[n1])
elseif n1_type == ImTriangulatorNodeType.Ear then
self._Ears:find_erase_unsorted(Index[n1])
end
if type == ImTriangulatorNodeType.Reflex then
self._Reflexes:push_back(n1)
elseif type == ImTriangulatorNodeType.Ear then
self._Ears:push_back(n1)
end
self.Type[n1] = type
end
local concave_triangulator = ImTriangulator() -- [Luau] reused scratch (see ImTriangulator())
-- Use ear-clipping algorithm to triangulate a simple polygon (no self-interaction, no holes).
-- (Reminder: we don't perform any coarse clipping/culling in ImDrawList layer!
-- It is up to caller to ensure not making costly calls that will be outside of visible area.
-- As concave fill is noticeably more expensive than other primitives, be mindful of this...
-- Caller can build AABB of points, and avoid filling if 'draw_list->_CmdHeader.ClipRect.Overlays(points_bb) == false')
--- @param points ImVec2[] # 1-based
--- @param points_count int
--- @param col ImU32
@native
function MT.ImDrawList:AddConcavePolyFilled(points, points_count, col)
if points_count < 3 or bit32.band(col, 4278190080 --[[IM_COL32_A_MASK]]) == 0 then
return
end
local uv = self._Data.TexUvWhitePixel
local uv_x, uv_y = uv.x, uv.y
local triangulator = concave_triangulator
if bit32.band(self.Flags, 4096 --[[ImDrawFlags.AAFill]]) ~= 0 then
-- Anti-aliased Fill
local AA_SIZE = self._FringeScale
local col_trans = bit32.band(col, bit32.bnot(4278190080 --[[IM_COL32_A_MASK]]))
local idx_count = (points_count - 2) * 3 + points_count * 6
local vtx_count = (points_count * 2)
PrimReserve(self, idx_count, vtx_count)
local vb = self.VtxBuffer.Buf
local ib = self.IdxBuffer.Data
local vw = self._VtxWritePtr
local iw = self._IdxWritePtr
-- Add indexes for fill
local vtx_inner_idx = self._VtxCurrentIdx
local vtx_outer_idx = self._VtxCurrentIdx + 1
triangulator:Init(points, points_count)
while triangulator._TrianglesLeft > 0 do
local t0, t1, t2 = triangulator:GetNextTriangle()
ib[iw + 0] = vtx_inner_idx + t0 * 2; ib[iw + 1] = vtx_inner_idx + t1 * 2; ib[iw + 2] = vtx_inner_idx + t2 * 2
iw = iw + 3
end
-- Compute normals
-- [Luau] scratch arrays (see AddPolyline) instead of _Data->TempBuffer. Indexes below are 1-based.
local temp_normals_x, temp_normals_y = poly_normals_x, poly_normals_y
local i0 = points_count
for i1 = 1, points_count do
local p0 = points[i0]
local p1 = points[i1]
local dx, dy = IM_NORMALIZE2F_OVER_ZERO(p1.x - p0.x, p1.y - p0.y)
temp_normals_x[i0] = dy
temp_normals_y[i0] = -dx
i0 = i1
end
i0 = points_count
for i1 = 1, points_count do
-- Average normals
local dm_x, dm_y = IM_FIXNORMAL2F((temp_normals_x[i0] + temp_normals_x[i1]) * 0.5, (temp_normals_y[i0] + temp_normals_y[i1]) * 0.5)
dm_x = dm_x * AA_SIZE * 0.5
dm_y = dm_y * AA_SIZE * 0.5
-- Add vertices
local p1 = points[i1]
WV(vb, vw, p1.x - dm_x, p1.y - dm_y, uv_x, uv_y, col) -- Inner
WV(vb, vw + 1, p1.x + dm_x, p1.y + dm_y, uv_x, uv_y, col_trans) -- Outer
vw = vw + 2
-- Add indexes for fringes
local e0, e1 = (i0 - 1) * 2, (i1 - 1) * 2
ib[iw + 0] = vtx_inner_idx + e1; ib[iw + 1] = vtx_inner_idx + e0; ib[iw + 2] = vtx_outer_idx + e0
ib[iw + 3] = vtx_outer_idx + e0; ib[iw + 4] = vtx_outer_idx + e1; ib[iw + 5] = vtx_inner_idx + e1
iw = iw + 6
i0 = i1
end
self._VtxWritePtr = vw
self._IdxWritePtr = iw
self._VtxCurrentIdx = self._VtxCurrentIdx + vtx_count
else
-- Non Anti-aliased Fill
local idx_count = (points_count - 2) * 3
local vtx_count = points_count
PrimReserve(self, idx_count, vtx_count)
local vb = self.VtxBuffer.Buf
local ib = self.IdxBuffer.Data
local vw = self._VtxWritePtr
local iw = self._IdxWritePtr
for i = 1, vtx_count do
local p = points[i]
WV(vb, vw, p.x, p.y, uv_x, uv_y, col)
vw = vw + 1
end
local base_idx = self._VtxCurrentIdx
triangulator:Init(points, points_count)
while triangulator._TrianglesLeft > 0 do
local t0, t1, t2 = triangulator:GetNextTriangle()
ib[iw + 0] = base_idx + t0; ib[iw + 1] = base_idx + t1; ib[iw + 2] = base_idx + t2
iw = iw + 3
end
self._VtxWritePtr = vw
self._IdxWritePtr = iw
self._VtxCurrentIdx = base_idx + vtx_count
end
if #idx == 3 then self:AddTriangleFilled(points[idx[1]], points[idx[2]], points[idx[3]], col) end
end
function MT.ImDrawList:PathFillConcave(col)
@@ -52244,6 +52538,18 @@ function ImMul(lhs, rhs)
return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y)
end
--- @param a ImVec2
--- @param b ImVec2
--- @param c ImVec2
--- @return float
function ImTriangleArea(a, b, c) return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5 end
--- @param a ImVec2
--- @param b ImVec2
--- @param c ImVec2
--- @return boolean
function ImTriangleIsClockwise(a, b, c) return ((b.x - a.x) * (c.y - b.y)) - ((c.x - b.x) * (b.y - a.y)) > 0.0 end
--- @param str char[]
--- @param begin? int
function ImStd.ImStrlen(str, begin)
@@ -78237,6 +78543,8 @@ return {
ImTextureRef = ImTextureRef,
ImTextureStatus = ImTextureStatus,
ImToUpper = ImToUpper,
ImTriangleArea = ImTriangleArea,
ImTriangleIsClockwise = ImTriangleIsClockwise,
ImTrunc = ImTrunc,
ImTrunc64 = ImTrunc64,
ImU16 = ImU16,
+1 -1
View File
@@ -1 +1 @@
[[183, "imgui.lua"], [21603, "imgui_demo.lua"], [33455, "imgui_draw.lua"], [40964, "imgui_h.lua"], [43870, "imgui_impl_love.lua"], [44410, "imgui_internal.lua"], [48120, "imgui_tables.lua"], [53179, "imgui_widgets.lua"], [65155, "imstb_rectpack.lua"], [65819, "imstb_textedit.lua"], [67361, "imstb_truetype.lua"], [70149, "imstd_minstdio.lua"]]
[[183, "imgui.lua"], [21603, "imgui_demo.lua"], [33455, "imgui_draw.lua"], [41258, "imgui_h.lua"], [44164, "imgui_impl_love.lua"], [44704, "imgui_internal.lua"], [48426, "imgui_tables.lua"], [53485, "imgui_widgets.lua"], [65461, "imstb_rectpack.lua"], [66125, "imstb_textedit.lua"], [67667, "imstb_truetype.lua"], [70455, "imstd_minstdio.lua"]]
+344 -36
View File
@@ -138,7 +138,7 @@ if not utf8 then
end
local ImGui, ImVec2, ImVec4, ImRect, HelpMarker, ImVec2_Copy, IMGUI_DEMO_MARKER, ImGuiTableFlags, ImStd, ImVector, ImGuiKey, ImDrawFlags, ImGuiInputFlags, ImRect_Copy, ImGuiDataType, ImStb, IM_TRUNC, ImVec2_CopyV, ImGuiStyleVarInfo, IM_ASSERT_USER_ERROR, ImGuiHoveredFlags, ImFormatString, IM_ASSERT_USER_ERROR_RET, ImHashStr, ImS32, ImGuiColorEditFlags, ImIsPowerOfTwo, ImAbs, ImVec4_Copy, ExampleAppConsoleMT, IM_ROUND, ImGuiTableColumnFlags, ImGuiTreeNodeFlags, PopStyleCompact, PushStyleCompact, IM_ASSERT_PARANOID, ImU16, ExampleNames, ImGuiWindowFlags, ImGuiItemFlags, stbte, ImColor, ImCos, ImGuiButtonFlags, ImGuiDebugLogFlags, ImGuiLocKey, ImU32, ExampleTreeFuncs, ImGuiListClipper, ImS16, _PathArcToFastExXY, ImGuiMultiSelectFlags, ImSin, ImGuiTabBarFlags, ImUpperPowerOfTwo, IM_F32_TO_INT8_SAT, ImFontAtlasPackGetRect, ImGuiMouseCursor, DockSettingsRenameNodeReferences, ExampleDualListBoxMT, IM_DRAWLIST_TEX_LINES_WIDTH_MAX, ImCeil, ImGuiCol, ImGuiSelectionBasicStorage, ImLengthSqr, ImS8, ImU8, ExampleAppPropertyEditorMT, ImFabs, ImGuiScrollFlags, ImGui_ImplLOVE_GetBackendData, ImLog, ExampleSelectionWithDeletionMT, CustomConstraints, ExampleAppLogMT, ImFontAtlasBuildInit, ImGuiComboFlags, ImGuiPopupFlags, ImGuiSliderFlags, ImTextClassifierSetCharClass, MyDocument, ShowExampleMenuFile, CalcCornerArcStepAndCount, ImFontAtlasBakedAddFontGlyph, ImFontAtlasPackAddRect, ImFontBaked_BuildLoadGlyph, ImGuiInputTextFlags, ImGuiStyle_Copy, ExampleAsset_s_current_sort_specs, ExampleMemberInfo, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC, ImFontAtlasBuildRenderBitmapFromString, ImFontAtlasFontDestroyOutput, ImFontAtlasFontSourceAddToFont, ImFontAtlasFontSourceInit, ImFontAtlasTextureAdd, ImFontAtlasTextureBlockQueueUpload, ImFontBaked_BuildGrowIndex, ImGuiTableColumn, stb_textedit_key, stbtt_GetGlyphBitmapBoxSubpixel, IM_FREE, ImDrawListSplitter, ImGuiDragDropFlags, ImGuiFocusedFlags, stb_text_locate_coord, stb_text_makeundo_insert, stb_text_makeundo_replace, stb_textedit_find_charpos, stbtt_GetGlyphShape, IM_ALLOC, ImGuiTableColumnSortSpecs, ImGuiTableInstanceData, ImGuiTableSettings, stb_text_makeundo_delete, stb_text_redo, stb_text_undo, stb_textedit_click, stb_textedit_drag, stbtt_FindGlyphIndex, stbtt_GetFontOffsetForIndex, stbtt_GetFontVMetrics, stbtt_GetGlyphBitmapBox, stbtt_GetGlyphHMetrics, stbtt_InitFont, stbtt_MakeGlyphBitmapSubpixelPrefilter, stbtt_ScaleForPixelHeight, stbtt__GetGlyphInfoT2, stbtt__GetGlyphShapeT2, stbtt_fontinfo, ImGuiOldColumnData, ImGuiOldColumnFlags, ImGuiOldColumns, ImGuiTable, ImGuiTableColumnSettings, ImGuiTableSortSpecs, ImGuiTableTempData, ImGui_ImplLOVE_CreateTexture, ImGui_ImplLOVE_DestroyTexture, ImGui_ImplLOVE_Init, ImGui_ImplLOVE_NewFrame, ImGui_ImplLOVE_RenderDrawData, ImGui_ImplLOVE_Shutdown, ImGui_ImplLOVE_UpdateTexture, stbrp_init_target, IMGUI_TABLE_MAX_COLUMNS, IMSTB_TEXTEDIT_UNDOSTATECOUNT, IM_COL32_DISABLE, ImGui_ImplLove, STB_TEXTEDIT_K_BACKSPACE, STB_TEXTEDIT_K_DELETE, STB_TEXTEDIT_K_DOWN, STB_TEXTEDIT_K_LEFT, STB_TEXTEDIT_K_LINEEND, STB_TEXTEDIT_K_LINESTART, STB_TEXTEDIT_K_PGDOWN, STB_TEXTEDIT_K_PGUP, STB_TEXTEDIT_K_REDO, STB_TEXTEDIT_K_RIGHT, STB_TEXTEDIT_K_SHIFT
local ImGui, ImVec2, ImVec4, ImRect, HelpMarker, ImVec2_Copy, IMGUI_DEMO_MARKER, ImGuiTableFlags, ImStd, ImVector, ImGuiKey, ImDrawFlags, ImGuiInputFlags, ImRect_Copy, ImGuiDataType, ImStb, IM_TRUNC, ImVec2_CopyV, ImGuiStyleVarInfo, IM_ASSERT_USER_ERROR, ImGuiHoveredFlags, ImFormatString, IM_ASSERT_USER_ERROR_RET, ImHashStr, ImS32, ImGuiColorEditFlags, ImIsPowerOfTwo, ImAbs, ImVec4_Copy, ExampleAppConsoleMT, IM_ROUND, ImGuiTableColumnFlags, ImGuiTreeNodeFlags, PopStyleCompact, PushStyleCompact, IM_ASSERT_PARANOID, ImU16, ExampleNames, ImGuiWindowFlags, ImGuiItemFlags, stbte, ImColor, ImCos, ImGuiButtonFlags, ImGuiDebugLogFlags, ImGuiLocKey, ImU32, ExampleTreeFuncs, ImGuiListClipper, ImS16, _PathArcToFastExXY, ImGuiMultiSelectFlags, ImSin, ImGuiTabBarFlags, ImUpperPowerOfTwo, IM_F32_TO_INT8_SAT, ImFontAtlasPackGetRect, ImGuiMouseCursor, DockSettingsRenameNodeReferences, ExampleDualListBoxMT, IM_DRAWLIST_TEX_LINES_WIDTH_MAX, ImCeil, ImFabs, ImGuiCol, ImGuiSelectionBasicStorage, ImLengthSqr, ImS8, ImU8, ExampleAppPropertyEditorMT, ImGuiScrollFlags, ImGui_ImplLOVE_GetBackendData, ImLog, ExampleSelectionWithDeletionMT, CustomConstraints, ExampleAppLogMT, ImFontAtlasBuildInit, ImGuiComboFlags, ImGuiPopupFlags, ImGuiSliderFlags, ImTextClassifierSetCharClass, MyDocument, ShowExampleMenuFile, CalcCornerArcStepAndCount, ImFontAtlasBakedAddFontGlyph, ImFontAtlasPackAddRect, ImFontBaked_BuildLoadGlyph, ImGuiInputTextFlags, ImGuiStyle_Copy, ExampleAsset_s_current_sort_specs, ExampleMemberInfo, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC, ImFontAtlasBuildRenderBitmapFromString, ImFontAtlasFontDestroyOutput, ImFontAtlasFontSourceAddToFont, ImFontAtlasFontSourceInit, ImFontAtlasTextureAdd, ImFontAtlasTextureBlockQueueUpload, ImFontBaked_BuildGrowIndex, ImGuiTableColumn, stb_textedit_key, stbtt_GetGlyphBitmapBoxSubpixel, IM_FREE, ImDrawListSplitter, ImGuiDragDropFlags, ImGuiFocusedFlags, stb_text_locate_coord, stb_text_makeundo_insert, stb_text_makeundo_replace, stb_textedit_find_charpos, stbtt_GetGlyphShape, IM_ALLOC, ImGuiTableColumnSortSpecs, ImGuiTableInstanceData, ImGuiTableSettings, stb_text_makeundo_delete, stb_text_redo, stb_text_undo, stb_textedit_click, stb_textedit_drag, stbtt_FindGlyphIndex, stbtt_GetFontOffsetForIndex, stbtt_GetFontVMetrics, stbtt_GetGlyphBitmapBox, stbtt_GetGlyphHMetrics, stbtt_InitFont, stbtt_MakeGlyphBitmapSubpixelPrefilter, stbtt_ScaleForPixelHeight, stbtt__GetGlyphInfoT2, stbtt__GetGlyphShapeT2, stbtt_fontinfo, ImGuiOldColumnData, ImGuiOldColumnFlags, ImGuiOldColumns, ImGuiTable, ImGuiTableColumnSettings, ImGuiTableSortSpecs, ImGuiTableTempData, ImGui_ImplLOVE_CreateTexture, ImGui_ImplLOVE_DestroyTexture, ImGui_ImplLOVE_Init, ImGui_ImplLOVE_NewFrame, ImGui_ImplLOVE_RenderDrawData, ImGui_ImplLOVE_Shutdown, ImGui_ImplLOVE_UpdateTexture, stbrp_init_target, IMGUI_TABLE_MAX_COLUMNS, IMSTB_TEXTEDIT_UNDOSTATECOUNT, IM_COL32_DISABLE, ImGui_ImplLove, STB_TEXTEDIT_K_BACKSPACE, STB_TEXTEDIT_K_DELETE, STB_TEXTEDIT_K_DOWN, STB_TEXTEDIT_K_LEFT, STB_TEXTEDIT_K_LINEEND, STB_TEXTEDIT_K_LINESTART, STB_TEXTEDIT_K_PGDOWN, STB_TEXTEDIT_K_PGUP, STB_TEXTEDIT_K_REDO, STB_TEXTEDIT_K_RIGHT, STB_TEXTEDIT_K_SHIFT
local type, mathMin, mathMax, mathFloor, mathCeil, bitOr, bitLShift = type, math.min, math.max, math.floor, math.ceil, bit32.bor, bit32.lshift
local function IM_COL32(R, G, B, A) return (bitOr(bitLShift(A, 24 --[[IM_COL32_A_SHIFT]]), bitLShift(B, 16 --[[IM_COL32_B_SHIFT]]), bitLShift(G, 8 --[[IM_COL32_G_SHIFT]]), bitLShift(R, 0 --[[IM_COL32_R_SHIFT]]))) end
@@ -40909,47 +40909,341 @@ function MT.ImDrawList:PathBezierQuadraticCurveTo(p2, p3, num_segments)
end
end
-- ponytail: ear-clipping, no anti-aliased fringe (upstream's AA triangulator not ported). O(n^2) is fine for UI polygons.
--------------------------------------------------------------------------------
-- [SECTION] ImTriangulator, ImDrawList concave polygon fill
--------------------------------------------------------------------------------
-- Triangulate concave polygons. Based on "Triangulation by Ear Clipping" paper, O(N^2) complexity.
-- Reference: https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
-- Provided as a convenience for user but not used by main library.
--------------------------------------------------------------------------------
-- - ImTriangulator [Internal]
-- - AddConcavePolyFilled()
--------------------------------------------------------------------------------
local ImTriangulatorNodeType =
{
Convex = 0,
Ear = 1,
Reflex = 2,
}
-- [Luau] No pointers: a node is an int handle (1-based slot) into the parallel arrays of its ImTriangulator
-- (tri.Type[n], tri.Index[n], tri.Pos[n], tri.Next[n], tri.Prev[n]). node->Index (0-based, as upstream) == n - 1.
local function ImTriangulatorNode_Unlink(tri, n) tri.Prev[tri.Next[n]] = tri.Prev[n]; tri.Next[tri.Prev[n]] = tri.Next[n] end
-- [Luau] Deviation: upstream classifies a node as reflex when '!ImTriangleIsClockwise()', i.e. also when its corner is
-- degenerate (collinear or duplicate points). A duplicate point then sits as a reflex on top of every candidate ear's vertex
-- and blocks it, ending in the degenerate fallback with overlapping triangles. Only strictly counter-clockwise corners are
-- reflex here: degenerate corners are clipped as zero-area ears.
local function ImTriangulator_IsReflex(a, b, c) return ((b.x - a.x) * (c.y - b.y)) - ((c.x - b.x) * (b.y - a.y)) < 0.0 end
local function ImTriangulatorNodeSpan()
return { Data = {}, Size = 0 } -- Data: node handles, 1-based
end
MT.ImTriangulatorNodeSpan = {}
MT.ImTriangulatorNodeSpan.__index = MT.ImTriangulatorNodeSpan
function MT.ImTriangulatorNodeSpan:push_back(node) self.Size = self.Size + 1; self.Data[self.Size] = node end
function MT.ImTriangulatorNodeSpan:find_erase_unsorted(idx) for i = self.Size, 1, -1 do if self.Data[i] - 1 == idx then self.Data[i] = self.Data[self.Size]; self.Size = self.Size - 1; return end end end
-- [Luau] The node/ears/reflexes storage (upstream: carved out of _Data->TempBuffer via scratch_buffer) is owned by the
-- triangulator itself and only ever grows. AddConcavePolyFilled() reuses a single module-level instance (no per-call allocations).
local function ImTriangulator()
return setmetatable({
_TrianglesLeft = 0,
_Nodes = 0, -- node handle (head of the circular list)
_Ears = setmetatable(ImTriangulatorNodeSpan(), MT.ImTriangulatorNodeSpan),
_Reflexes = setmetatable(ImTriangulatorNodeSpan(), MT.ImTriangulatorNodeSpan),
Type = {}, Index = {}, Pos = {}, Next = {}, Prev = {}, -- [Luau] ImTriangulatorNode fields, one array each
}, MT.ImTriangulator)
end
MT.ImTriangulator = {}
MT.ImTriangulator.__index = MT.ImTriangulator
function MT.ImTriangulator.EstimateTriangleCount(points_count) return (points_count < 3) and 0 or points_count - 2 end
-- [Luau] In elements (nodes + ears + reflexes) rather than bytes. Unused by the port: arrays grow on demand.
function MT.ImTriangulator.EstimateScratchBufferSize(points_count) return points_count + points_count * 2 end
-- Distribute storage for nodes, ears and reflexes.
-- FIXME-OPT: if everything is convex, we could report it to caller and let it switch to an convex renderer
-- (this would require first building reflexes to bail to convex if empty, without even building nodes)
--- @param points ImVec2[] # 1-based
function MT.ImDrawList:AddConcavePolyFilled(points, points_count, col)
if points_count < 3 or bit32.band(col, 4278190080 --[[IM_COL32_A_MASK]]) == 0 then return end
local idx = {}
local area = 0.0
function MT.ImTriangulator:Init(points, points_count)
assert(points_count >= 3)
self._TrianglesLeft = MT.ImTriangulator.EstimateTriangleCount(points_count)
self._Nodes = 1
self._Ears.Size = 0
self._Reflexes.Size = 0
self:BuildNodes(points, points_count)
-- [Luau] Deviation: upstream only flips the node list when no ear is found, so a counter-clockwise *concave* polygon
-- (whose reflex corners look like ears) yields triangles outside of it. Normalize to clockwise order up-front (O(N)).
local area2 = 0.0
local p0 = points[points_count]
for i = 1, points_count do
idx[i] = i
local a, b = points[i], points[i % points_count + 1]
area = area + (a.x * b.y - b.x * a.y)
local p1 = points[i]
area2 = area2 + (p0.x * p1.y - p1.x * p0.y)
p0 = p1
end
local sign = (area >= 0) and 1 or -1
local function cross(o, a, b) return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x) end
local guard = 0
while #idx > 3 and guard < points_count * points_count do
guard = guard + 1
local n = #idx
local clipped = false
for i = 1, n do
local ia, ib, ic = idx[(i - 2) % n + 1], idx[i], idx[i % n + 1]
local a, b, c = points[ia], points[ib], points[ic]
if cross(a, b, c) * sign > 0 then
local inside = false
for j = 1, n do
local p = idx[j]
if p ~= ia and p ~= ib and p ~= ic then
local q = points[p]
if cross(a, b, q) * sign >= 0 and cross(b, c, q) * sign >= 0 and cross(c, a, q) * sign >= 0 then inside = true; break end
end
end
if not inside then
self:AddTriangleFilled(a, b, c, col)
table.remove(idx, i)
clipped = true
break
end
if area2 < 0.0 then
self:FlipNodeList()
end
self:BuildReflexes()
self:BuildEars()
end
function MT.ImTriangulator:BuildNodes(points, points_count)
local Type, Index, Pos, Next, Prev = self.Type, self.Index, self.Pos, self.Next, self.Prev
for i = 1, points_count do
Type[i] = ImTriangulatorNodeType.Convex
Index[i] = i - 1
Pos[i] = points[i] -- [Luau] reference, not a copy (points are not modified while triangulating)
Next[i] = i + 1
Prev[i] = i - 1
end
Prev[1] = points_count
Next[points_count] = 1
end
function MT.ImTriangulator:BuildReflexes()
local Pos, Next, Prev = self.Pos, self.Next, self.Prev
local n1 = self._Nodes
for _ = self._TrianglesLeft, 0, -1 do
if ImTriangulator_IsReflex(Pos[Prev[n1]], Pos[n1], Pos[Next[n1]]) then
self.Type[n1] = ImTriangulatorNodeType.Reflex
self._Reflexes:push_back(n1)
end
n1 = Next[n1]
end
end
function MT.ImTriangulator:BuildEars()
local Index, Pos, Next, Prev = self.Index, self.Pos, self.Next, self.Prev
local n1 = self._Nodes
for _ = self._TrianglesLeft, 0, -1 do
if self.Type[n1] == ImTriangulatorNodeType.Convex then
local n0, n2 = Prev[n1], Next[n1]
if self:IsEar(Index[n0], Index[n1], Index[n2], Pos[n0], Pos[n1], Pos[n2]) then
self.Type[n1] = ImTriangulatorNodeType.Ear
self._Ears:push_back(n1)
end
end
if not clipped then break end
n1 = Next[n1]
end
end
-- [Luau] out_triangle[3] is returned as 3 values (relative 0-based indexes)
function MT.ImTriangulator:GetNextTriangle()
if self._Ears.Size == 0 then
self:FlipNodeList()
local node = self._Nodes
for _ = self._TrianglesLeft, 0, -1 do
self.Type[node] = ImTriangulatorNodeType.Convex
node = self.Next[node]
end
self._Reflexes.Size = 0
self:BuildReflexes()
self:BuildEars()
-- If we still don't have ears, it means geometry is degenerated.
if self._Ears.Size == 0 then
-- Return first triangle available, mimicking the behavior of convex fill.
assert(self._TrianglesLeft > 0) -- Geometry is degenerated
self._Ears.Data[1] = self._Nodes
self._Ears.Size = 1
end
end
local ear = self._Ears.Data[self._Ears.Size]
self._Ears.Size = self._Ears.Size - 1
local Index, Next, Prev = self.Index, self.Next, self.Prev
local t0, t1, t2 = Index[Prev[ear]], Index[ear], Index[Next[ear]]
ImTriangulatorNode_Unlink(self, ear)
if ear == self._Nodes then
self._Nodes = Next[ear]
end
self:ReclassifyNode(Prev[ear])
self:ReclassifyNode(Next[ear])
self._TrianglesLeft = self._TrianglesLeft - 1
return t0, t1, t2
end
function MT.ImTriangulator:FlipNodeList()
local Next, Prev = self.Next, self.Prev
local nodes = self._Nodes
local prev = nodes
local temp = nodes
local current = Next[nodes]
Next[prev] = prev
Prev[prev] = prev
while current ~= nodes do
temp = Next[current]
Next[current] = prev
Prev[prev] = current
Next[nodes] = current
Prev[current] = nodes
prev = current
current = temp
end
self._Nodes = prev
end
-- A triangle is an ear is no other vertex is inside it. We can test reflexes vertices only (see reference algorithm)
function MT.ImTriangulator:IsEar(i0, i1, i2, v0, v1, v2)
local Index, Pos = self.Index, self.Pos
local data = self._Reflexes.Data
for p = 1, self._Reflexes.Size do
local reflex = data[p]
local idx = Index[reflex]
if idx ~= i0 and idx ~= i1 and idx ~= i2 then
if ImStd.ImTriangleContainsPoint(v0, v1, v2, Pos[reflex]) then
return false
end
end
end
return true
end
function MT.ImTriangulator:ReclassifyNode(n1)
-- Classify node
local type
local n0 = self.Prev[n1]
local n2 = self.Next[n1]
local Index, Pos = self.Index, self.Pos
if ImTriangulator_IsReflex(Pos[n0], Pos[n1], Pos[n2]) then
type = ImTriangulatorNodeType.Reflex
elseif self:IsEar(Index[n0], Index[n1], Index[n2], Pos[n0], Pos[n1], Pos[n2]) then
type = ImTriangulatorNodeType.Ear
else
type = ImTriangulatorNodeType.Convex
end
-- Update lists when a type changes
local n1_type = self.Type[n1]
if type == n1_type then
return
end
if n1_type == ImTriangulatorNodeType.Reflex then
self._Reflexes:find_erase_unsorted(Index[n1])
elseif n1_type == ImTriangulatorNodeType.Ear then
self._Ears:find_erase_unsorted(Index[n1])
end
if type == ImTriangulatorNodeType.Reflex then
self._Reflexes:push_back(n1)
elseif type == ImTriangulatorNodeType.Ear then
self._Ears:push_back(n1)
end
self.Type[n1] = type
end
local concave_triangulator = ImTriangulator() -- [Luau] reused scratch (see ImTriangulator())
-- Use ear-clipping algorithm to triangulate a simple polygon (no self-interaction, no holes).
-- (Reminder: we don't perform any coarse clipping/culling in ImDrawList layer!
-- It is up to caller to ensure not making costly calls that will be outside of visible area.
-- As concave fill is noticeably more expensive than other primitives, be mindful of this...
-- Caller can build AABB of points, and avoid filling if 'draw_list->_CmdHeader.ClipRect.Overlays(points_bb) == false')
--- @param points ImVec2[] # 1-based
--- @param points_count int
--- @param col ImU32
function MT.ImDrawList:AddConcavePolyFilled(points, points_count, col)
if points_count < 3 or bit32.band(col, 4278190080 --[[IM_COL32_A_MASK]]) == 0 then
return
end
local uv = self._Data.TexUvWhitePixel
local uv_x, uv_y = uv.x, uv.y
local triangulator = concave_triangulator
if bit32.band(self.Flags, 4096 --[[ImDrawFlags.AAFill]]) ~= 0 then
-- Anti-aliased Fill
local AA_SIZE = self._FringeScale
local col_trans = bit32.band(col, bit32.bnot(4278190080 --[[IM_COL32_A_MASK]]))
local idx_count = (points_count - 2) * 3 + points_count * 6
local vtx_count = (points_count * 2)
PrimReserve(self, idx_count, vtx_count)
local vb = self.VtxBuffer.Buf
local ib = self.IdxBuffer.Data
local vw = self._VtxWritePtr
local iw = self._IdxWritePtr
-- Add indexes for fill
local vtx_inner_idx = self._VtxCurrentIdx
local vtx_outer_idx = self._VtxCurrentIdx + 1
triangulator:Init(points, points_count)
while triangulator._TrianglesLeft > 0 do
local t0, t1, t2 = triangulator:GetNextTriangle()
ib[iw + 0] = vtx_inner_idx + t0 * 2; ib[iw + 1] = vtx_inner_idx + t1 * 2; ib[iw + 2] = vtx_inner_idx + t2 * 2
iw = iw + 3
end
-- Compute normals
-- [Luau] scratch arrays (see AddPolyline) instead of _Data->TempBuffer. Indexes below are 1-based.
local temp_normals_x, temp_normals_y = poly_normals_x, poly_normals_y
local i0 = points_count
for i1 = 1, points_count do
local p0 = points[i0]
local p1 = points[i1]
local dx, dy = IM_NORMALIZE2F_OVER_ZERO(p1.x - p0.x, p1.y - p0.y)
temp_normals_x[i0] = dy
temp_normals_y[i0] = -dx
i0 = i1
end
i0 = points_count
for i1 = 1, points_count do
-- Average normals
local dm_x, dm_y = IM_FIXNORMAL2F((temp_normals_x[i0] + temp_normals_x[i1]) * 0.5, (temp_normals_y[i0] + temp_normals_y[i1]) * 0.5)
dm_x = dm_x * AA_SIZE * 0.5
dm_y = dm_y * AA_SIZE * 0.5
-- Add vertices
local p1 = points[i1]
WV(vb, vw, p1.x - dm_x, p1.y - dm_y, uv_x, uv_y, col) -- Inner
WV(vb, vw + 1, p1.x + dm_x, p1.y + dm_y, uv_x, uv_y, col_trans) -- Outer
vw = vw + 2
-- Add indexes for fringes
local e0, e1 = (i0 - 1) * 2, (i1 - 1) * 2
ib[iw + 0] = vtx_inner_idx + e1; ib[iw + 1] = vtx_inner_idx + e0; ib[iw + 2] = vtx_outer_idx + e0
ib[iw + 3] = vtx_outer_idx + e0; ib[iw + 4] = vtx_outer_idx + e1; ib[iw + 5] = vtx_inner_idx + e1
iw = iw + 6
i0 = i1
end
self._VtxWritePtr = vw
self._IdxWritePtr = iw
self._VtxCurrentIdx = self._VtxCurrentIdx + vtx_count
else
-- Non Anti-aliased Fill
local idx_count = (points_count - 2) * 3
local vtx_count = points_count
PrimReserve(self, idx_count, vtx_count)
local vb = self.VtxBuffer.Buf
local ib = self.IdxBuffer.Data
local vw = self._VtxWritePtr
local iw = self._IdxWritePtr
for i = 1, vtx_count do
local p = points[i]
WV(vb, vw, p.x, p.y, uv_x, uv_y, col)
vw = vw + 1
end
local base_idx = self._VtxCurrentIdx
triangulator:Init(points, points_count)
while triangulator._TrianglesLeft > 0 do
local t0, t1, t2 = triangulator:GetNextTriangle()
ib[iw + 0] = base_idx + t0; ib[iw + 1] = base_idx + t1; ib[iw + 2] = base_idx + t2
iw = iw + 3
end
self._VtxWritePtr = vw
self._IdxWritePtr = iw
self._VtxCurrentIdx = base_idx + vtx_count
end
if #idx == 3 then self:AddTriangleFilled(points[idx[1]], points[idx[2]], points[idx[3]], col) end
end
function MT.ImDrawList:PathFillConcave(col)
@@ -44870,6 +45164,18 @@ function ImMul(lhs, rhs)
return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y)
end
--- @param a ImVec2
--- @param b ImVec2
--- @param c ImVec2
--- @return float
function ImTriangleArea(a, b, c) return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5 end
--- @param a ImVec2
--- @param b ImVec2
--- @param c ImVec2
--- @return boolean
function ImTriangleIsClockwise(a, b, c) return ((b.x - a.x) * (c.y - b.y)) - ((c.x - b.x) * (b.y - a.y)) > 0.0 end
--- @param str char[]
--- @param begin? int
function ImStd.ImStrlen(str, begin)
@@ -70856,6 +71162,8 @@ return {
ImTextureRef = ImTextureRef,
ImTextureStatus = ImTextureStatus,
ImToUpper = ImToUpper,
ImTriangleArea = ImTriangleArea,
ImTriangleIsClockwise = ImTriangleIsClockwise,
ImTrunc = ImTrunc,
ImTrunc64 = ImTrunc64,
ImU16 = ImU16,
+133 -133
View File
@@ -14,18 +14,18 @@ polyline stroker (AddPolyline), Lua-native replacements (ImGuiStorage, ImStr*, I
upstream file funcs ported by size similarity stubs
imgui.cpp 786 87.4% 93.5% 75.1% 2
imgui_widgets.cpp 308 93.8% 98.7% 78.4% 1
imgui_draw.cpp 258 81.8% 92.3% 61.1% 2
imgui_draw.cpp 258 86.8% 94.4% 61.2% 2
imgui_tables.cpp 113 96.5% 99.0% 74.0% 0
imgui_demo.cpp 56 100.0% 100.0% 55.8% 0
imgui.h 110 53.6% 37.4% 60.0% 0
imgui_internal.h 269 62.5% 65.7% 67.6% 1
TOTAL 1900 83.1% 95.3% 70.4% 6
imgui_internal.h 269 63.2% 67.5% 68.5% 1
TOTAL 1900 83.9% 95.6% 70.4% 6
upstream code reproduced (similarity x ported size / all upstream size): 67.0%
upstream code reproduced (similarity x ported size / all upstream size): 67.2%
Public API (imgui.h, namespace ImGui) 368 / 376 97.9%
Internal API (imgui_internal.h, namespace ImGui) 417 / 443 94.1%
Enum values (imgui.h + imgui_internal.h) 1034 / 1078 95.9%
Struct fields (imgui.h + imgui_internal.h) 1833 / 1926 95.2%
Enum values (imgui.h + imgui_internal.h) 1037 / 1078 96.2%
Struct fields (imgui.h + imgui_internal.h) 1839 / 1926 95.5%
Legend: [x] ported (sim %) [~] stub [ ] not ported [-] excluded (c++-only / obsolete / os-specific / #if 0 / test-engine)
@@ -41,7 +41,7 @@ imgui.cpp
[ ] FreeWrapper
-- USER FACING STRUCTURES (ImGuiStyle, ImGuiIO, ImGuiPlatformIO)
[x] 33% ImGuiStyle::ImGuiStyle imgui_internal.lua:1518
[x] 33% ImGuiStyle::ImGuiStyle imgui_internal.lua:1530
[x] 83% ImGuiStyle::ScaleAllSizes imgui.lua:4779
[x] 12% ImGuiIO::ImGuiIO imgui_h.lua:1187
[x] 83% ImGuiIO::AddInputCharacter imgui.lua:7983
@@ -200,7 +200,7 @@ imgui.cpp
[ ] ImGui::GetAllocatorFunctions
[x] 87% ImGui::CreateContext imgui.lua:5580
[x] 83% ImGui::DestroyContext imgui.lua:5592
[x] 6% ImGuiContext::ImGuiContext imgui_internal.lua:2239
[x] 6% ImGuiContext::ImGuiContext imgui_internal.lua:2251
[-] ImGuiContext::~ImGuiContext c++-only
[x] 78% ImGui::Initialize imgui.lua:5538
[x] 44% ImGui::Shutdown imgui.lua:14315
@@ -210,7 +210,7 @@ imgui.cpp
[ ] ImGui::CallContextHooks
-- MAIN CODE (most of the code! lots of stuff, needs tidying up!)
[x] 11% ImGuiWindow::ImGuiWindow imgui_internal.lua:2843
[x] 11% ImGuiWindow::ImGuiWindow imgui_internal.lua:2855
[-] ImGuiWindow::~ImGuiWindow c++-only
[x] 74% SetCurrentWindow imgui.lua:10805
[x] 85% ImGui::GcCompactTransientMiscBuffers imgui.lua:10826
@@ -1076,7 +1076,7 @@ imgui_widgets.cpp
[x] 79% STB_TEXTEDIT_DELETECHARS imgui_widgets.lua:4712
[x] 87% STB_TEXTEDIT_INSERTCHARS imgui_widgets.lua:4726
[x] 81% stb_textedit_replace imgui_widgets.lua:4769
[x] 12% ImGuiInputTextState::ImGuiInputTextState imgui_internal.lua:1705
[x] 12% ImGuiInputTextState::ImGuiInputTextState imgui_internal.lua:1717
[-] ImGuiInputTextState::~ImGuiInputTextState c++-only
[x] 93% ImGuiInputTextState::OnKeyPressed imgui_widgets.lua:4797
[x] 63% ImGuiInputTextState::OnCharPressed imgui_widgets.lua:4812
@@ -1219,7 +1219,7 @@ imgui_widgets.cpp
-- Widgets: BeginTabBar, EndTabBar, etc.
[x] 19% ImGuiTabBarSection::ImGuiTabBarSection imgui_widgets.lua:10678
[x] 16% ImGuiTabBar::ImGuiTabBar imgui_internal.lua:2210
[x] 16% ImGuiTabBar::ImGuiTabBar imgui_internal.lua:2222
[x] 65% TabItemGetSectionIdx imgui_widgets.lua:10645
[ ] TabItemComparerBySection
[ ] TabItemComparerByBeginOrder
@@ -1273,7 +1273,7 @@ imgui_draw.cpp
[x] 82% ImGui::StyleColorsLight imgui_draw.lua:270
-- ImDrawList
[x] 30% ImDrawListSharedData::ImDrawListSharedData imgui_internal.lua:1120
[x] 30% ImDrawListSharedData::ImDrawListSharedData imgui_internal.lua:1132
[-] ImDrawListSharedData::~ImDrawListSharedData c++-only
[x] 57% ImDrawListSharedData::SetCircleTessellationMaxError imgui_draw.lua:3918
[x] 6% ImDrawList::ImDrawList imgui_h.lua:657
@@ -1351,20 +1351,20 @@ imgui_draw.cpp
[x] 84% ImDrawList::AddImageRounded imgui_draw.lua:6549
-- ImTriangulator, ImDrawList concave polygon fill
[ ] ImTriangulatorNode::Unlink
[ ] ImTriangulatorNodeSpan::push_back
[ ] ImTriangulatorNodeSpan::find_erase_unsorted
[ ] ImTriangulator::EstimateTriangleCount
[ ] ImTriangulator::EstimateScratchBufferSize
[ ] ImTriangulator::Init
[ ] ImTriangulator::BuildNodes
[ ] ImTriangulator::BuildReflexes
[ ] ImTriangulator::BuildEars
[ ] ImTriangulator::GetNextTriangle
[ ] ImTriangulator::FlipNodeList
[ ] ImTriangulator::IsEar
[ ] ImTriangulator::ReclassifyNode
[x] 17% ImDrawList::AddConcavePolyFilled imgui_draw.lua:7460
[x] 35% ImTriangulatorNode::Unlink imgui_draw.lua:7478
[x] 50% ImTriangulatorNodeSpan::push_back imgui_draw.lua:7491
[x] 66% ImTriangulatorNodeSpan::find_erase_unsorted imgui_draw.lua:7492
[x] 84% ImTriangulator::EstimateTriangleCount imgui_draw.lua:7508
[x] 71% ImTriangulator::EstimateScratchBufferSize imgui_draw.lua:7510
[x] 38% ImTriangulator::Init imgui_draw.lua:7516
[x] 45% ImTriangulator::BuildNodes imgui_draw.lua:7541
[x] 32% ImTriangulator::BuildReflexes imgui_draw.lua:7554
[x] 38% ImTriangulator::BuildEars imgui_draw.lua:7566
[x] 53% ImTriangulator::GetNextTriangle imgui_draw.lua:7582
[x] 65% ImTriangulator::FlipNodeList imgui_draw.lua:7620
[x] 56% ImTriangulator::IsEar imgui_draw.lua:7643
[x] 58% ImTriangulator::ReclassifyNode imgui_draw.lua:7658
[x] 39% ImDrawList::AddConcavePolyFilled imgui_draw.lua:7701
-- ImDrawListSplitter
[x] 58% ImDrawListSplitter::ClearFreeMemory imgui_draw.lua:4201
@@ -1964,13 +1964,13 @@ imgui.h
[x] 92% ImDrawListSplitter::Clear imgui_draw.lua:4196
[ ] ImDrawList::GetClipRectMin
[ ] ImDrawList::GetClipRectMax
[x] 80% ImDrawList::AddPolyline imgui_internal.lua:1077
[x] 100% ImDrawList::PathClear imgui_internal.lua:1029
[x] 16% ImDrawList::PathLineTo imgui_internal.lua:1033
[x] 48% ImDrawList::PathLineToMergeDuplicate imgui_internal.lua:1043
[x] 94% ImDrawList::PathFillConvex imgui_internal.lua:1053
[x] 94% ImDrawList::PathFillConcave imgui_draw.lua:7501
[x] 75% ImDrawList::PathStroke imgui_internal.lua:1061
[x] 80% ImDrawList::AddPolyline imgui_internal.lua:1089
[x] 100% ImDrawList::PathClear imgui_internal.lua:1041
[x] 16% ImDrawList::PathLineTo imgui_internal.lua:1045
[x] 48% ImDrawList::PathLineToMergeDuplicate imgui_internal.lua:1055
[x] 94% ImDrawList::PathFillConvex imgui_internal.lua:1065
[x] 94% ImDrawList::PathFillConcave imgui_draw.lua:7795
[x] 75% ImDrawList::PathStroke imgui_internal.lua:1073
[x] 89% ImDrawList::ChannelsSplit imgui_draw.lua:4377
[x] 80% ImDrawList::ChannelsMerge imgui_draw.lua:4378
[x] 89% ImDrawList::ChannelsSetCurrent imgui_draw.lua:4380
@@ -2040,8 +2040,8 @@ imgui_internal.h
[x] 35% ImUpperPowerOfTwo imgui_internal.lua:280
[x] 82% ImCountSetBits imgui_internal.lua:295
[x] 62% ImToUpper imgui_internal.lua:403
[x] 75% ImCharIsBlankA imgui_internal.lua:692
[x] 83% ImCharIsBlankW imgui_internal.lua:695
[x] 75% ImCharIsBlankA imgui_internal.lua:704
[x] 83% ImCharIsBlankW imgui_internal.lua:707
[ ] ImCharIsXdigitA
[x] 0% ImFileOpen imgui.lua:4702
[x] 0% ImFileClose imgui.lua:4719
@@ -2080,41 +2080,41 @@ imgui_internal.h
[x] 71% ImExponentialMovingAverage imgui_internal.lua:308
[x] 60% ImIsTruncated imgui_internal.lua:264
[x] 60% ImIsTruncated4 imgui_internal.lua:266
[ ] ImTriangleArea
[ ] ImTriangleIsClockwise
[x] 0% IM_MSVC_RUNTIME_CHECKS_OFF::ImVec1 imgui_internal.lua:797
[x] 100% ImTriangleArea imgui_internal.lua:468
[x] 100% ImTriangleIsClockwise imgui_internal.lua:474
[x] 0% IM_MSVC_RUNTIME_CHECKS_OFF::ImVec1 imgui_internal.lua:809
[ ] ImVec2i::ImVec2i
[ ] ImVec2ih::ImVec2ih
[x] 0% ImRect::ImRect imgui_internal.lua:827
[x] 90% ImRect::GetCenter imgui_internal.lua:857
[x] 89% ImRect::GetSize imgui_internal.lua:862
[x] 94% ImRect::GetWidth imgui_internal.lua:858
[x] 94% ImRect::GetHeight imgui_internal.lua:859
[x] 91% ImRect::GetArea imgui_internal.lua:951
[x] 33% ImRect::GetTL imgui_internal.lua:865
[x] 89% ImRect::GetTR imgui_internal.lua:867
[x] 89% ImRect::GetBL imgui_internal.lua:869
[x] 33% ImRect::GetBR imgui_internal.lua:871
[x] 43% ImRect::Contains imgui_internal.lua:834
[x] 96% ImRect::ContainsWithPad imgui_internal.lua:846
[x] 14% ImRect::Overlaps imgui_internal.lua:852
[x] 59% ImRect::Add imgui_internal.lua:896
[x] 96% ImRect::AddX imgui_internal.lua:912
[x] 96% ImRect::AddY imgui_internal.lua:913
[x] 38% ImRect::Expand imgui_internal.lua:917
[x] 64% ImRect::Translate imgui_internal.lua:934
[x] 55% ImRect::TranslateX imgui_internal.lua:940
[x] 55% ImRect::TranslateY imgui_internal.lua:945
[x] 22% ImRect::ClipWith imgui_internal.lua:876
[x] 20% ImRect::ClipWithFull imgui_internal.lua:886
[x] 91% ImRect::IsInverted imgui_internal.lua:949
[x] 94% ImRect::ToVec4 imgui_internal.lua:928
[x] 36% ImRect::AsVec4 imgui_internal.lua:954
[x] 0% ImRect::ImRect imgui_internal.lua:839
[x] 90% ImRect::GetCenter imgui_internal.lua:869
[x] 89% ImRect::GetSize imgui_internal.lua:874
[x] 94% ImRect::GetWidth imgui_internal.lua:870
[x] 94% ImRect::GetHeight imgui_internal.lua:871
[x] 91% ImRect::GetArea imgui_internal.lua:963
[x] 33% ImRect::GetTL imgui_internal.lua:877
[x] 89% ImRect::GetTR imgui_internal.lua:879
[x] 89% ImRect::GetBL imgui_internal.lua:881
[x] 33% ImRect::GetBR imgui_internal.lua:883
[x] 43% ImRect::Contains imgui_internal.lua:846
[x] 96% ImRect::ContainsWithPad imgui_internal.lua:858
[x] 14% ImRect::Overlaps imgui_internal.lua:864
[x] 59% ImRect::Add imgui_internal.lua:908
[x] 96% ImRect::AddX imgui_internal.lua:924
[x] 96% ImRect::AddY imgui_internal.lua:925
[x] 38% ImRect::Expand imgui_internal.lua:929
[x] 64% ImRect::Translate imgui_internal.lua:946
[x] 55% ImRect::TranslateX imgui_internal.lua:952
[x] 55% ImRect::TranslateY imgui_internal.lua:957
[x] 22% ImRect::ClipWith imgui_internal.lua:888
[x] 20% ImRect::ClipWithFull imgui_internal.lua:898
[x] 91% ImRect::IsInverted imgui_internal.lua:961
[x] 94% ImRect::ToVec4 imgui_internal.lua:940
[x] 36% ImRect::AsVec4 imgui_internal.lua:966
[ ] ImBitArrayGetStorageSizeInBytes
[ ] ImBitArrayClearAllBits
[ ] ImBitArrayTestBit
[ ] ImBitArrayClearBit
[x] 34% ImBitArraySetBit imgui_internal.lua:989
[x] 34% ImBitArraySetBit imgui_internal.lua:1001
[ ] ImBitArraySetBitRange
[ ] ImBitVector::Create
[ ] ImBitVector::Clear
@@ -2166,10 +2166,10 @@ imgui_internal.h
[ ] template::offset_from_ptr
[ ] template::ptr_from_offset
[ ] template::swap
[x] 83% ImGuiTextIndex::clear imgui_internal.lua:1819
[x] 100% ImGuiTextIndex::size imgui_internal.lua:1821
[x] 71% ImGuiTextIndex::get_line_begin imgui_internal.lua:1823
[x] 76% ImGuiTextIndex::get_line_end imgui_internal.lua:1827
[x] 83% ImGuiTextIndex::clear imgui_internal.lua:1831
[x] 100% ImGuiTextIndex::size imgui_internal.lua:1833
[x] 71% ImGuiTextIndex::get_line_begin imgui_internal.lua:1835
[x] 76% ImGuiTextIndex::get_line_end imgui_internal.lua:1839
[ ] ImGuiTextFilterItem::ImGuiTextFilterItem
[ ] ImGuiPackedDate::ImGuiPackedDate
[ ] ImGuiPackedDate::IsValid
@@ -2177,37 +2177,37 @@ imgui_internal.h
[ ] ImGuiPackedDate::SubtractMonths
-- ImDrawList support
[x] 27% ImDrawDataBuilder::ImDrawDataBuilder imgui_internal.lua:3016
[x] 27% ImDrawDataBuilder::ImDrawDataBuilder imgui_internal.lua:3028
-- Style support
[ ] ImGuiStyleVarInfo::GetVarPtr
[x] 39% ImGuiStyleMod::ImGuiStyleMod imgui_internal.lua:1268
[x] 39% ImGuiStyleMod::ImGuiStyleMod imgui_internal.lua:1280
-- Widgets support: flags, enums, data structures
[x] 21% ImGuiComboPreviewData::ImGuiComboPreviewData imgui_internal.lua:1665
[x] 12% ImGuiMenuColumns::ImGuiMenuColumns imgui_internal.lua:2683
[x] 20% ImGuiInputTextDeactivatedState::ImGuiInputTextDeactivatedState imgui_internal.lua:1751
[x] 21% ImGuiComboPreviewData::ImGuiComboPreviewData imgui_internal.lua:1677
[x] 12% ImGuiMenuColumns::ImGuiMenuColumns imgui_internal.lua:2695
[x] 20% ImGuiInputTextDeactivatedState::ImGuiInputTextDeactivatedState imgui_internal.lua:1763
[ ] ImGuiInputTextDeactivatedState::ClearFreeMemory
[ ] ImGuiInputTextState::ClearText
[ ] ImGuiInputTextState::ClearFreeMemory
[ ] ImGuiInputTextState::GetText
[x] 3% ImGuiNextWindowData::ImGuiNextWindowData imgui_internal.lua:1433
[x] 3% ImGuiNextWindowData::ImGuiNextWindowData imgui_internal.lua:1445
[ ] ImGuiNextWindowData::ClearFlags
[x] 20% ImGuiNextItemData::ImGuiNextItemData imgui_internal.lua:1385
[x] 20% ImGuiNextItemData::ImGuiNextItemData imgui_internal.lua:1397
[ ] ImGuiNextItemData::ClearFlags
[x] 11% ImGuiLastItemData::ImGuiLastItemData imgui_internal.lua:1305
[x] 11% ImGuiLastItemData::ImGuiLastItemData imgui_internal.lua:1317
[x] 8% ImGuiErrorRecoveryState::ImGuiErrorRecoveryState imgui.lua:19808
[ ] ImGuiPtrOrIndex::ImGuiPtrOrIndex
-- Popup support
[x] 36% ImGuiPopupData::ImGuiPopupData imgui_internal.lua:3570
[x] 36% ImGuiPopupData::ImGuiPopupData imgui_internal.lua:3582
-- Inputs support
[x] 9% ImGuiInputEvent::ImGuiInputEvent imgui_internal.lua:3364
[x] 73% ImGuiKeyRoutingData::ImGuiKeyRoutingData imgui_internal.lua:1772
[x] 10% ImGuiKeyRoutingTable::ImGuiKeyRoutingTable imgui_internal.lua:1799
[x] 9% ImGuiInputEvent::ImGuiInputEvent imgui_internal.lua:3376
[x] 73% ImGuiKeyRoutingData::ImGuiKeyRoutingData imgui_internal.lua:1784
[x] 10% ImGuiKeyRoutingTable::ImGuiKeyRoutingTable imgui_internal.lua:1811
[ ] ImGuiKeyRoutingTable::Clear
[x] 64% ImGuiKeyOwnerData::ImGuiKeyOwnerData imgui_internal.lua:647
[x] 64% ImGuiKeyOwnerData::ImGuiKeyOwnerData imgui_internal.lua:659
-- Clipper support
[ ] ImGuiListClipperRange::FromIndices
@@ -2216,25 +2216,25 @@ imgui_internal.h
[ ] ImGuiListClipperData::Reset
-- Navigation support
[x] 13% ImGuiNavItemData::ImGuiNavItemData imgui_internal.lua:1905
[x] 13% ImGuiNavItemData::ImGuiNavItemData imgui_internal.lua:1917
[ ] ImGuiNavItemData::Clear
-- Typing-select support
[x] 7% ImGuiTypingSelectState::ImGuiTypingSelectState imgui_internal.lua:1949
[x] 71% ImGuiTypingSelectState::Clear imgui_internal.lua:1952
[x] 7% ImGuiTypingSelectState::ImGuiTypingSelectState imgui_internal.lua:1961
[x] 71% ImGuiTypingSelectState::Clear imgui_internal.lua:1964
-- Columns support
[x] 19% ImGuiOldColumnData::ImGuiOldColumnData imgui_tables.lua:340
[x] 5% ImGuiOldColumns::ImGuiOldColumns imgui_tables.lua:345
-- Box-select support
[x] 6% ImGuiBoxSelectState::ImGuiBoxSelectState imgui_internal.lua:1976
[x] 6% ImGuiBoxSelectState::ImGuiBoxSelectState imgui_internal.lua:1988
-- Multi-select support
[x] 9% ImGuiMultiSelectTempData::ImGuiMultiSelectTempData imgui_internal.lua:2022
[x] 10% ImGuiMultiSelectTempData::Clear imgui_internal.lua:2028
[x] 67% ImGuiMultiSelectTempData::ClearIO imgui_internal.lua:2046
[x] 72% ImGuiMultiSelectState::ImGuiMultiSelectState imgui_internal.lua:2059
[x] 9% ImGuiMultiSelectTempData::ImGuiMultiSelectTempData imgui_internal.lua:2034
[x] 10% ImGuiMultiSelectTempData::Clear imgui_internal.lua:2040
[x] 67% ImGuiMultiSelectTempData::ClearIO imgui_internal.lua:2058
[x] 72% ImGuiMultiSelectState::ImGuiMultiSelectState imgui_internal.lua:2071
-- Docking support
[x] 100% ImGuiDockNode::IsRootNode imgui.lua:1095
@@ -2252,23 +2252,23 @@ imgui_internal.h
[x] 20% ImGuiDockContext::ImGuiDockContext imgui.lua:1040
-- Viewport support
[x] 36% ImGuiViewportP::ImGuiViewportP imgui_internal.lua:3103
[x] 36% ImGuiViewportP::ImGuiViewportP imgui_internal.lua:3115
[-] ImGuiViewportP::~ImGuiViewportP c++-only
[x] 78% ImGuiViewportP::ClearRequestFlags imgui_internal.lua:3058
[x] 94% ImGuiViewportP::CalcWorkRectPos imgui_internal.lua:3065
[x] 98% ImGuiViewportP::CalcWorkRectSize imgui_internal.lua:3069
[x] 87% ImGuiViewportP::UpdateWorkRect imgui_internal.lua:3074
[x] 92% ImGuiViewportP::GetMainRect imgui_internal.lua:3081
[x] 92% ImGuiViewportP::GetWorkRect imgui_internal.lua:3088
[x] 96% ImGuiViewportP::GetBuildWorkRect imgui_internal.lua:3095
[x] 78% ImGuiViewportP::ClearRequestFlags imgui_internal.lua:3070
[x] 94% ImGuiViewportP::CalcWorkRectPos imgui_internal.lua:3077
[x] 98% ImGuiViewportP::CalcWorkRectSize imgui_internal.lua:3081
[x] 87% ImGuiViewportP::UpdateWorkRect imgui_internal.lua:3086
[x] 92% ImGuiViewportP::GetMainRect imgui_internal.lua:3093
[x] 92% ImGuiViewportP::GetWorkRect imgui_internal.lua:3100
[x] 96% ImGuiViewportP::GetBuildWorkRect imgui_internal.lua:3107
-- Settings support
[x] 18% ImGuiWindowSettings::ImGuiWindowSettings imgui_internal.lua:2650
[x] 18% ImGuiWindowSettings::ImGuiWindowSettings imgui_internal.lua:2662
[ ] ImGuiWindowSettings::GetName
[x] 13% ImGuiSettingsHandler::ImGuiSettingsHandler imgui_h.lua:2898
-- Metrics, Debug Tools
[x] 7% ImGuiDebugAllocInfo::ImGuiDebugAllocInfo imgui_internal.lua:1853
[x] 7% ImGuiDebugAllocInfo::ImGuiDebugAllocInfo imgui_internal.lua:1865
[ ] ImGuiStackLevelInfo::ImGuiStackLevelInfo
[ ] ImGuiDebugItemPathQuery::ImGuiDebugItemPathQuery
[ ] ImGuiIDStackTool::ImGuiIDStackTool
@@ -2277,12 +2277,12 @@ imgui_internal.h
[ ] ImGuiContextHook::ImGuiContextHook
-- ImGuiWindowTempData, ImGuiWindow
[x] 92% ImGuiWindow::Rect imgui_internal.lua:2824
[x] 84% ImGuiWindow::TitleBarRect imgui_internal.lua:2830
[x] 91% ImGuiWindow::MenuBarRect imgui_internal.lua:2836
[x] 92% ImGuiWindow::Rect imgui_internal.lua:2836
[x] 84% ImGuiWindow::TitleBarRect imgui_internal.lua:2842
[x] 91% ImGuiWindow::MenuBarRect imgui_internal.lua:2848
-- Tab bar, Tab item support
[x] 50% ImGuiTabItem::ImGuiTabItem imgui_internal.lua:2191
[x] 50% ImGuiTabItem::ImGuiTabItem imgui_internal.lua:2203
-- Table support + internal API
[x] 28% ImGuiTableColumn::ImGuiTableColumn imgui_tables.lua:240
@@ -2302,32 +2302,32 @@ imgui_internal.h
[x] 100% GetCurrentWindowRead imgui.lua:13592
[x] 100% GetCurrentWindow imgui.lua:13599
[ ] SetWindowParentWindowForFocusRoute
[x] 99% WindowRectAbsToRel imgui_internal.lua:664
[x] 99% WindowRectRelToAbs imgui_internal.lua:669
[x] 98% WindowPosAbsToRel imgui_internal.lua:682
[x] 98% WindowPosRelToAbs imgui_internal.lua:688
[x] 99% WindowRectAbsToRel imgui_internal.lua:676
[x] 99% WindowRectRelToAbs imgui_internal.lua:681
[x] 98% WindowPosAbsToRel imgui_internal.lua:694
[x] 98% WindowPosRelToAbs imgui_internal.lua:700
[ ] GetPixelDensity
[x] 55% GetRoundedFontSize imgui_internal.lua:658
[x] 55% GetRoundedFontSize imgui_internal.lua:670
[x] 15% GetForegroundDrawList imgui.lua:13675
[x] 80% LocalizeGetMsg imgui_internal.lua:3674
[x] 80% LocalizeGetMsg imgui_internal.lua:3686
[ ] ScrollToBringRectIntoView
[ ] GetItemStatusFlags
[ ] GetActiveID
[ ] GetFocusID
[x] 2% ItemSize imgui.lua:6492
[x] 100% IsNamedKey imgui_internal.lua:572
[x] 75% IsNamedKeyOrMod imgui_internal.lua:603
[x] 100% IsNamedKey imgui_internal.lua:584
[x] 75% IsNamedKeyOrMod imgui_internal.lua:615
[ ] IsLegacyKey
[x] 60% IsKeyboardKey imgui_internal.lua:577
[x] 60% IsGamepadKey imgui_internal.lua:582
[x] 60% IsMouseKey imgui_internal.lua:587
[x] 60% IsAliasKey imgui_internal.lua:592
[x] 100% IsLRModKey imgui_internal.lua:597
[x] 76% ConvertSingleModFlagToKey imgui_internal.lua:609
[x] 60% IsKeyboardKey imgui_internal.lua:589
[x] 60% IsGamepadKey imgui_internal.lua:594
[x] 60% IsMouseKey imgui_internal.lua:599
[x] 60% IsAliasKey imgui_internal.lua:604
[x] 100% IsLRModKey imgui_internal.lua:609
[x] 76% ConvertSingleModFlagToKey imgui_internal.lua:621
[x] 17% GetKeyData imgui.lua:8440
[x] 97% MouseButtonToKey imgui_internal.lua:569
[x] 81% IsActiveIdUsingNavDir imgui_internal.lua:673
[x] 88% GetKeyOwnerData imgui_internal.lua:635
[x] 97% MouseButtonToKey imgui_internal.lua:581
[x] 81% IsActiveIdUsingNavDir imgui_internal.lua:685
[x] 88% GetKeyOwnerData imgui_internal.lua:647
[x] 100% DockNodeGetRootNode imgui.lua:4488
[x] 100% DockNodeIsInHierarchyOf imgui.lua:4493
[x] 86% DockNodeGetDepth imgui.lua:4501
@@ -2335,26 +2335,26 @@ imgui_internal.h
[ ] GetWindowDockNode
[x] 97% DockBuilderGetCentralNode imgui.lua:3661
[ ] GetCurrentFocusScope
[x] 91% GetBoxSelectState imgui_internal.lua:2065
[x] 95% GetMultiSelectState imgui_internal.lua:2068
[x] 91% GetBoxSelectState imgui_internal.lua:2077
[x] 95% GetMultiSelectState imgui_internal.lua:2080
[ ] GetCurrentTabBar
[x] 35% TabBarGetTabOrder imgui_widgets.lua:11197
[-] RenderNavHighlight obsolete
[x] 100% TempInputIsActive imgui_internal.lua:3681
[x] 88% GetInputTextState imgui_internal.lua:3689
[x] 100% TempInputIsActive imgui_internal.lua:3693
[x] 88% GetInputTextState imgui_internal.lua:3701
[ ] IsItemActiveAsInputText
[x] 80% SetNextItemColorMarker imgui_internal.lua:1083
[x] 80% SetNextItemColorMarker imgui_internal.lua:1095
-- ImFontLoader
[x] 6% ImFontLoader::ImFontLoader imgui_internal.lua:3165
[x] 6% ImFontLoader::ImFontLoader imgui_internal.lua:3177
-- ImFontAtlas internal API
[-] operator== c++-only
[-] operator!= c++-only
[x] 75% ImFontAtlasRectId_GetIndex imgui_internal.lua:3217
[x] 62% ImFontAtlasRectId_GetGeneration imgui_internal.lua:3221
[x] 77% ImFontAtlasRectId_Make imgui_internal.lua:3226
[x] 18% ImFontAtlasBuilder::ImFontAtlasBuilder imgui_internal.lua:1184
[x] 75% ImFontAtlasRectId_GetIndex imgui_internal.lua:3229
[x] 62% ImFontAtlasRectId_GetGeneration imgui_internal.lua:3233
[x] 77% ImFontAtlasRectId_Make imgui_internal.lua:3238
[x] 18% ImFontAtlasBuilder::ImFontAtlasBuilder imgui_internal.lua:1196
====================================================================================================
API declarations not ported (by upstream line)
@@ -2489,7 +2489,7 @@ Enums (values ported / total; missing listed)
ImGuiWindowRefreshFlags_ 4 / 4
ImTextureFormat 2 / 2
ImTextureStatus 5 / 5
ImTriangulatorNodeType 0 / 3 missing: ImTriangulatorNodeType_Convex, ImTriangulatorNodeType_Ear, ImTriangulatorNodeType_Reflex
ImTriangulatorNodeType 3 / 3
ImWcharClass 3 / 3
MyItemColumnID 5 / 5
@@ -2635,8 +2635,8 @@ Struct fields (name found in the port / total; missing listed). Field names are
ImRect 2 / 2
ImTextureData 16 / 17 missing: QueueUserData
ImTextureRect 4 / 4
ImTriangulator 0 / 4 missing: _TrianglesLeft, _Nodes, _Ears, _Reflexes
ImTriangulatorNode 3 / 5 missing: Next, Prev
ImTriangulator 4 / 4
ImTriangulatorNode 5 / 5
ImTriangulatorNodeSpan 2 / 2
ImVec2i 2 / 2
ImVec2ih 2 / 2
+329 -35
View File
@@ -7455,47 +7455,341 @@ function MT.ImDrawList:PathBezierQuadraticCurveTo(p2, p3, num_segments)
end
end
-- ponytail: ear-clipping, no anti-aliased fringe (upstream's AA triangulator not ported). O(n^2) is fine for UI polygons.
--------------------------------------------------------------------------------
-- [SECTION] ImTriangulator, ImDrawList concave polygon fill
--------------------------------------------------------------------------------
-- Triangulate concave polygons. Based on "Triangulation by Ear Clipping" paper, O(N^2) complexity.
-- Reference: https://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
-- Provided as a convenience for user but not used by main library.
--------------------------------------------------------------------------------
-- - ImTriangulator [Internal]
-- - AddConcavePolyFilled()
--------------------------------------------------------------------------------
local ImTriangulatorNodeType =
{
Convex = 0,
Ear = 1,
Reflex = 2,
}
-- [Luau] No pointers: a node is an int handle (1-based slot) into the parallel arrays of its ImTriangulator
-- (tri.Type[n], tri.Index[n], tri.Pos[n], tri.Next[n], tri.Prev[n]). node->Index (0-based, as upstream) == n - 1.
local function ImTriangulatorNode_Unlink(tri, n) tri.Prev[tri.Next[n]] = tri.Prev[n]; tri.Next[tri.Prev[n]] = tri.Next[n] end
-- [Luau] Deviation: upstream classifies a node as reflex when '!ImTriangleIsClockwise()', i.e. also when its corner is
-- degenerate (collinear or duplicate points). A duplicate point then sits as a reflex on top of every candidate ear's vertex
-- and blocks it, ending in the degenerate fallback with overlapping triangles. Only strictly counter-clockwise corners are
-- reflex here: degenerate corners are clipped as zero-area ears.
local function ImTriangulator_IsReflex(a, b, c) return ((b.x - a.x) * (c.y - b.y)) - ((c.x - b.x) * (b.y - a.y)) < 0.0 end
local function ImTriangulatorNodeSpan()
return { Data = {}, Size = 0 } -- Data: node handles, 1-based
end
MT.ImTriangulatorNodeSpan = {}
MT.ImTriangulatorNodeSpan.__index = MT.ImTriangulatorNodeSpan
function MT.ImTriangulatorNodeSpan:push_back(node) self.Size = self.Size + 1; self.Data[self.Size] = node end
function MT.ImTriangulatorNodeSpan:find_erase_unsorted(idx) for i = self.Size, 1, -1 do if self.Data[i] - 1 == idx then self.Data[i] = self.Data[self.Size]; self.Size = self.Size - 1; return end end end
-- [Luau] The node/ears/reflexes storage (upstream: carved out of _Data->TempBuffer via scratch_buffer) is owned by the
-- triangulator itself and only ever grows. AddConcavePolyFilled() reuses a single module-level instance (no per-call allocations).
local function ImTriangulator()
return setmetatable({
_TrianglesLeft = 0,
_Nodes = 0, -- node handle (head of the circular list)
_Ears = setmetatable(ImTriangulatorNodeSpan(), MT.ImTriangulatorNodeSpan),
_Reflexes = setmetatable(ImTriangulatorNodeSpan(), MT.ImTriangulatorNodeSpan),
Type = {}, Index = {}, Pos = {}, Next = {}, Prev = {}, -- [Luau] ImTriangulatorNode fields, one array each
}, MT.ImTriangulator)
end
MT.ImTriangulator = {}
MT.ImTriangulator.__index = MT.ImTriangulator
function MT.ImTriangulator.EstimateTriangleCount(points_count) return (points_count < 3) and 0 or points_count - 2 end
-- [Luau] In elements (nodes + ears + reflexes) rather than bytes. Unused by the port: arrays grow on demand.
function MT.ImTriangulator.EstimateScratchBufferSize(points_count) return points_count + points_count * 2 end
-- Distribute storage for nodes, ears and reflexes.
-- FIXME-OPT: if everything is convex, we could report it to caller and let it switch to an convex renderer
-- (this would require first building reflexes to bail to convex if empty, without even building nodes)
--- @param points ImVec2[] # 1-based
function MT.ImDrawList:AddConcavePolyFilled(points, points_count, col)
if points_count < 3 or bit32.band(col, IM_COL32_A_MASK) == 0 then return end
local idx = {}
local area = 0.0
function MT.ImTriangulator:Init(points, points_count)
IM_ASSERT(points_count >= 3)
self._TrianglesLeft = MT.ImTriangulator.EstimateTriangleCount(points_count)
self._Nodes = 1
self._Ears.Size = 0
self._Reflexes.Size = 0
self:BuildNodes(points, points_count)
-- [Luau] Deviation: upstream only flips the node list when no ear is found, so a counter-clockwise *concave* polygon
-- (whose reflex corners look like ears) yields triangles outside of it. Normalize to clockwise order up-front (O(N)).
local area2 = 0.0
local p0 = points[points_count]
for i = 1, points_count do
idx[i] = i
local a, b = points[i], points[i % points_count + 1]
area = area + (a.x * b.y - b.x * a.y)
local p1 = points[i]
area2 = area2 + (p0.x * p1.y - p1.x * p0.y)
p0 = p1
end
local sign = (area >= 0) and 1 or -1
local function cross(o, a, b) return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x) end
local guard = 0
while #idx > 3 and guard < points_count * points_count do
guard = guard + 1
local n = #idx
local clipped = false
for i = 1, n do
local ia, ib, ic = idx[(i - 2) % n + 1], idx[i], idx[i % n + 1]
local a, b, c = points[ia], points[ib], points[ic]
if cross(a, b, c) * sign > 0 then
local inside = false
for j = 1, n do
local p = idx[j]
if p ~= ia and p ~= ib and p ~= ic then
local q = points[p]
if cross(a, b, q) * sign >= 0 and cross(b, c, q) * sign >= 0 and cross(c, a, q) * sign >= 0 then inside = true; break end
end
end
if not inside then
self:AddTriangleFilled(a, b, c, col)
table.remove(idx, i)
clipped = true
break
end
if area2 < 0.0 then
self:FlipNodeList()
end
self:BuildReflexes()
self:BuildEars()
end
function MT.ImTriangulator:BuildNodes(points, points_count)
local Type, Index, Pos, Next, Prev = self.Type, self.Index, self.Pos, self.Next, self.Prev
for i = 1, points_count do
Type[i] = ImTriangulatorNodeType.Convex
Index[i] = i - 1
Pos[i] = points[i] -- [Luau] reference, not a copy (points are not modified while triangulating)
Next[i] = i + 1
Prev[i] = i - 1
end
Prev[1] = points_count
Next[points_count] = 1
end
function MT.ImTriangulator:BuildReflexes()
local Pos, Next, Prev = self.Pos, self.Next, self.Prev
local n1 = self._Nodes
for _ = self._TrianglesLeft, 0, -1 do
if ImTriangulator_IsReflex(Pos[Prev[n1]], Pos[n1], Pos[Next[n1]]) then
self.Type[n1] = ImTriangulatorNodeType.Reflex
self._Reflexes:push_back(n1)
end
n1 = Next[n1]
end
end
function MT.ImTriangulator:BuildEars()
local Index, Pos, Next, Prev = self.Index, self.Pos, self.Next, self.Prev
local n1 = self._Nodes
for _ = self._TrianglesLeft, 0, -1 do
if self.Type[n1] == ImTriangulatorNodeType.Convex then
local n0, n2 = Prev[n1], Next[n1]
if self:IsEar(Index[n0], Index[n1], Index[n2], Pos[n0], Pos[n1], Pos[n2]) then
self.Type[n1] = ImTriangulatorNodeType.Ear
self._Ears:push_back(n1)
end
end
if not clipped then break end
n1 = Next[n1]
end
end
-- [Luau] out_triangle[3] is returned as 3 values (relative 0-based indexes)
function MT.ImTriangulator:GetNextTriangle()
if self._Ears.Size == 0 then
self:FlipNodeList()
local node = self._Nodes
for _ = self._TrianglesLeft, 0, -1 do
self.Type[node] = ImTriangulatorNodeType.Convex
node = self.Next[node]
end
self._Reflexes.Size = 0
self:BuildReflexes()
self:BuildEars()
-- If we still don't have ears, it means geometry is degenerated.
if self._Ears.Size == 0 then
-- Return first triangle available, mimicking the behavior of convex fill.
IM_ASSERT(self._TrianglesLeft > 0) -- Geometry is degenerated
self._Ears.Data[1] = self._Nodes
self._Ears.Size = 1
end
end
local ear = self._Ears.Data[self._Ears.Size]
self._Ears.Size = self._Ears.Size - 1
local Index, Next, Prev = self.Index, self.Next, self.Prev
local t0, t1, t2 = Index[Prev[ear]], Index[ear], Index[Next[ear]]
ImTriangulatorNode_Unlink(self, ear)
if ear == self._Nodes then
self._Nodes = Next[ear]
end
self:ReclassifyNode(Prev[ear])
self:ReclassifyNode(Next[ear])
self._TrianglesLeft = self._TrianglesLeft - 1
return t0, t1, t2
end
function MT.ImTriangulator:FlipNodeList()
local Next, Prev = self.Next, self.Prev
local nodes = self._Nodes
local prev = nodes
local temp = nodes
local current = Next[nodes]
Next[prev] = prev
Prev[prev] = prev
while current ~= nodes do
temp = Next[current]
Next[current] = prev
Prev[prev] = current
Next[nodes] = current
Prev[current] = nodes
prev = current
current = temp
end
self._Nodes = prev
end
-- A triangle is an ear is no other vertex is inside it. We can test reflexes vertices only (see reference algorithm)
function MT.ImTriangulator:IsEar(i0, i1, i2, v0, v1, v2)
local Index, Pos = self.Index, self.Pos
local data = self._Reflexes.Data
for p = 1, self._Reflexes.Size do
local reflex = data[p]
local idx = Index[reflex]
if idx ~= i0 and idx ~= i1 and idx ~= i2 then
if ImStd.ImTriangleContainsPoint(v0, v1, v2, Pos[reflex]) then
return false
end
end
end
return true
end
function MT.ImTriangulator:ReclassifyNode(n1)
-- Classify node
local type
local n0 = self.Prev[n1]
local n2 = self.Next[n1]
local Index, Pos = self.Index, self.Pos
if ImTriangulator_IsReflex(Pos[n0], Pos[n1], Pos[n2]) then
type = ImTriangulatorNodeType.Reflex
elseif self:IsEar(Index[n0], Index[n1], Index[n2], Pos[n0], Pos[n1], Pos[n2]) then
type = ImTriangulatorNodeType.Ear
else
type = ImTriangulatorNodeType.Convex
end
-- Update lists when a type changes
local n1_type = self.Type[n1]
if type == n1_type then
return
end
if n1_type == ImTriangulatorNodeType.Reflex then
self._Reflexes:find_erase_unsorted(Index[n1])
elseif n1_type == ImTriangulatorNodeType.Ear then
self._Ears:find_erase_unsorted(Index[n1])
end
if type == ImTriangulatorNodeType.Reflex then
self._Reflexes:push_back(n1)
elseif type == ImTriangulatorNodeType.Ear then
self._Ears:push_back(n1)
end
self.Type[n1] = type
end
local concave_triangulator = ImTriangulator() -- [Luau] reused scratch (see ImTriangulator())
-- Use ear-clipping algorithm to triangulate a simple polygon (no self-interaction, no holes).
-- (Reminder: we don't perform any coarse clipping/culling in ImDrawList layer!
-- It is up to caller to ensure not making costly calls that will be outside of visible area.
-- As concave fill is noticeably more expensive than other primitives, be mindful of this...
-- Caller can build AABB of points, and avoid filling if 'draw_list->_CmdHeader.ClipRect.Overlays(points_bb) == false')
--- @param points ImVec2[] # 1-based
--- @param points_count int
--- @param col ImU32
@native
function MT.ImDrawList:AddConcavePolyFilled(points, points_count, col)
if points_count < 3 or bit32.band(col, IM_COL32_A_MASK) == 0 then
return
end
local uv = self._Data.TexUvWhitePixel
local uv_x, uv_y = uv.x, uv.y
local triangulator = concave_triangulator
if bit32.band(self.Flags, ImDrawFlags.AAFill) ~= 0 then
-- Anti-aliased Fill
local AA_SIZE = self._FringeScale
local col_trans = bit32.band(col, bit32.bnot(IM_COL32_A_MASK))
local idx_count = (points_count - 2) * 3 + points_count * 6
local vtx_count = (points_count * 2)
PrimReserve(self, idx_count, vtx_count)
local vb = self.VtxBuffer.Buf
local ib = self.IdxBuffer.Data
local vw = self._VtxWritePtr
local iw = self._IdxWritePtr
-- Add indexes for fill
local vtx_inner_idx = self._VtxCurrentIdx
local vtx_outer_idx = self._VtxCurrentIdx + 1
triangulator:Init(points, points_count)
while triangulator._TrianglesLeft > 0 do
local t0, t1, t2 = triangulator:GetNextTriangle()
ib[iw + 0] = vtx_inner_idx + t0 * 2; ib[iw + 1] = vtx_inner_idx + t1 * 2; ib[iw + 2] = vtx_inner_idx + t2 * 2
iw = iw + 3
end
-- Compute normals
-- [Luau] scratch arrays (see AddPolyline) instead of _Data->TempBuffer. Indexes below are 1-based.
local temp_normals_x, temp_normals_y = poly_normals_x, poly_normals_y
local i0 = points_count
for i1 = 1, points_count do
local p0 = points[i0]
local p1 = points[i1]
local dx, dy = IM_NORMALIZE2F_OVER_ZERO(p1.x - p0.x, p1.y - p0.y)
temp_normals_x[i0] = dy
temp_normals_y[i0] = -dx
i0 = i1
end
i0 = points_count
for i1 = 1, points_count do
-- Average normals
local dm_x, dm_y = IM_FIXNORMAL2F((temp_normals_x[i0] + temp_normals_x[i1]) * 0.5, (temp_normals_y[i0] + temp_normals_y[i1]) * 0.5)
dm_x = dm_x * AA_SIZE * 0.5
dm_y = dm_y * AA_SIZE * 0.5
-- Add vertices
local p1 = points[i1]
WV(vb, vw, p1.x - dm_x, p1.y - dm_y, uv_x, uv_y, col) -- Inner
WV(vb, vw + 1, p1.x + dm_x, p1.y + dm_y, uv_x, uv_y, col_trans) -- Outer
vw = vw + 2
-- Add indexes for fringes
local e0, e1 = (i0 - 1) * 2, (i1 - 1) * 2
ib[iw + 0] = vtx_inner_idx + e1; ib[iw + 1] = vtx_inner_idx + e0; ib[iw + 2] = vtx_outer_idx + e0
ib[iw + 3] = vtx_outer_idx + e0; ib[iw + 4] = vtx_outer_idx + e1; ib[iw + 5] = vtx_inner_idx + e1
iw = iw + 6
i0 = i1
end
self._VtxWritePtr = vw
self._IdxWritePtr = iw
self._VtxCurrentIdx = self._VtxCurrentIdx + vtx_count
else
-- Non Anti-aliased Fill
local idx_count = (points_count - 2) * 3
local vtx_count = points_count
PrimReserve(self, idx_count, vtx_count)
local vb = self.VtxBuffer.Buf
local ib = self.IdxBuffer.Data
local vw = self._VtxWritePtr
local iw = self._IdxWritePtr
for i = 1, vtx_count do
local p = points[i]
WV(vb, vw, p.x, p.y, uv_x, uv_y, col)
vw = vw + 1
end
local base_idx = self._VtxCurrentIdx
triangulator:Init(points, points_count)
while triangulator._TrianglesLeft > 0 do
local t0, t1, t2 = triangulator:GetNextTriangle()
ib[iw + 0] = base_idx + t0; ib[iw + 1] = base_idx + t1; ib[iw + 2] = base_idx + t2
iw = iw + 3
end
self._VtxWritePtr = vw
self._IdxWritePtr = iw
self._VtxCurrentIdx = base_idx + vtx_count
end
if #idx == 3 then self:AddTriangleFilled(points[idx[1]], points[idx[2]], points[idx[3]], col) end
end
function MT.ImDrawList:PathFillConcave(col)
+12
View File
@@ -461,6 +461,18 @@ function ImMul(lhs, rhs)
return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y)
end
--- @param a ImVec2
--- @param b ImVec2
--- @param c ImVec2
--- @return float
function ImTriangleArea(a, b, c) return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5 end
--- @param a ImVec2
--- @param b ImVec2
--- @param c ImVec2
--- @return boolean
function ImTriangleIsClockwise(a, b, c) return ((b.x - a.x) * (c.y - b.y)) - ((c.x - b.x) * (b.y - a.y)) > 0.0 end
--- @param str char[]
--- @param begin? int
function ImStd.ImStrlen(str, begin)