diff --git a/build/ImGui.linemap.json b/build/ImGui.linemap.json index 7da51a3..45bbb02 100644 --- a/build/ImGui.linemap.json +++ b/build/ImGui.linemap.json @@ -1 +1 @@ -[[12, "imgui.lua"], [13741, "imgui_demo.lua"], [14674, "imgui_demo_2.lua"], [17749, "imgui_demo_apps.lua"], [19008, "imgui_demo_tools.lua"], [20334, "imgui_demo_widgets.lua"], [22258, "imgui_docking.lua"], [25386, "imgui_dragdrop.lua"], [25678, "imgui_draw.lua"], [30900, "imgui_h.lua"], [33113, "imgui_impl_roblox.lua"], [33937, "imgui_impl_roblox_fonts.lua"], [40340, "imgui_internal.lua"], [43510, "imgui_tables.lua"], [47857, "imgui_tabs.lua"], [49024, "imgui_widgets.lua"], [57548, "imstb_rectpack.lua"], [57994, "imstb_textedit.lua"], [59235, "imstb_truetype.lua"], [61703, "imstd_minstdio.lua"]] \ No newline at end of file +[[12, "imgui.lua"], [13741, "imgui_demo.lua"], [14674, "imgui_demo_2.lua"], [17749, "imgui_demo_apps.lua"], [19008, "imgui_demo_tools.lua"], [20334, "imgui_demo_widgets.lua"], [22258, "imgui_docking.lua"], [25386, "imgui_dragdrop.lua"], [25678, "imgui_draw.lua"], [30900, "imgui_h.lua"], [33066, "imgui_impl_roblox.lua"], [33890, "imgui_impl_roblox_fonts.lua"], [40293, "imgui_internal.lua"], [43449, "imgui_tables.lua"], [47796, "imgui_tabs.lua"], [48963, "imgui_widgets.lua"], [57487, "imstb_rectpack.lua"], [57933, "imstb_textedit.lua"], [59174, "imstb_truetype.lua"], [61642, "imstd_minstdio.lua"]] \ No newline at end of file diff --git a/build/ImGui.luau b/build/ImGui.luau index 6d7df7e..29dd9fa 100644 --- a/build/ImGui.luau +++ b/build/ImGui.luau @@ -21962,7 +21962,7 @@ local function StyleCopy(dst, src) elseif type(v) == "table" and getmetatable(v) ~= nil and type(v[1]) == "number" then local c = dst[k] if type(c) ~= "table" then c = setmetatable({}, getmetatable(v)); dst[k] = c end - for i = 1, #v do rawset(c, i, v[i]) end + for _, key in ipairs({ "x", "y", "z", "w" }) do if rawget(v, key) ~= nil then c[key] = v[key] end end else dst[k] = v end @@ -26017,9 +26017,9 @@ function ImGui.ShadeVertsTransformPos(draw_list, vert_start_idx, vert_end_idx, p local pix, piy, pox, poy = pivot_in.x, pivot_in.y, pivot_out.x, pivot_out.y for i = vert_start_idx, vert_end_idx - 1 do local pos = data[i][1] - local x, y = pos[1] - pix, pos[2] - piy - pos[1] = x * cos_a - y * sin_a + pox - pos[2] = x * sin_a + y * cos_a + poy + local x, y = pos.x - pix, pos.y - piy + pos.x = x * cos_a - y * sin_a + pox + pos.y = x * sin_a + y * cos_a + poy end end @@ -29387,7 +29387,7 @@ function MT.ImDrawList:PrimRect(a, c, col) ImVec2_Copy(vtx_data[vtx_write_ptr + 0][2], uv) vtx_data[vtx_write_ptr + 0][3] = col - ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][1], c[1], a[2]) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][1], c.x, a.y) ImVec2_Copy(vtx_data[vtx_write_ptr + 1][2], uv) vtx_data[vtx_write_ptr + 1][3] = col @@ -29395,7 +29395,7 @@ function MT.ImDrawList:PrimRect(a, c, col) ImVec2_Copy(vtx_data[vtx_write_ptr + 2][2], uv) vtx_data[vtx_write_ptr + 2][3] = col - ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][1], a[1], c[2]) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][1], a.x, c.y) ImVec2_Copy(vtx_data[vtx_write_ptr + 3][2], uv) vtx_data[vtx_write_ptr + 3][3] = col @@ -29427,16 +29427,16 @@ function MT.ImDrawList:PrimRectUV(a, c, uv_a, uv_c, col) ImVec2_Copy(vtx_data[vtx_write_ptr + 0][2], uv_a) vtx_data[vtx_write_ptr + 0][3] = col - ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][1], c[1], a[2]) - ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][2], uv_c[1], uv_a[2]) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][1], c.x, a.y) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][2], uv_c.x, uv_a.y) vtx_data[vtx_write_ptr + 1][3] = col ImVec2_Copy(vtx_data[vtx_write_ptr + 2][1], c) ImVec2_Copy(vtx_data[vtx_write_ptr + 2][2], uv_c) vtx_data[vtx_write_ptr + 2][3] = col - ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][1], a[1], c[2]) - ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][2], uv_a[1], uv_c[2]) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][1], a.x, c.y) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][2], uv_a.x, uv_c.y) vtx_data[vtx_write_ptr + 3][3] = col self._VtxWritePtr = vtx_write_ptr + 4 @@ -29492,11 +29492,11 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) local i2 = (i1 == points_count) and 1 or i1 + 1 local p1 = points[i1] local p2 = points[i2] - local dx = p2[1] - p1[1] - local dy = p2[2] - p1[2] + local dx = p2.x - p1.x + local dy = p2.y - p1.y dx, dy = IM_NORMALIZE2F_OVER_ZERO(dx, dy) - temp_normals[i1][1] = dy - temp_normals[i1][2] = -dx + temp_normals[i1].x = dy + temp_normals[i1].y = -dx end if not closed then ImVec2_Copy(temp_normals[points_count], temp_normals[points_count - 1]) @@ -29524,18 +29524,18 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) local idx2 = (i1 == points_count) and self._VtxCurrentIdx or (idx1 + (use_texture and 2 or 3)) -- Average normals - local dm_x = (temp_normals[i1][1] + temp_normals[i2][1]) * 0.5 - local dm_y = (temp_normals[i1][2] + temp_normals[i2][2]) * 0.5 + local dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5 + local dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5 dm_x, dm_y = IM_FIXNORMAL2F(dm_x, dm_y) dm_x = dm_x * half_draw_size dm_y = dm_y * half_draw_size -- Add temporary vertices for the outer edges local out_off = (i2 - 1) * 2 - temp_points[temp_points_start + out_off + 0][1] = points[i2][1] + dm_x - temp_points[temp_points_start + out_off + 0][2] = points[i2][2] + dm_y - temp_points[temp_points_start + out_off + 1][1] = points[i2][1] - dm_x - temp_points[temp_points_start + out_off + 1][2] = points[i2][2] - dm_y + temp_points[temp_points_start + out_off + 0].x = points[i2].x + dm_x + temp_points[temp_points_start + out_off + 0].y = points[i2].y + dm_y + temp_points[temp_points_start + out_off + 1].x = points[i2].x - dm_x + temp_points[temp_points_start + out_off + 1].y = points[i2].y - dm_y if use_texture then -- Add indices for two triangles @@ -29603,8 +29603,8 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) local idx2 = (i1 == points_count) and self._VtxCurrentIdx or (idx1 + 4) -- Average normals - local dm_x = (temp_normals[i1][1] + temp_normals[i2][1]) * 0.5 - local dm_y = (temp_normals[i1][2] + temp_normals[i2][2]) * 0.5 + local dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5 + local dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5 dm_x, dm_y = IM_FIXNORMAL2F(dm_x, dm_y) local dm_out_x = dm_x * (half_inner_thickness + AA_SIZE) local dm_out_y = dm_y * (half_inner_thickness + AA_SIZE) @@ -29613,14 +29613,14 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) -- Add temporary vertices local out_off = (i2 - 1) * 4 - temp_points[temp_points_start + out_off + 0][1] = points[i2][1] + dm_out_x - temp_points[temp_points_start + out_off + 0][2] = points[i2][2] + dm_out_y - temp_points[temp_points_start + out_off + 1][1] = points[i2][1] + dm_in_x - temp_points[temp_points_start + out_off + 1][2] = points[i2][2] + dm_in_y - temp_points[temp_points_start + out_off + 2][1] = points[i2][1] - dm_in_x - temp_points[temp_points_start + out_off + 2][2] = points[i2][2] - dm_in_y - temp_points[temp_points_start + out_off + 3][1] = points[i2][1] - dm_out_x - temp_points[temp_points_start + out_off + 3][2] = points[i2][2] - dm_out_y + temp_points[temp_points_start + out_off + 0].x = points[i2].x + dm_out_x + temp_points[temp_points_start + out_off + 0].y = points[i2].y + dm_out_y + temp_points[temp_points_start + out_off + 1].x = points[i2].x + dm_in_x + temp_points[temp_points_start + out_off + 1].y = points[i2].y + dm_in_y + temp_points[temp_points_start + out_off + 2].x = points[i2].x - dm_in_x + temp_points[temp_points_start + out_off + 2].y = points[i2].y - dm_in_y + temp_points[temp_points_start + out_off + 3].x = points[i2].x - dm_out_x + temp_points[temp_points_start + out_off + 3].y = points[i2].y - dm_out_y -- Add indices local idx_write_ptr = self._IdxWritePtr @@ -29658,17 +29658,17 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) local p1 = points[i1] local p2 = points[i2] - local dx = p2[1] - p1[1] - local dy = p2[2] - p1[2] + local dx = p2.x - p1.x + local dy = p2.y - p1.y dx, dy = IM_NORMALIZE2F_OVER_ZERO(dx, dy) dx = dx * (thickness * 0.5) dy = dy * (thickness * 0.5) local vtx_write_ptr = self._VtxWritePtr - vtx_data[vtx_write_ptr + 0][1][1] = p1[1] + dy; vtx_data[vtx_write_ptr + 0][1][2] = p1[2] - dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 0][2], opaque_uv); vtx_data[vtx_write_ptr + 0][3] = col - vtx_data[vtx_write_ptr + 1][1][1] = p2[1] + dy; vtx_data[vtx_write_ptr + 1][1][2] = p2[2] - dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 1][2], opaque_uv); vtx_data[vtx_write_ptr + 1][3] = col - vtx_data[vtx_write_ptr + 2][1][1] = p2[1] - dy; vtx_data[vtx_write_ptr + 2][1][2] = p2[2] + dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 2][2], opaque_uv); vtx_data[vtx_write_ptr + 2][3] = col - vtx_data[vtx_write_ptr + 3][1][1] = p1[1] - dy; vtx_data[vtx_write_ptr + 3][1][2] = p1[2] + dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 3][2], opaque_uv); vtx_data[vtx_write_ptr + 3][3] = col + vtx_data[vtx_write_ptr + 0][1].x = p1.x + dy; vtx_data[vtx_write_ptr + 0][1].y = p1.y - dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 0][2], opaque_uv); vtx_data[vtx_write_ptr + 0][3] = col + vtx_data[vtx_write_ptr + 1][1].x = p2.x + dy; vtx_data[vtx_write_ptr + 1][1].y = p2.y - dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 1][2], opaque_uv); vtx_data[vtx_write_ptr + 1][3] = col + vtx_data[vtx_write_ptr + 2][1].x = p2.x - dy; vtx_data[vtx_write_ptr + 2][1].y = p2.y + dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 2][2], opaque_uv); vtx_data[vtx_write_ptr + 2][3] = col + vtx_data[vtx_write_ptr + 3][1].x = p1.x - dy; vtx_data[vtx_write_ptr + 3][1].y = p1.y + dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 3][2], opaque_uv); vtx_data[vtx_write_ptr + 3][3] = col self._VtxWritePtr = vtx_write_ptr + 4 local idx_write_ptr = self._IdxWritePtr @@ -30405,10 +30405,10 @@ function MT.ImFont:RenderText(draw_list, size, pos, col, clip_rect, text, text_b local glyph_col = glyph.Colored and color_untinted or col do - local vtx0 = vtx_data[vtx_write + 0]; vtx0[1][1] = x1; vtx0[1][2] = y1; vtx0[3] = glyph_col; vtx0[2][1] = u1; vtx0[2][2] = v1; - local vtx1 = vtx_data[vtx_write + 1]; vtx1[1][1] = x2; vtx1[1][2] = y1; vtx1[3] = glyph_col; vtx1[2][1] = u2; vtx1[2][2] = v1; - local vtx2 = vtx_data[vtx_write + 2]; vtx2[1][1] = x2; vtx2[1][2] = y2; vtx2[3] = glyph_col; vtx2[2][1] = u2; vtx2[2][2] = v2; - local vtx3 = vtx_data[vtx_write + 3]; vtx3[1][1] = x1; vtx3[1][2] = y2; vtx3[3] = glyph_col; vtx3[2][1] = u1; vtx3[2][2] = v2; + local vtx0 = vtx_data[vtx_write + 0]; vtx0[1].x = x1; vtx0[1].y = y1; vtx0[3] = glyph_col; vtx0[2].x = u1; vtx0[2].y = v1; + local vtx1 = vtx_data[vtx_write + 1]; vtx1[1].x = x2; vtx1[1].y = y1; vtx1[3] = glyph_col; vtx1[2].x = u2; vtx1[2].y = v1; + local vtx2 = vtx_data[vtx_write + 2]; vtx2[1].x = x2; vtx2[1].y = y2; vtx2[3] = glyph_col; vtx2[2].x = u2; vtx2[2].y = v2; + local vtx3 = vtx_data[vtx_write + 3]; vtx3[1].x = x1; vtx3[1].y = y2; vtx3[3] = glyph_col; vtx3[2].x = u1; vtx3[2].y = v2; idx_data[idx_write + 0] = vtx_index; idx_data[idx_write + 1] = vtx_index + 1; idx_data[idx_write + 2] = vtx_index + 2; idx_data[idx_write + 3] = vtx_index; idx_data[idx_write + 4] = vtx_index + 2; idx_data[idx_write + 5] = vtx_index + 3; vtx_write = vtx_write + 4 @@ -31092,8 +31092,8 @@ ImGuiMouseCursor = --- @return ImTextureRect function ImTextureRect(x, y, w, h) return { x = x, y = y, w = w, h = h } end --- This structure supports indexing on string keys `x`, `y` and number keys 1, 2. --- But note that the former is likely to be more expensive. +-- [Luau] Stored as named fields {x=, y=} so the common `.x`/`.y` access is a plain table read (no metamethod call). +-- Numeric keys 1, 2 still work through the metatable, but are slower: prefer .x/.y in hot code. --- @class ImVec2 --- @operator add(ImVec2): ImVec2 --- @operator sub(ImVec2): ImVec2 @@ -31101,146 +31101,97 @@ function ImTextureRect(x, y, w, h) return { x = x, y = y, w = w, h = h } end --- @operator mul(ImVec2): ImVec2 --- @operator div(number): ImVec2 --- @operator div(ImVec2): ImVec2 ---- @field [1] number ---- @field [2] number --- @field x number --- @field y number local IM_VEC2 = {} +local VEC2_KEYS = { "x", "y" } ---- @param t ImVec2 ---- @param k string IM_VEC2.__index = function(t, k) - if k == "x" then return rawget(t, 1) - elseif k == "y" then return rawget(t, 2) - end + local n = VEC2_KEYS[k] + if n then return rawget(t, n) end end ---- @param t ImVec2 ---- @param k string ---- @param v number IM_VEC2.__newindex = function(t, k, v) - if k == "x" then rawset(t, 1, v) - elseif k == "y" then rawset(t, 2, v) - else IM_ASSERT(false) - end + local n = VEC2_KEYS[k] + IM_ASSERT(n ~= nil) + rawset(t, n, v) end --- @param x? number --- @param y? number --- @return ImVec2 --- @nodiscard -function ImVec2(x, y) return setmetatable({x or 0, y or 0}, IM_VEC2) end +function ImVec2(x, y) return setmetatable({ x = x or 0, y = y or 0 }, IM_VEC2) end -function IM_VEC2.__add(lhs, rhs) return ImVec2(lhs[1] + rhs[1], lhs[2] + rhs[2]) end -function IM_VEC2.__sub(lhs, rhs) return ImVec2(lhs[1] - rhs[1], lhs[2] - rhs[2]) end +function IM_VEC2.__add(lhs, rhs) return setmetatable({ x = lhs.x + rhs.x, y = lhs.y + rhs.y }, IM_VEC2) end +function IM_VEC2.__sub(lhs, rhs) return setmetatable({ x = lhs.x - rhs.x, y = lhs.y - rhs.y }, IM_VEC2) end ---- @overload fun(lhs: ImVec2, rhs: number): ImVec2 ---- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 function IM_VEC2.__mul(lhs, rhs) - if type(lhs) == "table" and type(rhs) == "number" then return ImVec2(lhs[1] * rhs, lhs[2] * rhs) - elseif type(lhs) == "table" and type(rhs) == "table" then return ImVec2(lhs[1] * rhs[1], lhs[2] * rhs[2]) - end + if type(rhs) == "number" then return setmetatable({ x = lhs.x * rhs, y = lhs.y * rhs }, IM_VEC2) end + return setmetatable({ x = lhs.x * rhs.x, y = lhs.y * rhs.y }, IM_VEC2) end ---- @overload fun(lhs: ImVec2, rhs: number): ImVec2 ---- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 function IM_VEC2.__div(lhs, rhs) - if type(lhs) == "table" and type(rhs) == "number" then return ImVec2(lhs[1] / rhs, lhs[2] / rhs) - elseif type(lhs) == "table" and type(rhs) == "table" then return ImVec2(lhs[1] / rhs[1], lhs[2] / rhs[2]) - end + if type(rhs) == "number" then return setmetatable({ x = lhs.x / rhs, y = lhs.y / rhs }, IM_VEC2) end + return setmetatable({ x = lhs.x / rhs.x, y = lhs.y / rhs.y }, IM_VEC2) end -function IM_VEC2.__eq(lhs, rhs) return lhs[1] == rhs[1] and lhs[2] == rhs[2] end +function IM_VEC2.__eq(lhs, rhs) return lhs.x == rhs.x and lhs.y == rhs.y end function IM_VEC2:__tostring() return string.format("ImVec2(%g, %g)", self.x, self.y) end --- @param dest ImVec2 --- @param src ImVec2 -function ImVec2_Copy(dest, src) dest[1] = src[1]; dest[2] = src[2] end +function ImVec2_Copy(dest, src) dest.x = src.x; dest.y = src.y end ---- @param dest ImVec2 ---- @param src_x number ---- @param src_y number -function ImVec2_CopyV(dest, src_x, src_y) dest[1] = src_x; dest[2] = src_y end +function ImVec2_CopyV(dest, src_x, src_y) dest.x = src_x; dest.y = src_y end ---- @param v ImVec2 ---- @param add_x number ---- @param add_y number -function ImVec2_AddVA(v, add_x, add_y) return v[1] + add_x, v[2] + add_y end +function ImVec2_AddVA(v, add_x, add_y) return v.x + add_x, v.y + add_y end ---- @param v ImVec2 ---- @param sub_x number ---- @param sub_y number -function ImVec2_SubVA(v, sub_x, sub_y) return v[1] - sub_x, v[2] - sub_y end +function ImVec2_SubVA(v, sub_x, sub_y) return v.x - sub_x, v.y - sub_y end ---- @param a ImVec2 ---- @param scalar number -function ImVec2_MulVX(a, scalar) - return a[1] * scalar, a[2] * scalar -end +function ImVec2_MulVX(a, scalar) return a.x * scalar, a.y * scalar end --- An inlined version of `ImVec2_Copy` currently for use in certain ImVector `push_back` ---- @param t ImVec2[] ---- @param k int ---- @param v ImVec2 -local function ImVec2_TCopy(t, k, v) local dest = t[k]; dest[1] = v[1]; dest[2] = v[2]; end +local function ImVec2_TCopy(t, k, v) local dest = t[k]; dest.x = v.x; dest.y = v.y; end --- This structure supports indexing on string keys `x`, `y`, `z`, `w` and number keys 1, 2, 3, 4. --- But note that the former is likely to be more expensive. +-- [Luau] Same layout as ImVec2: named fields x, y, z, w; numeric keys 1..4 go through the metatable. --- @class ImVec4 --- @operator add(ImVec4): ImVec4 --- @operator sub(ImVec4): ImVec4 --- @operator mul(number): ImVec4 ---- @field [1] number ---- @field [2] number ---- @field [3] number ---- @field [4] number --- @field x number --- @field y number --- @field z number --- @field w number local IM_VEC4 = {} +local VEC4_KEYS = { "x", "y", "z", "w" } ---- @param t ImVec4 ---- @param k string IM_VEC4.__index = function(t, k) - if k == "x" then return rawget(t, 1) - elseif k == "y" then return rawget(t, 2) - elseif k == "z" then return rawget(t, 3) - elseif k == "w" then return rawget(t, 4) - end + local n = VEC4_KEYS[k] + if n then return rawget(t, n) end end ---- @param t ImVec4 ---- @param k string ---- @param v number IM_VEC4.__newindex = function(t, k, v) - if k == "x" then rawset(t, 1, v) - elseif k == "y" then rawset(t, 2, v) - elseif k == "z" then rawset(t, 3, v) - elseif k == "w" then rawset(t, 4, v) - else IM_ASSERT(false) - end + local n = VEC4_KEYS[k] + IM_ASSERT(n ~= nil) + rawset(t, n, v) end ---- @param x? number ---- @param y? number ---- @param z? number ---- @param w? number --- @return ImVec4 --- @nodiscard -function ImVec4(x, y, z, w) return setmetatable({x or 0, y or 0, z or 0, w or 0}, IM_VEC4) end +function ImVec4(x, y, z, w) return setmetatable({ x = x or 0, y = y or 0, z = z or 0, w = w or 0 }, IM_VEC4) end -function IM_VEC4.__add(lhs, rhs) return ImVec4(lhs[1] + rhs[1], lhs[2] + rhs[2], lhs[3] + rhs[3], lhs[4] + rhs[4]) end -function IM_VEC4.__sub(lhs, rhs) return ImVec4(lhs[1] - rhs[1], lhs[2] - rhs[2], lhs[3] - rhs[3], lhs[4] - rhs[4]) end -function IM_VEC4.__mul(lhs, rhs) return ImVec4(lhs[1] * rhs, lhs[2] * rhs, lhs[3] * rhs, lhs[4] * rhs) end -function IM_VEC4.__eq(lhs, rhs) return lhs[1] == rhs[1] and lhs[2] == rhs[2] and lhs[3] == rhs[3] and lhs[4] == rhs[4] end +function IM_VEC4.__add(lhs, rhs) return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w) end +function IM_VEC4.__sub(lhs, rhs) return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w) end +function IM_VEC4.__mul(lhs, rhs) return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs) end +function IM_VEC4.__eq(lhs, rhs) return lhs.x == rhs.x and lhs.y == rhs.y and lhs.z == rhs.z and lhs.w == rhs.w end function IM_VEC4:__tostring() return string.format("ImVec4(%g, %g, %g, %g)", self.x, self.y, self.z, self.w) end --- @param dest ImVec4 --- @param src ImVec4 -function ImVec4_Copy(dest, src) dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest[4] = src[4] end +function ImVec4_Copy(dest, src) dest.x = src.x; dest.y = src.y; dest.z = src.z; dest.w = src.w end --- A compact ImVector clone --- @class ImVector @@ -31255,8 +31206,10 @@ local IM_VECTOR = {} --- @param k string|int --- @return any IM_VECTOR.__index = function(t, k) + local m = IM_VECTOR[k] -- methods first (hot path) + if m ~= nil then return m end if k == "Data" then return nil end -- Data has already been discarded - return IM_VECTOR[k] or t.Data[IM_ASSERT(k >= 1 and k <= t.Size) or k] -- if the mt access turns out nil, the k must be int index into Data + return t.Data[IM_ASSERT(k >= 1 and k <= t.Size) or k] -- if the mt access turns out nil, the k must be int index into Data end --- @param t ImVector @@ -33455,9 +33408,9 @@ end -- Generic triangle: per-vertex colour + uv, top-left fill rule, clipped to [cx0, cx1) x [cy0, cy1) @native local function DrawTriangle(va, vb, vc, t, cx0, cy0, cx1, cy1, ox, oy) - local x0, y0 = va[1][1] - ox, va[1][2] - oy - local x1, y1 = vb[1][1] - ox, vb[1][2] - oy - local x2, y2 = vc[1][1] - ox, vc[1][2] - oy + local x0, y0 = va[1].x - ox, va[1].y - oy + local x1, y1 = vb[1].x - ox, vb[1].y - oy + local x2, y2 = vc[1].x - ox, vc[1].y - oy local area = (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0) if area == 0 then return end if area < 0 then -- make the winding consistent so "inside" means all edge functions >= 0 @@ -33482,7 +33435,7 @@ local function DrawTriangle(va, vb, vc, t, cx0, cy0, cx1, cy1, ox, oy) local ra, ga, ba, aa = UnpackColor(va[3]) local rb, gb, bb, ab = UnpackColor(vb[3]) local rc, gc, bc, ac = UnpackColor(vc[3]) - local ua, vva, ub, vvb, uc, vvc = va[2][1], va[2][2], vb[2][1], vb[2][2], vc[2][1], vc[2][2] + local ua, vva, ub, vvb, uc, vvc = va[2].x, va[2].y, vb[2].x, vb[2].y, vc[2].x, vc[2].y local textured = t and not (ua == ub and ua == uc and vva == vvb and vva == vvc) if t and not textured then -- constant uv (e.g. the atlas white pixel): fold the texel into the vertex colours @@ -33533,12 +33486,12 @@ end @native local function TryDrawRect(va, vb, vc, vd, t, cx0, cy0, cx1, cy1, ox, oy) local pa, pb, pc, pd = va[1], vb[1], vc[1], vd[1] - if not (pa[2] == pb[2] and pb[1] == pc[1] and pc[2] == pd[2] and pd[1] == pa[1] and pa[1] < pb[1] and pa[2] < pd[2]) then return false end + if not (pa.y == pb.y and pb.x == pc.x and pc.y == pd.y and pd.x == pa.x and pa.x < pb.x and pa.y < pd.y) then return false end local col = va[3] if vb[3] ~= col or vc[3] ~= col or vd[3] ~= col then return false end local ta, tb, tc, td = va[2], vb[2], vc[2], vd[2] - if not (tb[1] == tc[1] and tb[2] == ta[2] and td[1] == ta[1] and td[2] == tc[2]) then return false end - DrawRect(pa[1] - ox, pa[2] - oy, pc[1] - ox, pc[2] - oy, ta[1], ta[2], tc[1], tc[2], col, t, cx0, cy0, cx1, cy1) + if not (tb.x == tc.x and tb.y == ta.y and td.x == ta.x and td.y == tc.y) then return false end + DrawRect(pa.x - ox, pa.y - oy, pc.x - ox, pc.y - oy, ta.x, ta.y, tc.x, tc.y, col, t, cx0, cy0, cx1, cy1) return true end @@ -33557,8 +33510,8 @@ local pr_cx0, pr_cy0, pr_cx1, pr_cy1 = {}, {}, {}, {} -- clip (screen pixels) @native local function HashVertex(h1, h2, v) local p, u, c = v[1], v[2], v[3] - local x, y = p[1], p[2] - local uv = u[1] * 8192 + u[2] + local x, y = p.x, p.y + local uv = u.x * 8192 + u.y h1 = (h1 * 48271 + x * 4096 + y) % P1 h1 = (h1 * 48271 + uv * 4096) % P1 h1 = (h1 * 48271 + c) % P1 @@ -33670,22 +33623,22 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data) local d = vtx[vo + idx[i + 5]] local pd = d[1] -- axis aligned quad (TL, TR, BR, BL) with one colour and a matching uv rect - if pa[2] == pb[2] and pb[1] == pc[1] and pc[2] == pd[2] and pd[1] == pa[1] and pa[1] < pb[1] and pa[2] < pd[2] then + if pa.y == pb.y and pb.x == pc.x and pc.y == pd.y and pd.x == pa.x and pa.x < pb.x and pa.y < pd.y then local col = va[3] local ta, tb, tc, td = va[2], vb[2], vc[2], d[2] if vb[3] == col and vc[3] == col and d[3] == col - and tb[1] == tc[1] and tb[2] == ta[2] and td[1] == ta[1] and td[2] == tc[2] then + and tb.x == tc.x and tb.y == ta.y and td.x == ta.x and td.y == tc.y then vd = d - bx0, by0 = ceil(pa[1] - ox - 0.5), ceil(pa[2] - oy - 0.5) - bx1, by1 = ceil(pc[1] - ox - 0.5), ceil(pc[2] - oy - 0.5) + bx0, by0 = ceil(pa.x - ox - 0.5), ceil(pa.y - oy - 0.5) + bx1, by1 = ceil(pc.x - ox - 0.5), ceil(pc.y - oy - 0.5) end end end if vd then i = i + 6 else - bx0, by0 = floor(min(pa[1], pb[1], pc[1]) - ox), floor(min(pa[2], pb[2], pc[2]) - oy) - bx1, by1 = ceil(max(pa[1], pb[1], pc[1]) - ox) + 1, ceil(max(pa[2], pb[2], pc[2]) - oy) + 1 + bx0, by0 = floor(min(pa.x, pb.x, pc.x) - ox), floor(min(pa.y, pb.y, pc.y) - oy) + bx1, by1 = ceil(max(pa.x, pb.x, pc.x) - ox) + 1, ceil(max(pa.y, pb.y, pc.y) - oy) + 1 i = i + 3 end if bx0 < cx0 then bx0 = cx0 end @@ -33751,7 +33704,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data) local va, vc, vd = pr_a[p], pr_c[p], pr_d[p] if vd then local pa, pc, ta, tc = va[1], vc[1], va[2], vc[2] - DrawRect(pa[1] - tox, pa[2] - toy, pc[1] - tox, pc[2] - toy, ta[1], ta[2], tc[1], tc[2], va[3], pr_t[p], cx0, cy0, cx1, cy1) + DrawRect(pa.x - tox, pa.y - toy, pc.x - tox, pc.y - toy, ta.x, ta.y, tc.x, tc.y, va[3], pr_t[p], cx0, cy0, cx1, cy1) else DrawTriangle(va, pr_b[p], vc, pr_t[p], cx0, cy0, cx1, cy1, tox, toy) end @@ -40480,17 +40433,15 @@ end --- @overload fun(lhs: number, rhs: number): number --- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 function ImMin(lhs, rhs) - if type(lhs) == "number" and type(rhs) == "number" then return mathMin(lhs, rhs) - elseif type(lhs) == "table" and type(rhs) == "table" then return ImVec2(mathMin(lhs[1], rhs[1]), mathMin(lhs[2], rhs[2])) - end + if type(lhs) == "number" then return mathMin(lhs, rhs) end + return ImVec2(mathMin(lhs.x, rhs.x), mathMin(lhs.y, rhs.y)) end --- @overload fun(lhs: number, rhs: number): number --- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 function ImMax(lhs, rhs) - if type(lhs) == "number" and type(rhs) == "number" then return mathMax(lhs, rhs) - elseif type(lhs) == "table" and type(rhs) == "table" then return ImVec2(mathMax(lhs[1], rhs[1]), mathMax(lhs[2], rhs[2])) - end + if type(lhs) == "number" then return mathMax(lhs, rhs) end + return ImVec2(mathMax(lhs.x, rhs.x), mathMax(lhs.y, rhs.y)) end --- @param base table @@ -40502,7 +40453,7 @@ ImStd.ImQsort = function(base, count, cmp_func) if count > 0 then t_sort(base, c --- @overload fun(v: ImVec2, mn: ImVec2, mx: ImVec2): ImVec2 function ImClamp(v, mn, mx) if type(v) == "number" and type(mn) == "number" and type(mx) == "number" then return mathMin(mathMax(v, mn), mx) - elseif type(v) == "table" and type(mn) == "table" and type(mx) == "table" then return ImVec2(mathMax(mn[1], mathMin(v[1], mx[1])), mathMax(mn[2], mathMin(v[2], mx[2]))) + elseif type(v) == "table" and type(mn) == "table" and type(mx) == "table" then return ImVec2(mathMax(mn.x, mathMin(v.x, mx.x)), mathMax(mn.y, mathMin(v.y, mx.y))) end end @@ -40511,8 +40462,8 @@ end --- @overload fun(a: ImVec2, b: ImVec2, t: ImVec2): ImVec2 function ImLerp(a, b, t) if type(a) == "number" and type(b) == "number" and type(t) == "number" then return ((a) + ((b) - (a)) * (t)) - elseif type(a) == "table" and type(b) == "table" and type(t) == "number" then return ImVec2(a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t) - elseif type(a) == "table" and type(b) == "table" and type(t) == "table" then return ImVec2(a[1] + (b[1] - a[1]) * t[1], a[2] + (b[2] - a[2]) * t[2]) + elseif type(a) == "table" and type(b) == "table" and type(t) == "number" then return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t) + elseif type(a) == "table" and type(b) == "table" and type(t) == "table" then return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y) end end @@ -40522,7 +40473,7 @@ local function _Trunc(val) if val >= 0 then return mathFloor(val) else return ma --- @overload fun(v: ImVec2): ImVec2 function ImTrunc(v) if type(v) == "number" then return _Trunc(v) - elseif type(v) == "table" then return ImVec2(_Trunc(v[1]), _Trunc(v[2])) + elseif type(v) == "table" then return ImVec2(_Trunc(v.x), _Trunc(v.y)) end end @@ -41012,150 +40963,138 @@ end --- @field Min ImVec2 --- @field Max ImVec2 local IM_RECT = {} +setmetatable(IM_RECT, { __index = function(_, k) if k ~= "Min" and k ~= "Max" then error("ImRect: unknown key " .. tostring(k), 2) end end }) --- @param t ImRect --- @param k string -IM_RECT.__index = function(t, k) - local method = IM_RECT[k] - if method ~= nil then return method end - if k == "Min" then return rawget(t, 1) - elseif k == "Max" then return rawget(t, 2) - end -end +IM_RECT.__index = IM_RECT -- [Luau] plain table: fast method lookup. Use r.Min / r.Max (numeric r[1]/r[2] are not supported) ---- @param t ImRect ---- @param k string ---- @param v ImVec2 -IM_RECT.__newindex = function(t, k, v) - if k == "Min" then ImVec2_Copy(rawget(t, 1), v) - elseif k == "Max" then ImVec2_Copy(rawget(t, 2), v) - else IM_ASSERT(false) - end -end +-- [Luau] Min/Max are named fields, so `r.Min = v` assigns the reference: use ImVec2_Copy(r.Min, v) to keep copy semantics +IM_RECT.__newindex = function(t, k, v) IM_ASSERT(false, "ImRect: unknown field " .. tostring(k)) end --- @return ImRect --- @nodiscard -function ImRect(a, b, c, d) if c and d then return setmetatable({ ImVec2(a, b), ImVec2(c, d) }, IM_RECT) end return setmetatable({ ImVec2(a and a.x or 0, a and a.y or 0), ImVec2(b and b.x or 0, b and b.y or 0) }, IM_RECT) end +function ImRect(a, b, c, d) if c and d then return setmetatable({ Min = ImVec2(a, b), Max = ImVec2(c, d) }, IM_RECT) end return setmetatable({ Min = ImVec2(a and a.x or 0, a and a.y or 0), Max = ImVec2(b and b.x or 0, b and b.y or 0) }, IM_RECT) end -function IM_RECT:__eq(other) return self[1] == other[1] and self[2] == other[2] end +function IM_RECT:__eq(other) return self.Min == other.Min and self.Max == other.Max end function IM_RECT:__tostring() return string.format("ImRect(Min: %g,%g, Max: %g,%g)", self.Min.x, self.Min.y, self.Max.x, self.Max.y) end --- @param p ImRect|ImVec2 function IM_RECT:Contains(p) if p.Min then --- @cast p ImRect - return p[1][1] >= self[1][1] and p[2][1] <= self[2][1] and p[1][2] >= self[1][2] and p[2][2] <= self[2][2] + return p.Min.x >= self.Min.x and p.Max.x <= self.Max.x and p.Min.y >= self.Min.y and p.Max.y <= self.Max.y else --- @cast p ImVec2 - return p[1] >= self[1][1] and p[2] >= self[1][2] and p[1] < self[2][1] and p[2] < self[2][2] + return p.x >= self.Min.x and p.y >= self.Min.y and p.x < self.Max.x and p.y < self.Max.y end end --- @param p ImVec2 --- @param pad ImVec2 function IM_RECT:ContainsWithPad(p, pad) - return p[1] >= self[1][1] - pad[1] and p[2] >= self[1][2] - pad[2] and p[1] < self[2][1] + pad[1] and p[2] < self[2][2] + pad[2] + return p.x >= self.Min.x - pad.x and p.y >= self.Min.y - pad.y and p.x < self.Max.x + pad.x and p.y < self.Max.y + pad.y end --- @param r ImRect function IM_RECT:Overlaps(r) - return self[1][1] <= r[2][1] and self[2][1] >= r[1][1] and self[1][2] <= r[2][2] and self[2][2] >= r[1][2] + return self.Min.x <= r.Max.x and self.Max.x >= r.Min.x and self.Min.y <= r.Max.y and self.Max.y >= r.Min.y end --- @nodiscard -function IM_RECT:GetCenter() return ImVec2((self[1][1] + self[2][1]) * 0.5, (self[1][2] + self[2][2]) * 0.5) end -function IM_RECT:GetWidth() return self[2][1] - self[1][1] end -function IM_RECT:GetHeight() return self[2][2] - self[1][2] end +function IM_RECT:GetCenter() return ImVec2((self.Min.x + self.Max.x) * 0.5, (self.Min.y + self.Max.y) * 0.5) end +function IM_RECT:GetWidth() return self.Max.x - self.Min.x end +function IM_RECT:GetHeight() return self.Max.y - self.Min.y end --- @nodiscard -function IM_RECT:GetSize() return ImVec2(self[2][1] - self[1][1], self[2][2] - self[1][2]) end +function IM_RECT:GetSize() return ImVec2(self.Max.x - self.Min.x, self.Max.y - self.Min.y) end --- @nodiscard -function IM_RECT:GetTL() return ImVec2(self[1][1], self[1][2]) end +function IM_RECT:GetTL() return ImVec2(self.Min.x, self.Min.y) end --- @nodiscard -function IM_RECT:GetTR() return ImVec2(self[2][1], self[1][2]) end +function IM_RECT:GetTR() return ImVec2(self.Max.x, self.Min.y) end --- @nodiscard -function IM_RECT:GetBL() return ImVec2(self[1][1], self[2][2]) end +function IM_RECT:GetBL() return ImVec2(self.Min.x, self.Max.y) end --- @nodiscard -function IM_RECT:GetBR() return ImVec2(self[2][1], self[2][2]) end +function IM_RECT:GetBR() return ImVec2(self.Max.x, self.Max.y) end --- @param r ImRect function IM_RECT:ClipWith(r) - ImVec2_Copy(self[1], ImMax(self[1], r[1])); ImVec2_Copy(self[2], ImMin(self[2], r[2])) + ImVec2_Copy(self.Min, ImMax(self.Min, r.Min)); ImVec2_Copy(self.Max, ImMin(self.Max, r.Max)) end --- @param r ImRect function IM_RECT:ClipWithFull(r) - ImVec2_Copy(self[1], ImClamp(self[1], r[1], r[2])); ImVec2_Copy(self[2], ImClamp(self[2], r[1], r[2])) + ImVec2_Copy(self.Min, ImClamp(self.Min, r.Min, r.Max)); ImVec2_Copy(self.Max, ImClamp(self.Max, r.Min, r.Max)) end --- @param p ImRect|ImVec2 function IM_RECT:Add(p) if p.Min then --- @cast p ImRect - if (self[1][1] > p[1][1]) then self[1][1] = p[1][1] end - if (self[1][2] > p[1][2]) then self[1][2] = p[1][2] end - if (self[2][1] < p[2][1]) then self[2][1] = p[2][1] end - if (self[2][2] < p[2][2]) then self[2][2] = p[2][2] end + if (self.Min.x > p.Min.x) then self.Min.x = p.Min.x end + if (self.Min.y > p.Min.y) then self.Min.y = p.Min.y end + if (self.Max.x < p.Max.x) then self.Max.x = p.Max.x end + if (self.Max.y < p.Max.y) then self.Max.y = p.Max.y end else --- @cast p ImVec2 - if p[1] < self[1][1] then self[1][1] = p[1] end - if p[2] < self[1][2] then self[1][2] = p[2] end - if p[1] > self[2][1] then self[2][1] = p[1] end - if p[2] > self[2][2] then self[2][2] = p[2] end + if p.x < self.Min.x then self.Min.x = p.x end + if p.y < self.Min.y then self.Min.y = p.y end + if p.x > self.Max.x then self.Max.x = p.x end + if p.y > self.Max.y then self.Max.y = p.y end end end --- @param amount float|ImVec2 function IM_RECT:Expand(amount) if type(amount) == "number" then - self[1][1] = self[1][1] - amount; self[1][2] = self[1][2] - amount - self[2][1] = self[2][1] + amount; self[2][2] = self[2][2] + amount + self.Min.x = self.Min.x - amount; self.Min.y = self.Min.y - amount + self.Max.x = self.Max.x + amount; self.Max.y = self.Max.y + amount elseif type(amount) == "table" then - self[1][1] = self[1][1] - amount[1]; self[1][2] = self[1][2] - amount[2] - self[2][1] = self[2][1] + amount[1]; self[2][2] = self[2][2] + amount[2] + self.Min.x = self.Min.x - amount.x; self.Min.y = self.Min.y - amount.y + self.Max.x = self.Max.x + amount.x; self.Max.y = self.Max.y + amount.y end end --- @nodiscard function IM_RECT:ToVec4() - return ImVec4(self[1][1], self[1][2], self[2][1], self[2][2]) + return ImVec4(self.Min.x, self.Min.y, self.Max.x, self.Max.y) end --- @param d ImVec2 function IM_RECT:Translate(d) - self[1][1] = self[1][1] + d[1]; self[1][2] = self[1][2] + d[2] - self[2][1] = self[2][1] + d[1]; self[2][2] = self[2][2] + d[2] + self.Min.x = self.Min.x + d.x; self.Min.y = self.Min.y + d.y + self.Max.x = self.Max.x + d.x; self.Max.y = self.Max.y + d.y end --- @param dx float function IM_RECT:TranslateX(dx) - self[1][1] = self[1][1] + dx; self[2][1] = self[2][1] + dx + self.Min.x = self.Min.x + dx; self.Max.x = self.Max.x + dx end --- @param dy float function IM_RECT:TranslateY(dy) - self[1][2] = self[1][2] + dy; self[2][2] = self[2][2] + dy + self.Min.y = self.Min.y + dy; self.Max.y = self.Max.y + dy end -function IM_RECT:IsInverted() return self[1][1] > self[2][1] or self[1][2] > self[2][2] end +function IM_RECT:IsInverted() return self.Min.x > self.Max.x or self.Min.y > self.Max.y end -function IM_RECT:GetArea() return (self[2][1] - self[1][1]) * (self[2][2] - self[1][2]) end +function IM_RECT:GetArea() return (self.Max.x - self.Min.x) * (self.Max.y - self.Min.y) end --- @nodiscard -function IM_RECT:AsVec4() return ImVec4(self[1][1], self[1][2], self[2][1], self[2][2]) end +function IM_RECT:AsVec4() return ImVec4(self.Min.x, self.Min.y, self.Max.x, self.Max.y) end --- @param dest ImRect --- @param src ImRect function ImRect_Copy(dest, src) - dest[1][1] = src[1][1]; dest[1][2] = src[1][2] - dest[2][1] = src[2][1]; dest[2][2] = src[2][2] + dest.Min.x = src.Min.x; dest.Min.y = src.Min.y + dest.Max.x = src.Max.x; dest.Max.y = src.Max.y end --- @param dest ImRect --- @param src ImVec4 function ImRect_CopyFromV4(dest, src) - dest[1][1] = src[1]; dest[1][2] = src[2] - dest[2][1] = src[3]; dest[2][2] = src[4] + dest.Min.x = src.x; dest.Min.y = src.y + dest.Max.x = src.z; dest.Max.y = src.w end --- @param _ARRAY ImU32[] diff --git a/imgui/backend/imgui_impl_roblox.lua b/imgui/backend/imgui_impl_roblox.lua index 0c24932..2e6d634 100644 --- a/imgui/backend/imgui_impl_roblox.lua +++ b/imgui/backend/imgui_impl_roblox.lua @@ -343,9 +343,9 @@ end -- Generic triangle: per-vertex colour + uv, top-left fill rule, clipped to [cx0, cx1) x [cy0, cy1) @native local function DrawTriangle(va, vb, vc, t, cx0, cy0, cx1, cy1, ox, oy) - local x0, y0 = va[1][1] - ox, va[1][2] - oy - local x1, y1 = vb[1][1] - ox, vb[1][2] - oy - local x2, y2 = vc[1][1] - ox, vc[1][2] - oy + local x0, y0 = va[1].x - ox, va[1].y - oy + local x1, y1 = vb[1].x - ox, vb[1].y - oy + local x2, y2 = vc[1].x - ox, vc[1].y - oy local area = (x1 - x0) * (y2 - y0) - (y1 - y0) * (x2 - x0) if area == 0 then return end if area < 0 then -- make the winding consistent so "inside" means all edge functions >= 0 @@ -370,7 +370,7 @@ local function DrawTriangle(va, vb, vc, t, cx0, cy0, cx1, cy1, ox, oy) local ra, ga, ba, aa = UnpackColor(va[3]) local rb, gb, bb, ab = UnpackColor(vb[3]) local rc, gc, bc, ac = UnpackColor(vc[3]) - local ua, vva, ub, vvb, uc, vvc = va[2][1], va[2][2], vb[2][1], vb[2][2], vc[2][1], vc[2][2] + local ua, vva, ub, vvb, uc, vvc = va[2].x, va[2].y, vb[2].x, vb[2].y, vc[2].x, vc[2].y local textured = t and not (ua == ub and ua == uc and vva == vvb and vva == vvc) if t and not textured then -- constant uv (e.g. the atlas white pixel): fold the texel into the vertex colours @@ -421,12 +421,12 @@ end @native local function TryDrawRect(va, vb, vc, vd, t, cx0, cy0, cx1, cy1, ox, oy) local pa, pb, pc, pd = va[1], vb[1], vc[1], vd[1] - if not (pa[2] == pb[2] and pb[1] == pc[1] and pc[2] == pd[2] and pd[1] == pa[1] and pa[1] < pb[1] and pa[2] < pd[2]) then return false end + if not (pa.y == pb.y and pb.x == pc.x and pc.y == pd.y and pd.x == pa.x and pa.x < pb.x and pa.y < pd.y) then return false end local col = va[3] if vb[3] ~= col or vc[3] ~= col or vd[3] ~= col then return false end local ta, tb, tc, td = va[2], vb[2], vc[2], vd[2] - if not (tb[1] == tc[1] and tb[2] == ta[2] and td[1] == ta[1] and td[2] == tc[2]) then return false end - DrawRect(pa[1] - ox, pa[2] - oy, pc[1] - ox, pc[2] - oy, ta[1], ta[2], tc[1], tc[2], col, t, cx0, cy0, cx1, cy1) + if not (tb.x == tc.x and tb.y == ta.y and td.x == ta.x and td.y == tc.y) then return false end + DrawRect(pa.x - ox, pa.y - oy, pc.x - ox, pc.y - oy, ta.x, ta.y, tc.x, tc.y, col, t, cx0, cy0, cx1, cy1) return true end @@ -445,8 +445,8 @@ local pr_cx0, pr_cy0, pr_cx1, pr_cy1 = {}, {}, {}, {} -- clip (screen pixels) @native local function HashVertex(h1, h2, v) local p, u, c = v[1], v[2], v[3] - local x, y = p[1], p[2] - local uv = u[1] * 8192 + u[2] + local x, y = p.x, p.y + local uv = u.x * 8192 + u.y h1 = (h1 * 48271 + x * 4096 + y) % P1 h1 = (h1 * 48271 + uv * 4096) % P1 h1 = (h1 * 48271 + c) % P1 @@ -558,22 +558,22 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data) local d = vtx[vo + idx[i + 5]] local pd = d[1] -- axis aligned quad (TL, TR, BR, BL) with one colour and a matching uv rect - if pa[2] == pb[2] and pb[1] == pc[1] and pc[2] == pd[2] and pd[1] == pa[1] and pa[1] < pb[1] and pa[2] < pd[2] then + if pa.y == pb.y and pb.x == pc.x and pc.y == pd.y and pd.x == pa.x and pa.x < pb.x and pa.y < pd.y then local col = va[3] local ta, tb, tc, td = va[2], vb[2], vc[2], d[2] if vb[3] == col and vc[3] == col and d[3] == col - and tb[1] == tc[1] and tb[2] == ta[2] and td[1] == ta[1] and td[2] == tc[2] then + and tb.x == tc.x and tb.y == ta.y and td.x == ta.x and td.y == tc.y then vd = d - bx0, by0 = ceil(pa[1] - ox - 0.5), ceil(pa[2] - oy - 0.5) - bx1, by1 = ceil(pc[1] - ox - 0.5), ceil(pc[2] - oy - 0.5) + bx0, by0 = ceil(pa.x - ox - 0.5), ceil(pa.y - oy - 0.5) + bx1, by1 = ceil(pc.x - ox - 0.5), ceil(pc.y - oy - 0.5) end end end if vd then i = i + 6 else - bx0, by0 = floor(min(pa[1], pb[1], pc[1]) - ox), floor(min(pa[2], pb[2], pc[2]) - oy) - bx1, by1 = ceil(max(pa[1], pb[1], pc[1]) - ox) + 1, ceil(max(pa[2], pb[2], pc[2]) - oy) + 1 + bx0, by0 = floor(min(pa.x, pb.x, pc.x) - ox), floor(min(pa.y, pb.y, pc.y) - oy) + bx1, by1 = ceil(max(pa.x, pb.x, pc.x) - ox) + 1, ceil(max(pa.y, pb.y, pc.y) - oy) + 1 i = i + 3 end if bx0 < cx0 then bx0 = cx0 end @@ -639,7 +639,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data) local va, vc, vd = pr_a[p], pr_c[p], pr_d[p] if vd then local pa, pc, ta, tc = va[1], vc[1], va[2], vc[2] - DrawRect(pa[1] - tox, pa[2] - toy, pc[1] - tox, pc[2] - toy, ta[1], ta[2], tc[1], tc[2], va[3], pr_t[p], cx0, cy0, cx1, cy1) + DrawRect(pa.x - tox, pa.y - toy, pc.x - tox, pc.y - toy, ta.x, ta.y, tc.x, tc.y, va[3], pr_t[p], cx0, cy0, cx1, cy1) else DrawTriangle(va, pr_b[p], vc, pr_t[p], cx0, cy0, cx1, cy1, tox, toy) end diff --git a/imgui/imgui_demo_widgets.lua b/imgui/imgui_demo_widgets.lua index 439122c..14140ac 100644 --- a/imgui/imgui_demo_widgets.lua +++ b/imgui/imgui_demo_widgets.lua @@ -1629,7 +1629,7 @@ local function StyleCopy(dst, src) elseif type(v) == "table" and getmetatable(v) ~= nil and type(v[1]) == "number" then local c = dst[k] if type(c) ~= "table" then c = setmetatable({}, getmetatable(v)); dst[k] = c end - for i = 1, #v do rawset(c, i, v[i]) end + for _, key in ipairs({ "x", "y", "z", "w" }) do if rawget(v, key) ~= nil then c[key] = v[key] end end else dst[k] = v end diff --git a/imgui/imgui_draw.lua b/imgui/imgui_draw.lua index af14945..f141241 100644 --- a/imgui/imgui_draw.lua +++ b/imgui/imgui_draw.lua @@ -340,9 +340,9 @@ function ImGui.ShadeVertsTransformPos(draw_list, vert_start_idx, vert_end_idx, p local pix, piy, pox, poy = pivot_in.x, pivot_in.y, pivot_out.x, pivot_out.y for i = vert_start_idx, vert_end_idx - 1 do local pos = data[i][1] - local x, y = pos[1] - pix, pos[2] - piy - pos[1] = x * cos_a - y * sin_a + pox - pos[2] = x * sin_a + y * cos_a + poy + local x, y = pos.x - pix, pos.y - piy + pos.x = x * cos_a - y * sin_a + pox + pos.y = x * sin_a + y * cos_a + poy end end @@ -3710,7 +3710,7 @@ function MT.ImDrawList:PrimRect(a, c, col) ImVec2_Copy(vtx_data[vtx_write_ptr + 0][2], uv) vtx_data[vtx_write_ptr + 0][3] = col - ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][1], c[1], a[2]) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][1], c.x, a.y) ImVec2_Copy(vtx_data[vtx_write_ptr + 1][2], uv) vtx_data[vtx_write_ptr + 1][3] = col @@ -3718,7 +3718,7 @@ function MT.ImDrawList:PrimRect(a, c, col) ImVec2_Copy(vtx_data[vtx_write_ptr + 2][2], uv) vtx_data[vtx_write_ptr + 2][3] = col - ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][1], a[1], c[2]) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][1], a.x, c.y) ImVec2_Copy(vtx_data[vtx_write_ptr + 3][2], uv) vtx_data[vtx_write_ptr + 3][3] = col @@ -3750,16 +3750,16 @@ function MT.ImDrawList:PrimRectUV(a, c, uv_a, uv_c, col) ImVec2_Copy(vtx_data[vtx_write_ptr + 0][2], uv_a) vtx_data[vtx_write_ptr + 0][3] = col - ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][1], c[1], a[2]) - ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][2], uv_c[1], uv_a[2]) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][1], c.x, a.y) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 1][2], uv_c.x, uv_a.y) vtx_data[vtx_write_ptr + 1][3] = col ImVec2_Copy(vtx_data[vtx_write_ptr + 2][1], c) ImVec2_Copy(vtx_data[vtx_write_ptr + 2][2], uv_c) vtx_data[vtx_write_ptr + 2][3] = col - ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][1], a[1], c[2]) - ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][2], uv_a[1], uv_c[2]) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][1], a.x, c.y) + ImVec2_CopyV(vtx_data[vtx_write_ptr + 3][2], uv_a.x, uv_c.y) vtx_data[vtx_write_ptr + 3][3] = col self._VtxWritePtr = vtx_write_ptr + 4 @@ -3815,11 +3815,11 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) local i2 = (i1 == points_count) and 1 or i1 + 1 local p1 = points[i1] local p2 = points[i2] - local dx = p2[1] - p1[1] - local dy = p2[2] - p1[2] + local dx = p2.x - p1.x + local dy = p2.y - p1.y dx, dy = IM_NORMALIZE2F_OVER_ZERO(dx, dy) - temp_normals[i1][1] = dy - temp_normals[i1][2] = -dx + temp_normals[i1].x = dy + temp_normals[i1].y = -dx end if not closed then ImVec2_Copy(temp_normals[points_count], temp_normals[points_count - 1]) @@ -3847,18 +3847,18 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) local idx2 = (i1 == points_count) and self._VtxCurrentIdx or (idx1 + (use_texture and 2 or 3)) -- Average normals - local dm_x = (temp_normals[i1][1] + temp_normals[i2][1]) * 0.5 - local dm_y = (temp_normals[i1][2] + temp_normals[i2][2]) * 0.5 + local dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5 + local dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5 dm_x, dm_y = IM_FIXNORMAL2F(dm_x, dm_y) dm_x = dm_x * half_draw_size dm_y = dm_y * half_draw_size -- Add temporary vertices for the outer edges local out_off = (i2 - 1) * 2 - temp_points[temp_points_start + out_off + 0][1] = points[i2][1] + dm_x - temp_points[temp_points_start + out_off + 0][2] = points[i2][2] + dm_y - temp_points[temp_points_start + out_off + 1][1] = points[i2][1] - dm_x - temp_points[temp_points_start + out_off + 1][2] = points[i2][2] - dm_y + temp_points[temp_points_start + out_off + 0].x = points[i2].x + dm_x + temp_points[temp_points_start + out_off + 0].y = points[i2].y + dm_y + temp_points[temp_points_start + out_off + 1].x = points[i2].x - dm_x + temp_points[temp_points_start + out_off + 1].y = points[i2].y - dm_y if use_texture then -- Add indices for two triangles @@ -3926,8 +3926,8 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) local idx2 = (i1 == points_count) and self._VtxCurrentIdx or (idx1 + 4) -- Average normals - local dm_x = (temp_normals[i1][1] + temp_normals[i2][1]) * 0.5 - local dm_y = (temp_normals[i1][2] + temp_normals[i2][2]) * 0.5 + local dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5 + local dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5 dm_x, dm_y = IM_FIXNORMAL2F(dm_x, dm_y) local dm_out_x = dm_x * (half_inner_thickness + AA_SIZE) local dm_out_y = dm_y * (half_inner_thickness + AA_SIZE) @@ -3936,14 +3936,14 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) -- Add temporary vertices local out_off = (i2 - 1) * 4 - temp_points[temp_points_start + out_off + 0][1] = points[i2][1] + dm_out_x - temp_points[temp_points_start + out_off + 0][2] = points[i2][2] + dm_out_y - temp_points[temp_points_start + out_off + 1][1] = points[i2][1] + dm_in_x - temp_points[temp_points_start + out_off + 1][2] = points[i2][2] + dm_in_y - temp_points[temp_points_start + out_off + 2][1] = points[i2][1] - dm_in_x - temp_points[temp_points_start + out_off + 2][2] = points[i2][2] - dm_in_y - temp_points[temp_points_start + out_off + 3][1] = points[i2][1] - dm_out_x - temp_points[temp_points_start + out_off + 3][2] = points[i2][2] - dm_out_y + temp_points[temp_points_start + out_off + 0].x = points[i2].x + dm_out_x + temp_points[temp_points_start + out_off + 0].y = points[i2].y + dm_out_y + temp_points[temp_points_start + out_off + 1].x = points[i2].x + dm_in_x + temp_points[temp_points_start + out_off + 1].y = points[i2].y + dm_in_y + temp_points[temp_points_start + out_off + 2].x = points[i2].x - dm_in_x + temp_points[temp_points_start + out_off + 2].y = points[i2].y - dm_in_y + temp_points[temp_points_start + out_off + 3].x = points[i2].x - dm_out_x + temp_points[temp_points_start + out_off + 3].y = points[i2].y - dm_out_y -- Add indices local idx_write_ptr = self._IdxWritePtr @@ -3981,17 +3981,17 @@ function MT.ImDrawList:AddPolyline(points, points_count, col, thickness, flags) local p1 = points[i1] local p2 = points[i2] - local dx = p2[1] - p1[1] - local dy = p2[2] - p1[2] + local dx = p2.x - p1.x + local dy = p2.y - p1.y dx, dy = IM_NORMALIZE2F_OVER_ZERO(dx, dy) dx = dx * (thickness * 0.5) dy = dy * (thickness * 0.5) local vtx_write_ptr = self._VtxWritePtr - vtx_data[vtx_write_ptr + 0][1][1] = p1[1] + dy; vtx_data[vtx_write_ptr + 0][1][2] = p1[2] - dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 0][2], opaque_uv); vtx_data[vtx_write_ptr + 0][3] = col - vtx_data[vtx_write_ptr + 1][1][1] = p2[1] + dy; vtx_data[vtx_write_ptr + 1][1][2] = p2[2] - dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 1][2], opaque_uv); vtx_data[vtx_write_ptr + 1][3] = col - vtx_data[vtx_write_ptr + 2][1][1] = p2[1] - dy; vtx_data[vtx_write_ptr + 2][1][2] = p2[2] + dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 2][2], opaque_uv); vtx_data[vtx_write_ptr + 2][3] = col - vtx_data[vtx_write_ptr + 3][1][1] = p1[1] - dy; vtx_data[vtx_write_ptr + 3][1][2] = p1[2] + dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 3][2], opaque_uv); vtx_data[vtx_write_ptr + 3][3] = col + vtx_data[vtx_write_ptr + 0][1].x = p1.x + dy; vtx_data[vtx_write_ptr + 0][1].y = p1.y - dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 0][2], opaque_uv); vtx_data[vtx_write_ptr + 0][3] = col + vtx_data[vtx_write_ptr + 1][1].x = p2.x + dy; vtx_data[vtx_write_ptr + 1][1].y = p2.y - dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 1][2], opaque_uv); vtx_data[vtx_write_ptr + 1][3] = col + vtx_data[vtx_write_ptr + 2][1].x = p2.x - dy; vtx_data[vtx_write_ptr + 2][1].y = p2.y + dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 2][2], opaque_uv); vtx_data[vtx_write_ptr + 2][3] = col + vtx_data[vtx_write_ptr + 3][1].x = p1.x - dy; vtx_data[vtx_write_ptr + 3][1].y = p1.y + dx; ImVec2_Copy(vtx_data[vtx_write_ptr + 3][2], opaque_uv); vtx_data[vtx_write_ptr + 3][3] = col self._VtxWritePtr = vtx_write_ptr + 4 local idx_write_ptr = self._IdxWritePtr @@ -4728,10 +4728,10 @@ function MT.ImFont:RenderText(draw_list, size, pos, col, clip_rect, text, text_b local glyph_col = glyph.Colored and color_untinted or col do - local vtx0 = vtx_data[vtx_write + 0]; vtx0[1][1] = x1; vtx0[1][2] = y1; vtx0[3] = glyph_col; vtx0[2][1] = u1; vtx0[2][2] = v1; - local vtx1 = vtx_data[vtx_write + 1]; vtx1[1][1] = x2; vtx1[1][2] = y1; vtx1[3] = glyph_col; vtx1[2][1] = u2; vtx1[2][2] = v1; - local vtx2 = vtx_data[vtx_write + 2]; vtx2[1][1] = x2; vtx2[1][2] = y2; vtx2[3] = glyph_col; vtx2[2][1] = u2; vtx2[2][2] = v2; - local vtx3 = vtx_data[vtx_write + 3]; vtx3[1][1] = x1; vtx3[1][2] = y2; vtx3[3] = glyph_col; vtx3[2][1] = u1; vtx3[2][2] = v2; + local vtx0 = vtx_data[vtx_write + 0]; vtx0[1].x = x1; vtx0[1].y = y1; vtx0[3] = glyph_col; vtx0[2].x = u1; vtx0[2].y = v1; + local vtx1 = vtx_data[vtx_write + 1]; vtx1[1].x = x2; vtx1[1].y = y1; vtx1[3] = glyph_col; vtx1[2].x = u2; vtx1[2].y = v1; + local vtx2 = vtx_data[vtx_write + 2]; vtx2[1].x = x2; vtx2[1].y = y2; vtx2[3] = glyph_col; vtx2[2].x = u2; vtx2[2].y = v2; + local vtx3 = vtx_data[vtx_write + 3]; vtx3[1].x = x1; vtx3[1].y = y2; vtx3[3] = glyph_col; vtx3[2].x = u1; vtx3[2].y = v2; idx_data[idx_write + 0] = vtx_index; idx_data[idx_write + 1] = vtx_index + 1; idx_data[idx_write + 2] = vtx_index + 2; idx_data[idx_write + 3] = vtx_index; idx_data[idx_write + 4] = vtx_index + 2; idx_data[idx_write + 5] = vtx_index + 3; vtx_write = vtx_write + 4 diff --git a/imgui/imgui_h.lua b/imgui/imgui_h.lua index c8de511..a3ba940 100644 --- a/imgui/imgui_h.lua +++ b/imgui/imgui_h.lua @@ -193,8 +193,8 @@ ImGuiMouseCursor = --- @return ImTextureRect function ImTextureRect(x, y, w, h) return { x = x, y = y, w = w, h = h } end --- This structure supports indexing on string keys `x`, `y` and number keys 1, 2. --- But note that the former is likely to be more expensive. +-- [Luau] Stored as named fields {x=, y=} so the common `.x`/`.y` access is a plain table read (no metamethod call). +-- Numeric keys 1, 2 still work through the metatable, but are slower: prefer .x/.y in hot code. --- @class ImVec2 --- @operator add(ImVec2): ImVec2 --- @operator sub(ImVec2): ImVec2 @@ -202,146 +202,97 @@ function ImTextureRect(x, y, w, h) return { x = x, y = y, w = w, h = h } end --- @operator mul(ImVec2): ImVec2 --- @operator div(number): ImVec2 --- @operator div(ImVec2): ImVec2 ---- @field [1] number ---- @field [2] number --- @field x number --- @field y number local IM_VEC2 = {} +local VEC2_KEYS = { "x", "y" } ---- @param t ImVec2 ---- @param k string IM_VEC2.__index = function(t, k) - if k == "x" then return rawget(t, 1) - elseif k == "y" then return rawget(t, 2) - end + local n = VEC2_KEYS[k] + if n then return rawget(t, n) end end ---- @param t ImVec2 ---- @param k string ---- @param v number IM_VEC2.__newindex = function(t, k, v) - if k == "x" then rawset(t, 1, v) - elseif k == "y" then rawset(t, 2, v) - else IM_ASSERT(false) - end + local n = VEC2_KEYS[k] + IM_ASSERT(n ~= nil) + rawset(t, n, v) end --- @param x? number --- @param y? number --- @return ImVec2 --- @nodiscard -function ImVec2(x, y) return setmetatable({x or 0, y or 0}, IM_VEC2) end +function ImVec2(x, y) return setmetatable({ x = x or 0, y = y or 0 }, IM_VEC2) end -function IM_VEC2.__add(lhs, rhs) return ImVec2(lhs[1] + rhs[1], lhs[2] + rhs[2]) end -function IM_VEC2.__sub(lhs, rhs) return ImVec2(lhs[1] - rhs[1], lhs[2] - rhs[2]) end +function IM_VEC2.__add(lhs, rhs) return setmetatable({ x = lhs.x + rhs.x, y = lhs.y + rhs.y }, IM_VEC2) end +function IM_VEC2.__sub(lhs, rhs) return setmetatable({ x = lhs.x - rhs.x, y = lhs.y - rhs.y }, IM_VEC2) end ---- @overload fun(lhs: ImVec2, rhs: number): ImVec2 ---- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 function IM_VEC2.__mul(lhs, rhs) - if type(lhs) == "table" and type(rhs) == "number" then return ImVec2(lhs[1] * rhs, lhs[2] * rhs) - elseif type(lhs) == "table" and type(rhs) == "table" then return ImVec2(lhs[1] * rhs[1], lhs[2] * rhs[2]) - end + if type(rhs) == "number" then return setmetatable({ x = lhs.x * rhs, y = lhs.y * rhs }, IM_VEC2) end + return setmetatable({ x = lhs.x * rhs.x, y = lhs.y * rhs.y }, IM_VEC2) end ---- @overload fun(lhs: ImVec2, rhs: number): ImVec2 ---- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 function IM_VEC2.__div(lhs, rhs) - if type(lhs) == "table" and type(rhs) == "number" then return ImVec2(lhs[1] / rhs, lhs[2] / rhs) - elseif type(lhs) == "table" and type(rhs) == "table" then return ImVec2(lhs[1] / rhs[1], lhs[2] / rhs[2]) - end + if type(rhs) == "number" then return setmetatable({ x = lhs.x / rhs, y = lhs.y / rhs }, IM_VEC2) end + return setmetatable({ x = lhs.x / rhs.x, y = lhs.y / rhs.y }, IM_VEC2) end -function IM_VEC2.__eq(lhs, rhs) return lhs[1] == rhs[1] and lhs[2] == rhs[2] end +function IM_VEC2.__eq(lhs, rhs) return lhs.x == rhs.x and lhs.y == rhs.y end function IM_VEC2:__tostring() return string.format("ImVec2(%g, %g)", self.x, self.y) end --- @param dest ImVec2 --- @param src ImVec2 -function ImVec2_Copy(dest, src) dest[1] = src[1]; dest[2] = src[2] end +function ImVec2_Copy(dest, src) dest.x = src.x; dest.y = src.y end ---- @param dest ImVec2 ---- @param src_x number ---- @param src_y number -function ImVec2_CopyV(dest, src_x, src_y) dest[1] = src_x; dest[2] = src_y end +function ImVec2_CopyV(dest, src_x, src_y) dest.x = src_x; dest.y = src_y end ---- @param v ImVec2 ---- @param add_x number ---- @param add_y number -function ImVec2_AddVA(v, add_x, add_y) return v[1] + add_x, v[2] + add_y end +function ImVec2_AddVA(v, add_x, add_y) return v.x + add_x, v.y + add_y end ---- @param v ImVec2 ---- @param sub_x number ---- @param sub_y number -function ImVec2_SubVA(v, sub_x, sub_y) return v[1] - sub_x, v[2] - sub_y end +function ImVec2_SubVA(v, sub_x, sub_y) return v.x - sub_x, v.y - sub_y end ---- @param a ImVec2 ---- @param scalar number -function ImVec2_MulVX(a, scalar) - return a[1] * scalar, a[2] * scalar -end +function ImVec2_MulVX(a, scalar) return a.x * scalar, a.y * scalar end --- An inlined version of `ImVec2_Copy` currently for use in certain ImVector `push_back` ---- @param t ImVec2[] ---- @param k int ---- @param v ImVec2 -local function ImVec2_TCopy(t, k, v) local dest = t[k]; dest[1] = v[1]; dest[2] = v[2]; end +local function ImVec2_TCopy(t, k, v) local dest = t[k]; dest.x = v.x; dest.y = v.y; end --- This structure supports indexing on string keys `x`, `y`, `z`, `w` and number keys 1, 2, 3, 4. --- But note that the former is likely to be more expensive. +-- [Luau] Same layout as ImVec2: named fields x, y, z, w; numeric keys 1..4 go through the metatable. --- @class ImVec4 --- @operator add(ImVec4): ImVec4 --- @operator sub(ImVec4): ImVec4 --- @operator mul(number): ImVec4 ---- @field [1] number ---- @field [2] number ---- @field [3] number ---- @field [4] number --- @field x number --- @field y number --- @field z number --- @field w number local IM_VEC4 = {} +local VEC4_KEYS = { "x", "y", "z", "w" } ---- @param t ImVec4 ---- @param k string IM_VEC4.__index = function(t, k) - if k == "x" then return rawget(t, 1) - elseif k == "y" then return rawget(t, 2) - elseif k == "z" then return rawget(t, 3) - elseif k == "w" then return rawget(t, 4) - end + local n = VEC4_KEYS[k] + if n then return rawget(t, n) end end ---- @param t ImVec4 ---- @param k string ---- @param v number IM_VEC4.__newindex = function(t, k, v) - if k == "x" then rawset(t, 1, v) - elseif k == "y" then rawset(t, 2, v) - elseif k == "z" then rawset(t, 3, v) - elseif k == "w" then rawset(t, 4, v) - else IM_ASSERT(false) - end + local n = VEC4_KEYS[k] + IM_ASSERT(n ~= nil) + rawset(t, n, v) end ---- @param x? number ---- @param y? number ---- @param z? number ---- @param w? number --- @return ImVec4 --- @nodiscard -function ImVec4(x, y, z, w) return setmetatable({x or 0, y or 0, z or 0, w or 0}, IM_VEC4) end +function ImVec4(x, y, z, w) return setmetatable({ x = x or 0, y = y or 0, z = z or 0, w = w or 0 }, IM_VEC4) end -function IM_VEC4.__add(lhs, rhs) return ImVec4(lhs[1] + rhs[1], lhs[2] + rhs[2], lhs[3] + rhs[3], lhs[4] + rhs[4]) end -function IM_VEC4.__sub(lhs, rhs) return ImVec4(lhs[1] - rhs[1], lhs[2] - rhs[2], lhs[3] - rhs[3], lhs[4] - rhs[4]) end -function IM_VEC4.__mul(lhs, rhs) return ImVec4(lhs[1] * rhs, lhs[2] * rhs, lhs[3] * rhs, lhs[4] * rhs) end -function IM_VEC4.__eq(lhs, rhs) return lhs[1] == rhs[1] and lhs[2] == rhs[2] and lhs[3] == rhs[3] and lhs[4] == rhs[4] end +function IM_VEC4.__add(lhs, rhs) return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w) end +function IM_VEC4.__sub(lhs, rhs) return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w) end +function IM_VEC4.__mul(lhs, rhs) return ImVec4(lhs.x * rhs, lhs.y * rhs, lhs.z * rhs, lhs.w * rhs) end +function IM_VEC4.__eq(lhs, rhs) return lhs.x == rhs.x and lhs.y == rhs.y and lhs.z == rhs.z and lhs.w == rhs.w end function IM_VEC4:__tostring() return string.format("ImVec4(%g, %g, %g, %g)", self.x, self.y, self.z, self.w) end --- @param dest ImVec4 --- @param src ImVec4 -function ImVec4_Copy(dest, src) dest[1] = src[1]; dest[2] = src[2]; dest[3] = src[3]; dest[4] = src[4] end +function ImVec4_Copy(dest, src) dest.x = src.x; dest.y = src.y; dest.z = src.z; dest.w = src.w end --- A compact ImVector clone --- @class ImVector @@ -356,8 +307,10 @@ local IM_VECTOR = {} --- @param k string|int --- @return any IM_VECTOR.__index = function(t, k) + local m = IM_VECTOR[k] -- methods first (hot path) + if m ~= nil then return m end if k == "Data" then return nil end -- Data has already been discarded - return IM_VECTOR[k] or t.Data[IM_ASSERT(k >= 1 and k <= t.Size) or k] -- if the mt access turns out nil, the k must be int index into Data + return t.Data[IM_ASSERT(k >= 1 and k <= t.Size) or k] -- if the mt access turns out nil, the k must be int index into Data end --- @param t ImVector diff --git a/imgui/imgui_internal.lua b/imgui/imgui_internal.lua index 7d4262f..58e0698 100644 --- a/imgui/imgui_internal.lua +++ b/imgui/imgui_internal.lua @@ -141,17 +141,15 @@ end --- @overload fun(lhs: number, rhs: number): number --- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 function ImMin(lhs, rhs) - if type(lhs) == "number" and type(rhs) == "number" then return mathMin(lhs, rhs) - elseif type(lhs) == "table" and type(rhs) == "table" then return ImVec2(mathMin(lhs[1], rhs[1]), mathMin(lhs[2], rhs[2])) - end + if type(lhs) == "number" then return mathMin(lhs, rhs) end + return ImVec2(mathMin(lhs.x, rhs.x), mathMin(lhs.y, rhs.y)) end --- @overload fun(lhs: number, rhs: number): number --- @overload fun(lhs: ImVec2, rhs: ImVec2): ImVec2 function ImMax(lhs, rhs) - if type(lhs) == "number" and type(rhs) == "number" then return mathMax(lhs, rhs) - elseif type(lhs) == "table" and type(rhs) == "table" then return ImVec2(mathMax(lhs[1], rhs[1]), mathMax(lhs[2], rhs[2])) - end + if type(lhs) == "number" then return mathMax(lhs, rhs) end + return ImVec2(mathMax(lhs.x, rhs.x), mathMax(lhs.y, rhs.y)) end --- @param base table @@ -163,7 +161,7 @@ ImStd.ImQsort = function(base, count, cmp_func) if count > 0 then t_sort(base, c --- @overload fun(v: ImVec2, mn: ImVec2, mx: ImVec2): ImVec2 function ImClamp(v, mn, mx) if type(v) == "number" and type(mn) == "number" and type(mx) == "number" then return mathMin(mathMax(v, mn), mx) - elseif type(v) == "table" and type(mn) == "table" and type(mx) == "table" then return ImVec2(mathMax(mn[1], mathMin(v[1], mx[1])), mathMax(mn[2], mathMin(v[2], mx[2]))) + elseif type(v) == "table" and type(mn) == "table" and type(mx) == "table" then return ImVec2(mathMax(mn.x, mathMin(v.x, mx.x)), mathMax(mn.y, mathMin(v.y, mx.y))) end end @@ -172,8 +170,8 @@ end --- @overload fun(a: ImVec2, b: ImVec2, t: ImVec2): ImVec2 function ImLerp(a, b, t) if type(a) == "number" and type(b) == "number" and type(t) == "number" then return ((a) + ((b) - (a)) * (t)) - elseif type(a) == "table" and type(b) == "table" and type(t) == "number" then return ImVec2(a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t) - elseif type(a) == "table" and type(b) == "table" and type(t) == "table" then return ImVec2(a[1] + (b[1] - a[1]) * t[1], a[2] + (b[2] - a[2]) * t[2]) + elseif type(a) == "table" and type(b) == "table" and type(t) == "number" then return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t) + elseif type(a) == "table" and type(b) == "table" and type(t) == "table" then return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y) end end @@ -183,7 +181,7 @@ local function _Trunc(val) if val >= 0 then return mathFloor(val) else return ma --- @overload fun(v: ImVec2): ImVec2 function ImTrunc(v) if type(v) == "number" then return _Trunc(v) - elseif type(v) == "table" then return ImVec2(_Trunc(v[1]), _Trunc(v[2])) + elseif type(v) == "table" then return ImVec2(_Trunc(v.x), _Trunc(v.y)) end end @@ -673,150 +671,138 @@ end --- @field Min ImVec2 --- @field Max ImVec2 local IM_RECT = {} +setmetatable(IM_RECT, { __index = function(_, k) if k ~= "Min" and k ~= "Max" then error("ImRect: unknown key " .. tostring(k), 2) end end }) --- @param t ImRect --- @param k string -IM_RECT.__index = function(t, k) - local method = IM_RECT[k] - if method ~= nil then return method end - if k == "Min" then return rawget(t, 1) - elseif k == "Max" then return rawget(t, 2) - end -end +IM_RECT.__index = IM_RECT -- [Luau] plain table: fast method lookup. Use r.Min / r.Max (numeric r[1]/r[2] are not supported) ---- @param t ImRect ---- @param k string ---- @param v ImVec2 -IM_RECT.__newindex = function(t, k, v) - if k == "Min" then ImVec2_Copy(rawget(t, 1), v) - elseif k == "Max" then ImVec2_Copy(rawget(t, 2), v) - else IM_ASSERT(false) - end -end +-- [Luau] Min/Max are named fields, so `r.Min = v` assigns the reference: use ImVec2_Copy(r.Min, v) to keep copy semantics +IM_RECT.__newindex = function(t, k, v) IM_ASSERT(false, "ImRect: unknown field " .. tostring(k)) end --- @return ImRect --- @nodiscard -function ImRect(a, b, c, d) if c and d then return setmetatable({ ImVec2(a, b), ImVec2(c, d) }, IM_RECT) end return setmetatable({ ImVec2(a and a.x or 0, a and a.y or 0), ImVec2(b and b.x or 0, b and b.y or 0) }, IM_RECT) end +function ImRect(a, b, c, d) if c and d then return setmetatable({ Min = ImVec2(a, b), Max = ImVec2(c, d) }, IM_RECT) end return setmetatable({ Min = ImVec2(a and a.x or 0, a and a.y or 0), Max = ImVec2(b and b.x or 0, b and b.y or 0) }, IM_RECT) end -function IM_RECT:__eq(other) return self[1] == other[1] and self[2] == other[2] end +function IM_RECT:__eq(other) return self.Min == other.Min and self.Max == other.Max end function IM_RECT:__tostring() return string.format("ImRect(Min: %g,%g, Max: %g,%g)", self.Min.x, self.Min.y, self.Max.x, self.Max.y) end --- @param p ImRect|ImVec2 function IM_RECT:Contains(p) if p.Min then --- @cast p ImRect - return p[1][1] >= self[1][1] and p[2][1] <= self[2][1] and p[1][2] >= self[1][2] and p[2][2] <= self[2][2] + return p.Min.x >= self.Min.x and p.Max.x <= self.Max.x and p.Min.y >= self.Min.y and p.Max.y <= self.Max.y else --- @cast p ImVec2 - return p[1] >= self[1][1] and p[2] >= self[1][2] and p[1] < self[2][1] and p[2] < self[2][2] + return p.x >= self.Min.x and p.y >= self.Min.y and p.x < self.Max.x and p.y < self.Max.y end end --- @param p ImVec2 --- @param pad ImVec2 function IM_RECT:ContainsWithPad(p, pad) - return p[1] >= self[1][1] - pad[1] and p[2] >= self[1][2] - pad[2] and p[1] < self[2][1] + pad[1] and p[2] < self[2][2] + pad[2] + return p.x >= self.Min.x - pad.x and p.y >= self.Min.y - pad.y and p.x < self.Max.x + pad.x and p.y < self.Max.y + pad.y end --- @param r ImRect function IM_RECT:Overlaps(r) - return self[1][1] <= r[2][1] and self[2][1] >= r[1][1] and self[1][2] <= r[2][2] and self[2][2] >= r[1][2] + return self.Min.x <= r.Max.x and self.Max.x >= r.Min.x and self.Min.y <= r.Max.y and self.Max.y >= r.Min.y end --- @nodiscard -function IM_RECT:GetCenter() return ImVec2((self[1][1] + self[2][1]) * 0.5, (self[1][2] + self[2][2]) * 0.5) end -function IM_RECT:GetWidth() return self[2][1] - self[1][1] end -function IM_RECT:GetHeight() return self[2][2] - self[1][2] end +function IM_RECT:GetCenter() return ImVec2((self.Min.x + self.Max.x) * 0.5, (self.Min.y + self.Max.y) * 0.5) end +function IM_RECT:GetWidth() return self.Max.x - self.Min.x end +function IM_RECT:GetHeight() return self.Max.y - self.Min.y end --- @nodiscard -function IM_RECT:GetSize() return ImVec2(self[2][1] - self[1][1], self[2][2] - self[1][2]) end +function IM_RECT:GetSize() return ImVec2(self.Max.x - self.Min.x, self.Max.y - self.Min.y) end --- @nodiscard -function IM_RECT:GetTL() return ImVec2(self[1][1], self[1][2]) end +function IM_RECT:GetTL() return ImVec2(self.Min.x, self.Min.y) end --- @nodiscard -function IM_RECT:GetTR() return ImVec2(self[2][1], self[1][2]) end +function IM_RECT:GetTR() return ImVec2(self.Max.x, self.Min.y) end --- @nodiscard -function IM_RECT:GetBL() return ImVec2(self[1][1], self[2][2]) end +function IM_RECT:GetBL() return ImVec2(self.Min.x, self.Max.y) end --- @nodiscard -function IM_RECT:GetBR() return ImVec2(self[2][1], self[2][2]) end +function IM_RECT:GetBR() return ImVec2(self.Max.x, self.Max.y) end --- @param r ImRect function IM_RECT:ClipWith(r) - ImVec2_Copy(self[1], ImMax(self[1], r[1])); ImVec2_Copy(self[2], ImMin(self[2], r[2])) + ImVec2_Copy(self.Min, ImMax(self.Min, r.Min)); ImVec2_Copy(self.Max, ImMin(self.Max, r.Max)) end --- @param r ImRect function IM_RECT:ClipWithFull(r) - ImVec2_Copy(self[1], ImClamp(self[1], r[1], r[2])); ImVec2_Copy(self[2], ImClamp(self[2], r[1], r[2])) + ImVec2_Copy(self.Min, ImClamp(self.Min, r.Min, r.Max)); ImVec2_Copy(self.Max, ImClamp(self.Max, r.Min, r.Max)) end --- @param p ImRect|ImVec2 function IM_RECT:Add(p) if p.Min then --- @cast p ImRect - if (self[1][1] > p[1][1]) then self[1][1] = p[1][1] end - if (self[1][2] > p[1][2]) then self[1][2] = p[1][2] end - if (self[2][1] < p[2][1]) then self[2][1] = p[2][1] end - if (self[2][2] < p[2][2]) then self[2][2] = p[2][2] end + if (self.Min.x > p.Min.x) then self.Min.x = p.Min.x end + if (self.Min.y > p.Min.y) then self.Min.y = p.Min.y end + if (self.Max.x < p.Max.x) then self.Max.x = p.Max.x end + if (self.Max.y < p.Max.y) then self.Max.y = p.Max.y end else --- @cast p ImVec2 - if p[1] < self[1][1] then self[1][1] = p[1] end - if p[2] < self[1][2] then self[1][2] = p[2] end - if p[1] > self[2][1] then self[2][1] = p[1] end - if p[2] > self[2][2] then self[2][2] = p[2] end + if p.x < self.Min.x then self.Min.x = p.x end + if p.y < self.Min.y then self.Min.y = p.y end + if p.x > self.Max.x then self.Max.x = p.x end + if p.y > self.Max.y then self.Max.y = p.y end end end --- @param amount float|ImVec2 function IM_RECT:Expand(amount) if type(amount) == "number" then - self[1][1] = self[1][1] - amount; self[1][2] = self[1][2] - amount - self[2][1] = self[2][1] + amount; self[2][2] = self[2][2] + amount + self.Min.x = self.Min.x - amount; self.Min.y = self.Min.y - amount + self.Max.x = self.Max.x + amount; self.Max.y = self.Max.y + amount elseif type(amount) == "table" then - self[1][1] = self[1][1] - amount[1]; self[1][2] = self[1][2] - amount[2] - self[2][1] = self[2][1] + amount[1]; self[2][2] = self[2][2] + amount[2] + self.Min.x = self.Min.x - amount.x; self.Min.y = self.Min.y - amount.y + self.Max.x = self.Max.x + amount.x; self.Max.y = self.Max.y + amount.y end end --- @nodiscard function IM_RECT:ToVec4() - return ImVec4(self[1][1], self[1][2], self[2][1], self[2][2]) + return ImVec4(self.Min.x, self.Min.y, self.Max.x, self.Max.y) end --- @param d ImVec2 function IM_RECT:Translate(d) - self[1][1] = self[1][1] + d[1]; self[1][2] = self[1][2] + d[2] - self[2][1] = self[2][1] + d[1]; self[2][2] = self[2][2] + d[2] + self.Min.x = self.Min.x + d.x; self.Min.y = self.Min.y + d.y + self.Max.x = self.Max.x + d.x; self.Max.y = self.Max.y + d.y end --- @param dx float function IM_RECT:TranslateX(dx) - self[1][1] = self[1][1] + dx; self[2][1] = self[2][1] + dx + self.Min.x = self.Min.x + dx; self.Max.x = self.Max.x + dx end --- @param dy float function IM_RECT:TranslateY(dy) - self[1][2] = self[1][2] + dy; self[2][2] = self[2][2] + dy + self.Min.y = self.Min.y + dy; self.Max.y = self.Max.y + dy end -function IM_RECT:IsInverted() return self[1][1] > self[2][1] or self[1][2] > self[2][2] end +function IM_RECT:IsInverted() return self.Min.x > self.Max.x or self.Min.y > self.Max.y end -function IM_RECT:GetArea() return (self[2][1] - self[1][1]) * (self[2][2] - self[1][2]) end +function IM_RECT:GetArea() return (self.Max.x - self.Min.x) * (self.Max.y - self.Min.y) end --- @nodiscard -function IM_RECT:AsVec4() return ImVec4(self[1][1], self[1][2], self[2][1], self[2][2]) end +function IM_RECT:AsVec4() return ImVec4(self.Min.x, self.Min.y, self.Max.x, self.Max.y) end --- @param dest ImRect --- @param src ImRect function ImRect_Copy(dest, src) - dest[1][1] = src[1][1]; dest[1][2] = src[1][2] - dest[2][1] = src[2][1]; dest[2][2] = src[2][2] + dest.Min.x = src.Min.x; dest.Min.y = src.Min.y + dest.Max.x = src.Max.x; dest.Max.y = src.Max.y end --- @param dest ImRect --- @param src ImVec4 function ImRect_CopyFromV4(dest, src) - dest[1][1] = src[1]; dest[1][2] = src[2] - dest[2][1] = src[3]; dest[2][2] = src[4] + dest.Min.x = src.x; dest.Min.y = src.y + dest.Max.x = src.z; dest.Max.y = src.w end --- @param _ARRAY ImU32[] diff --git a/tools/test/roblox_mock.luau b/tools/test/roblox_mock.luau index 6bfb0d2..ca9fc8c 100644 --- a/tools/test/roblox_mock.luau +++ b/tools/test/roblox_mock.luau @@ -167,12 +167,12 @@ local render_time = 0 local realDemo = G.ImGui.ShowDemoWindow local realCH = G.ImGui.CollapsingHeader G.ImGui.CollapsingHeader = function(...) - if ARG_OPEN then G.ImGui.SetNextItemOpen(true, G.ImGuiCond.Always) end + if ARG_OPEN == true or (type(ARG_OPEN) == "table" and ARG_OPEN[(...)]) then G.ImGui.SetNextItemOpen(true, G.ImGuiCond.Always) end return realCH(...) end local realTN = G.ImGui.TreeNode G.ImGui.TreeNode = function(...) - if ARG_OPEN then G.ImGui.SetNextItemOpen(true, G.ImGuiCond.Always) end + if ARG_OPEN == true or (type(ARG_OPEN) == "table" and ARG_OPEN[(...)]) then G.ImGui.SetNextItemOpen(true, G.ImGuiCond.Always) end return realTN(...) end G.ImGui.ShowDemoWindow = function(...) diff --git a/tools/test/run.py b/tools/test/run.py index d0cb055..cee1533 100644 --- a/tools/test/run.py +++ b/tools/test/run.py @@ -16,7 +16,7 @@ G = "game, workspace, Instance, Enum, Vector2, Vector3, UDim2, Color3, Content, def build_run(args, flags): subprocess.run([sys.executable, os.path.join(ROOT, "tools", "bundle.py"), TMP], check=True, stdout=subprocess.DEVNULL) - out = ["--!native", "--!optimize 2", flags, "local SOURCE_FNS = {}"] + out = ["--" if args.roblox else "--!native", "--!optimize 2", flags, "local SOURCE_FNS = {}"] def add(key, path): s = "\n".join(l for l in open(path).read().split("\n") if not l.startswith("--!")) out.append("SOURCE_FNS[%r] = function(%s)\n%s\nend" % (key, G, s)) @@ -31,7 +31,7 @@ def build_run(args, flags): return path def run(args, extra=""): - flags = "ARG_FRAMES=%d; ARG_BIG=%s; ARG_OPEN=%s; ARG_QUIET=%s; %s" % (args.frames, str(args.big).lower(), str(args.open).lower(), str(args.quiet).lower(), extra) + flags = "ARG_FRAMES=%d; ARG_BIG=%s; ARG_OPEN=%s; ARG_QUIET=%s; %s" % (args.frames, str(args.big).lower(), ("{%s}" % ",".join("[%r]=true" % x for x in args.open_only.split(",")) if args.open_only else str(args.open).lower()), str(args.quiet).lower(), extra) try: p = subprocess.run([LUAU, "-O2"] + (["--profile=2000"] if args.profile else ["--codegen"]) + [build_run(args, flags)], capture_output=True, text=True, timeout=args.timeout) except subprocess.TimeoutExpired as e: @@ -58,6 +58,8 @@ def main(): ap.add_argument("--frames", type=int, default=400) ap.add_argument("--main", default=os.path.join(ROOT, "main.client.luau")) ap.add_argument("--big", action="store_true", help="demo window forced to 900x1000") + ap.add_argument("--roblox", action="store_true", help="like Studio: only @native functions get native code (default: whole bundle native)") + ap.add_argument("--open-only", default="", help="comma list of CollapsingHeader/TreeNode labels to force open, e.g. Widgets,Basic") ap.add_argument("--profile", action="store_true", help="sampling profile (no codegen) -> profile.out; see tools/test/prof.py") ap.add_argument("--open", action="store_true", help="force all CollapsingHeader/TreeNode open") ap.add_argument("--timeout", type=int, default=120)