Embed widget example (Instances inside imgui windows, one Frame per id, hidden when not submitted, EmbedFlags) + backend SetOverlay

This commit is contained in:
4DBug
2026-10-08 17:28:13 -05:00
parent dfe357d963
commit ffc0332971
6 changed files with 275 additions and 7 deletions
+79 -2
View File
@@ -600,6 +600,73 @@ local function DrawListSignature(draw_list, ox, oy)
return readstring(draw_list.VtxBuffer.Buf, 0, draw_list.VtxBuffer.Size * VTX_STRIDE) .. readstring(b, 0, o) return readstring(draw_list.VtxBuffer.Buf, 0, draw_list.VtxBuffer.Size * VTX_STRIDE) .. readstring(b, 0, o)
end end
-- Overlays: user Instances (e.g. a Frame holding a ViewportFrame) placed inside a window, registered every frame with
-- ImGui_ImplRoblox.SetOverlay() while that window is current. They stack right above the window's layers, move with
-- it, and (clip = true) are clipped to the window's content area like its widgets.
local function OverlayHolder(bd, draw_list, clip)
local hs = bd.OverlayHolders[draw_list]
if not hs then hs = {}; bd.OverlayHolders[draw_list] = hs end
local h = hs[clip]
if not h then
h = Instance.new("Frame")
h.Name = clip and "OverlayClip" or "Overlay"
h.BackgroundTransparency = 1
h.BorderSizePixel = 0
h.ClipsDescendants = clip
h.Size = UDim2.fromOffset(0, 0)
h.Parent = bd.Gui
hs[clip] = h
end
return h
end
local function PlaceOverlays(bd, draw_list, z, ox, oy)
local list = bd.Overlays[draw_list]
local hs = bd.OverlayHolders[draw_list]
if not list then
if hs then for _, h in pairs(hs) do h.Visible = false end end
return z
end
local scale, frame_no = bd.Scale, bd.FrameNo
z += 1
local used = {}
for _, o in ipairs(list) do
local clip = o.Clip and draw_list._ContentClipX0 ~= nil
local h = OverlayHolder(bd, draw_list, clip)
local hx, hy = 0, 0
if clip then
hx, hy = draw_list._ContentClipX0 - ox, draw_list._ContentClipY0 - oy
if not used[h] then
h.Position = UDim2.fromOffset(hx / scale, hy / scale)
h.Size = UDim2.fromOffset((draw_list._ContentClipX1 - draw_list._ContentClipX0) / scale, (draw_list._ContentClipY1 - draw_list._ContentClipY0) / scale)
end
elseif not used[h] then
h.Position = UDim2.fromOffset(0, 0)
end
used[h] = true
h.ZIndex = z
h.Visible = true
local f = o.Frame
if f.Parent ~= h then f.Parent = h end
f.Position = UDim2.fromOffset((o.X - ox - hx) / scale, (o.Y - oy - hy) / scale)
f.Size = UDim2.fromOffset(o.W / scale, o.H / scale)
f.Visible = true
bd.OverlayShown[f] = frame_no
end
if hs then for _, h in pairs(hs) do if not used[h] then h.Visible = false end end end
return z
end
--- Show `frame` this frame at (x, y, w, h) (imgui coordinates) inside the current window. Call every frame it should
--- be visible; frames not submitted are hidden. clip: clip to the window's content area (scrolls with it).
function ImGui_ImplRoblox_SetOverlay(frame, x, y, w, h, clip)
local bd = ImGui_ImplRoblox_GetBackendData()
local dl = ImGui.GetWindowDrawList()
local list = bd.Overlays[dl]
if not list then list = {}; bd.Overlays[dl] = list end
list[#list + 1] = { Frame = frame, X = x, Y = y, W = w, H = h, Clip = clip ~= false }
end
-- MicroProfiler labels, enabled with ImGui_ImplRoblox.SetProfiling(true) -- MicroProfiler labels, enabled with ImGui_ImplRoblox.SetProfiling(true)
local profilebegin, profileend = debug.profilebegin, debug.profileend local profilebegin, profileend = debug.profilebegin, debug.profileend
local profiling = false local profiling = false
@@ -781,7 +848,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
end end
if rate > 0 then if rate > 0 then
local now = os.clock() local now = os.clock()
if now + 0.002 < bd.NextRender then PE(); return end if now + 0.002 < bd.NextRender then table.clear(bd.Overlays); PE(); return end
bd.NextRender = math.max(bd.NextRender + 1 / rate, now) bd.NextRender = math.max(bd.NextRender + 1 / rate, now)
end end
@@ -811,6 +878,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
end end
end end
set.LastUsed = frame_no set.LastUsed = frame_no
z = PlaceOverlays(bd, draw_list, z, ox, oy)
PE() PE()
continue continue
end end
@@ -938,8 +1006,15 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
elseif set and set[3] then HideLayer(set[3]) end elseif set and set[3] then HideLayer(set[3]) end
set = bd.Layers[draw_list] set = bd.Layers[draw_list]
if set then set.LastUsed = frame_no; set.Sig = sig end if set then set.LastUsed = frame_no; set.Sig = sig end
z = PlaceOverlays(bd, draw_list, z, ox, oy)
end end
-- Overlay frames not submitted this frame are hidden (never destroyed: the user owns them)
for frame, shown in pairs(bd.OverlayShown) do
if shown ~= frame_no then frame.Visible = false; bd.OverlayShown[frame] = nil end
end
table.clear(bd.Overlays)
-- Hide layers not drawn this frame; free long unused ones (closed windows, old tooltips) -- Hide layers not drawn this frame; free long unused ones (closed windows, old tooltips)
for draw_list, set in pairs(bd.Layers) do for draw_list, set in pairs(bd.Layers) do
if set.LastUsed ~= frame_no then if set.LastUsed ~= frame_no then
@@ -980,7 +1055,7 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
local bd = { local bd = {
Time = os.clock(), Gui = gui, Connections = {}, Time = os.clock(), Gui = gui, Connections = {},
Textures = {}, TextureCount = 0, MouseX = -1, MouseY = -1, Textures = {}, TextureCount = 0, MouseX = -1, MouseY = -1,
Layers = {}, FrameNo = 0, Scale = render_scale or 1, TilesActive = false, RenderRate = 60, BusyRenderRate = 0, NextRender = 0, LastPrimCount = 0, ForceRedraw = true, Layers = {}, Overlays = {}, OverlayHolders = {}, OverlayShown = {}, FrameNo = 0, Scale = render_scale or 1, TilesActive = false, RenderRate = 60, BusyRenderRate = 0, NextRender = 0, LastPrimCount = 0, ForceRedraw = true,
} }
io.BackendPlatformUserData = bd io.BackendPlatformUserData = bd
@@ -1115,6 +1190,8 @@ ImGui_ImplRoblox = {
AddFile = ImGui_ImplRoblox_AddFile, AddFile = ImGui_ImplRoblox_AddFile,
SetRenderScale = ImGui_ImplRoblox_SetRenderScale, SetRenderScale = ImGui_ImplRoblox_SetRenderScale,
SetRenderRate = ImGui_ImplRoblox_SetRenderRate, SetRenderRate = ImGui_ImplRoblox_SetRenderRate,
SetOverlay = ImGui_ImplRoblox_SetOverlay,
GetRenderScale = function() return ImGui_ImplRoblox_GetBackendData().Scale end,
SetBusyRenderRate = ImGui_ImplRoblox_SetBusyRenderRate, SetBusyRenderRate = ImGui_ImplRoblox_SetBusyRenderRate,
SetProfiling = ImGui_ImplRoblox_SetProfiling, SetProfiling = ImGui_ImplRoblox_SetProfiling,
IsProfiling = ImGui_ImplRoblox_IsProfiling, IsProfiling = ImGui_ImplRoblox_IsProfiling,
+1 -1
View File
@@ -1 +1 @@
[[12, "imgui.lua"], [18472, "imgui_demo.lua"], [25757, "imgui_draw.lua"], [30995, "imgui_h.lua"], [33193, "imgui_impl_roblox.lua"], [34319, "imgui_impl_roblox_fonts.lua"], [40722, "imgui_internal.lua"], [43894, "imgui_tables.lua"], [48241, "imgui_widgets.lua"], [57996, "imstb_rectpack.lua"], [58442, "imstb_textedit.lua"], [59683, "imstb_truetype.lua"], [62151, "imstd_minstdio.lua"]] [[12, "imgui.lua"], [18472, "imgui_demo.lua"], [25757, "imgui_draw.lua"], [30995, "imgui_h.lua"], [33193, "imgui_impl_roblox.lua"], [34396, "imgui_impl_roblox_fonts.lua"], [40799, "imgui_internal.lua"], [43971, "imgui_tables.lua"], [48318, "imgui_widgets.lua"], [58073, "imstb_rectpack.lua"], [58519, "imstb_textedit.lua"], [59760, "imstb_truetype.lua"], [62228, "imstd_minstdio.lua"]]
+80 -2
View File
@@ -33792,6 +33792,73 @@ local function DrawListSignature(draw_list, ox, oy)
return readstring(draw_list.VtxBuffer.Buf, 0, draw_list.VtxBuffer.Size * VTX_STRIDE) .. readstring(b, 0, o) return readstring(draw_list.VtxBuffer.Buf, 0, draw_list.VtxBuffer.Size * VTX_STRIDE) .. readstring(b, 0, o)
end end
-- Overlays: user Instances (e.g. a Frame holding a ViewportFrame) placed inside a window, registered every frame with
-- ImGui_ImplRoblox.SetOverlay() while that window is current. They stack right above the window's layers, move with
-- it, and (clip = true) are clipped to the window's content area like its widgets.
local function OverlayHolder(bd, draw_list, clip)
local hs = bd.OverlayHolders[draw_list]
if not hs then hs = {}; bd.OverlayHolders[draw_list] = hs end
local h = hs[clip]
if not h then
h = Instance.new("Frame")
h.Name = clip and "OverlayClip" or "Overlay"
h.BackgroundTransparency = 1
h.BorderSizePixel = 0
h.ClipsDescendants = clip
h.Size = UDim2.fromOffset(0, 0)
h.Parent = bd.Gui
hs[clip] = h
end
return h
end
local function PlaceOverlays(bd, draw_list, z, ox, oy)
local list = bd.Overlays[draw_list]
local hs = bd.OverlayHolders[draw_list]
if not list then
if hs then for _, h in pairs(hs) do h.Visible = false end end
return z
end
local scale, frame_no = bd.Scale, bd.FrameNo
z += 1
local used = {}
for _, o in ipairs(list) do
local clip = o.Clip and draw_list._ContentClipX0 ~= nil
local h = OverlayHolder(bd, draw_list, clip)
local hx, hy = 0, 0
if clip then
hx, hy = draw_list._ContentClipX0 - ox, draw_list._ContentClipY0 - oy
if not used[h] then
h.Position = UDim2.fromOffset(hx / scale, hy / scale)
h.Size = UDim2.fromOffset((draw_list._ContentClipX1 - draw_list._ContentClipX0) / scale, (draw_list._ContentClipY1 - draw_list._ContentClipY0) / scale)
end
elseif not used[h] then
h.Position = UDim2.fromOffset(0, 0)
end
used[h] = true
h.ZIndex = z
h.Visible = true
local f = o.Frame
if f.Parent ~= h then f.Parent = h end
f.Position = UDim2.fromOffset((o.X - ox - hx) / scale, (o.Y - oy - hy) / scale)
f.Size = UDim2.fromOffset(o.W / scale, o.H / scale)
f.Visible = true
bd.OverlayShown[f] = frame_no
end
if hs then for _, h in pairs(hs) do if not used[h] then h.Visible = false end end end
return z
end
--- Show `frame` this frame at (x, y, w, h) (imgui coordinates) inside the current window. Call every frame it should
--- be visible; frames not submitted are hidden. clip: clip to the window's content area (scrolls with it).
function ImGui_ImplRoblox_SetOverlay(frame, x, y, w, h, clip)
local bd = ImGui_ImplRoblox_GetBackendData()
local dl = ImGui.GetWindowDrawList()
local list = bd.Overlays[dl]
if not list then list = {}; bd.Overlays[dl] = list end
list[#list + 1] = { Frame = frame, X = x, Y = y, W = w, H = h, Clip = clip ~= false }
end
-- MicroProfiler labels, enabled with ImGui_ImplRoblox.SetProfiling(true) -- MicroProfiler labels, enabled with ImGui_ImplRoblox.SetProfiling(true)
local profilebegin, profileend = debug.profilebegin, debug.profileend local profilebegin, profileend = debug.profilebegin, debug.profileend
local profiling = false local profiling = false
@@ -33973,7 +34040,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
end end
if rate > 0 then if rate > 0 then
local now = os.clock() local now = os.clock()
if now + 0.002 < bd.NextRender then PE(); return end if now + 0.002 < bd.NextRender then table.clear(bd.Overlays); PE(); return end
bd.NextRender = math.max(bd.NextRender + 1 / rate, now) bd.NextRender = math.max(bd.NextRender + 1 / rate, now)
end end
@@ -34003,6 +34070,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
end end
end end
set.LastUsed = frame_no set.LastUsed = frame_no
z = PlaceOverlays(bd, draw_list, z, ox, oy)
PE() PE()
continue continue
end end
@@ -34130,8 +34198,15 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
elseif set and set[3] then HideLayer(set[3]) end elseif set and set[3] then HideLayer(set[3]) end
set = bd.Layers[draw_list] set = bd.Layers[draw_list]
if set then set.LastUsed = frame_no; set.Sig = sig end if set then set.LastUsed = frame_no; set.Sig = sig end
z = PlaceOverlays(bd, draw_list, z, ox, oy)
end end
-- Overlay frames not submitted this frame are hidden (never destroyed: the user owns them)
for frame, shown in pairs(bd.OverlayShown) do
if shown ~= frame_no then frame.Visible = false; bd.OverlayShown[frame] = nil end
end
table.clear(bd.Overlays)
-- Hide layers not drawn this frame; free long unused ones (closed windows, old tooltips) -- Hide layers not drawn this frame; free long unused ones (closed windows, old tooltips)
for draw_list, set in pairs(bd.Layers) do for draw_list, set in pairs(bd.Layers) do
if set.LastUsed ~= frame_no then if set.LastUsed ~= frame_no then
@@ -34172,7 +34247,7 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
local bd = { local bd = {
Time = os.clock(), Gui = gui, Connections = {}, Time = os.clock(), Gui = gui, Connections = {},
Textures = {}, TextureCount = 0, MouseX = -1, MouseY = -1, Textures = {}, TextureCount = 0, MouseX = -1, MouseY = -1,
Layers = {}, FrameNo = 0, Scale = render_scale or 1, TilesActive = false, RenderRate = 60, BusyRenderRate = 0, NextRender = 0, LastPrimCount = 0, ForceRedraw = true, Layers = {}, Overlays = {}, OverlayHolders = {}, OverlayShown = {}, FrameNo = 0, Scale = render_scale or 1, TilesActive = false, RenderRate = 60, BusyRenderRate = 0, NextRender = 0, LastPrimCount = 0, ForceRedraw = true,
} }
io.BackendPlatformUserData = bd io.BackendPlatformUserData = bd
@@ -34307,6 +34382,8 @@ ImGui_ImplRoblox = {
AddFile = ImGui_ImplRoblox_AddFile, AddFile = ImGui_ImplRoblox_AddFile,
SetRenderScale = ImGui_ImplRoblox_SetRenderScale, SetRenderScale = ImGui_ImplRoblox_SetRenderScale,
SetRenderRate = ImGui_ImplRoblox_SetRenderRate, SetRenderRate = ImGui_ImplRoblox_SetRenderRate,
SetOverlay = ImGui_ImplRoblox_SetOverlay,
GetRenderScale = function() return ImGui_ImplRoblox_GetBackendData().Scale end,
SetBusyRenderRate = ImGui_ImplRoblox_SetBusyRenderRate, SetBusyRenderRate = ImGui_ImplRoblox_SetBusyRenderRate,
SetProfiling = ImGui_ImplRoblox_SetProfiling, SetProfiling = ImGui_ImplRoblox_SetProfiling,
IsProfiling = ImGui_ImplRoblox_IsProfiling, IsProfiling = ImGui_ImplRoblox_IsProfiling,
@@ -62764,6 +62841,7 @@ return {
ImGui_ImplRoblox_NewFrame = ImGui_ImplRoblox_NewFrame, ImGui_ImplRoblox_NewFrame = ImGui_ImplRoblox_NewFrame,
ImGui_ImplRoblox_RenderDrawData = ImGui_ImplRoblox_RenderDrawData, ImGui_ImplRoblox_RenderDrawData = ImGui_ImplRoblox_RenderDrawData,
ImGui_ImplRoblox_SetBusyRenderRate = ImGui_ImplRoblox_SetBusyRenderRate, ImGui_ImplRoblox_SetBusyRenderRate = ImGui_ImplRoblox_SetBusyRenderRate,
ImGui_ImplRoblox_SetOverlay = ImGui_ImplRoblox_SetOverlay,
ImGui_ImplRoblox_SetProfiling = ImGui_ImplRoblox_SetProfiling, ImGui_ImplRoblox_SetProfiling = ImGui_ImplRoblox_SetProfiling,
ImGui_ImplRoblox_SetRenderRate = ImGui_ImplRoblox_SetRenderRate, ImGui_ImplRoblox_SetRenderRate = ImGui_ImplRoblox_SetRenderRate,
ImGui_ImplRoblox_SetRenderScale = ImGui_ImplRoblox_SetRenderScale, ImGui_ImplRoblox_SetRenderScale = ImGui_ImplRoblox_SetRenderScale,
+111
View File
@@ -81,6 +81,89 @@ ImGui_ImplRoblox.SetProfiling(true) -- MicroProfiler (Ctrl+F6) labels; turn off
local function P(name) if ImGui_ImplRoblox.IsProfiling() then debug.profilebegin(name) end end local function P(name) if ImGui_ImplRoblox.IsProfiling() then debug.profilebegin(name) end end
local function PE() if ImGui_ImplRoblox.IsProfiling() then debug.profileend() end end local function PE() if ImGui_ImplRoblox.IsProfiling() then debug.profileend() end end
--------------------------------------------------------------------------------------------------------------------
-- Custom widget: ImGui.Embed(id, size, flags, init) -> Frame
-- Reserves a widget-sized area in the current window and shows a real Frame there, so any Instances (UI, a
-- ViewportFrame, ...) can live inside an imgui window. Immediate-mode friendly:
-- * one Frame per id (per window, through the ID stack, like any widget); `init(frame)` runs only when it is created
-- * call it every frame the Frame should be visible; when it isn't called (window closed/collapsed, tab or tree node
-- closed, scrolled fully out of view) the Frame is hidden, never destroyed, so your Instances keep their state
-- * size uses imgui sizing (ImVec2(-1, h) = fill width, 0 = default), style gives padding/rounding/background/border
-- * returns the Frame: edit properties, add or remove children any time
-- ImGui.DestroyEmbed(id) removes it for good (call while the same window is current, like the widget itself).
--------------------------------------------------------------------------------------------------------------------
local EmbedFlags = {
None = 0,
NoClip = 1, -- don't clip to the window's content area (still moves/hides/stacks with the window)
NoBackground = 2, -- no FrameBg behind the Frame
NoBorder = 4, -- no style border
NoPadding = 8, -- no FramePadding inside the Frame (UIPadding)
NoRounding = 16, -- no FrameRounding corners (UICorner)
}
G.ImGuiEmbedFlags = EmbedFlags
local embeds = {} -- [ImGuiID] = { Frame, Padding, Corner }
function ImGui.Embed(id, size, flags, init)
flags = flags or EmbedFlags.None
local window = ImGui.GetCurrentWindow()
local gid = window:GetID(id)
local e = embeds[gid]
if not e then
local frame = Instance.new("Frame")
frame.Name = tostring(id)
frame.BackgroundTransparency = 1
frame.BorderSizePixel = 0
frame.Visible = false
e = { Frame = frame, Padding = Instance.new("UIPadding"), Corner = Instance.new("UICorner") }
e.Padding.Parent = frame
e.Corner.Parent = frame
embeds[gid] = e
if init then init(frame) end
end
if window.SkipItems then return e.Frame end
local style = ImGui.GetStyle()
local sz = ImGui.CalcItemSize(size or G.ImVec2(0, 0), ImGui.CalcItemWidth(), ImGui.GetFrameHeight() * 4)
local p = window.DC.CursorPos
local bb = G.ImRect(p.x, p.y, p.x + sz.x, p.y + sz.y)
ImGui.ItemSize(sz)
if not ImGui.ItemAdd(bb, gid) then return e.Frame end -- fully clipped: not submitted -> hidden this frame
local rounding = bit32.band(flags, EmbedFlags.NoRounding) == 0 and style.FrameRounding or 0
if bit32.band(flags, EmbedFlags.NoBackground) == 0 then
ImGui.RenderFrame(bb.Min, bb.Max, ImGui.GetColorU32(G.ImGuiCol.FrameBg), bit32.band(flags, EmbedFlags.NoBorder) == 0, rounding)
elseif bit32.band(flags, EmbedFlags.NoBorder) == 0 then
ImGui.RenderFrameBorder(bb.Min, bb.Max, rounding)
end
-- style -> Instances (only written when changed)
local scale = ImGui_ImplRoblox.GetRenderScale()
local px, py = 0, 0
if bit32.band(flags, EmbedFlags.NoPadding) == 0 then px, py = style.FramePadding.x / scale, style.FramePadding.y / scale end
if e.PX ~= px or e.PY ~= py then
e.PX, e.PY = px, py
e.Padding.PaddingLeft, e.Padding.PaddingRight = UDim.new(0, px), UDim.new(0, px)
e.Padding.PaddingTop, e.Padding.PaddingBottom = UDim.new(0, py), UDim.new(0, py)
end
if e.R ~= rounding then e.R = rounding; e.Corner.CornerRadius = UDim.new(0, rounding / scale) end
ImGui_ImplRoblox.SetOverlay(e.Frame, bb.Min.x, bb.Min.y, sz.x, sz.y, bit32.band(flags, EmbedFlags.NoClip) == 0)
return e.Frame
end
function ImGui.DestroyEmbed(id)
local gid = ImGui.GetCurrentWindow():GetID(id)
local e = embeds[gid]
if e then e.Frame:Destroy(); embeds[gid] = nil end
end
-- Example: a ViewportFrame with a spinning part, edited live from imgui widgets
local spin_speed = 1.0
local part_color = ImVec4(0.80, 0.65, 0.97, 1.0)
local spin_angle = 0.0
local show_viewport_window = true
RunService.Stepped:Connect(function() RunService.Stepped:Connect(function()
P("ImGui frame") P("ImGui frame")
ImGui_ImplRoblox.NewFrame() ImGui_ImplRoblox.NewFrame()
@@ -128,6 +211,34 @@ RunService.Stepped:Connect(function()
end end
PE() PE()
if show_viewport_window then
show_viewport_window = ImGui.Begin("Viewport", show_viewport_window)
spin_speed = ImGui.SliderFloat("speed", spin_speed, 0.0, 5.0)
ImGui.ColorEdit3("color", part_color)
local frame = ImGui.Embed("viewport", G.ImVec2(-1, 220), G.ImGuiEmbedFlags.None, function(f)
-- runs once
local vpf = Instance.new("ViewportFrame")
vpf.Size = UDim2.fromScale(1, 1)
vpf.BackgroundTransparency = 1
vpf.Parent = f
local cam = Instance.new("Camera")
cam.CFrame = CFrame.lookAt(Vector3.new(0, 2, 6), Vector3.new(0, 0, 0))
cam.Parent = vpf
vpf.CurrentCamera = cam
local part = Instance.new("Part")
part.Name = "Spinner"
part.Size = Vector3.new(2, 2, 2)
part.Parent = vpf
end)
-- every frame: edit what was created once
spin_angle += spin_speed * io.DeltaTime
local part = frame.ViewportFrame.Spinner
part.CFrame = CFrame.Angles(0.4, spin_angle, 0)
part.Color = Color3.new(part_color.x, part_color.y, part_color.z)
ImGui.Text("Frames created: 1 (same Frame every frame)")
ImGui.End()
end
P("ImGui.Render"); ImGui.EndFrame(); ImGui.Render(); PE() P("ImGui.Render"); ImGui.EndFrame(); ImGui.Render(); PE()
ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData()) ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
PE() PE()
+3 -1
View File
@@ -134,7 +134,7 @@ local fakeG = {} -- Roblox's shared _G
local cache = {} local cache = {}
local ROBLOX local ROBLOX
local function makeEnv(inst) return setmetatable({ script = inst }, { __index = ROBLOX }) end local function makeEnv(inst) return setmetatable({ script = inst }, { __index = ROBLOX }) end
local GLOBAL_NAMES = { "game", "workspace", "Instance", "Enum", "Vector2", "Vector3", "UDim2", "Color3", "Content", "warn", "require", "script", "os" } local GLOBAL_NAMES = { "game", "workspace", "Instance", "Enum", "Vector2", "Vector3", "UDim2", "Color3", "Content", "UDim", "CFrame", "warn", "require", "script", "os" }
-- Load like Roblox does but WITHOUT setfenv (which would disable Luau optimizations): Roblox globals become chunk locals. -- Load like Roblox does but WITHOUT setfenv (which would disable Luau optimizations): Roblox globals become chunk locals.
local function loadAsScript(src_name, inst) local function loadAsScript(src_name, inst)
local fn = SOURCE_FNS[src_name] local fn = SOURCE_FNS[src_name]
@@ -158,6 +158,8 @@ ROBLOX = setmetatable({
Vector3 = { new = function(x, y, z) return { X = x, Y = y, Z = z } end }, Vector3 = { new = function(x, y, z) return { X = x, Y = y, Z = z } end },
UDim2 = { new = function(...) return { ... } end, fromScale = function(...) return { ... } end, fromOffset = function(x, y) return { X = x, Y = y } end }, UDim2 = { new = function(...) return { ... } end, fromScale = function(...) return { ... } end, fromOffset = function(x, y) return { X = x, Y = y } end },
Color3 = { new = function(r, g, b) return { R = r or 0, G = g or 0, B = b or 0 } end }, Color3 = { new = function(r, g, b) return { R = r or 0, G = g or 0, B = b or 0 } end },
UDim = { new = function(s, o) return { Scale = s, Offset = o } end },
CFrame = { new = function(...) return { ... } end, lookAt = function(...) return { ... } end, Angles = function(...) return { ... } end },
Content = { fromObject = function(o) return { Object = o } end }, Content = { fromObject = function(o) return { Object = o } end },
warn = function(...) print("WARN", ...) end, warn = function(...) print("WARN", ...) end,
os = { clock = function() return FAKE_TIME end, time = os.time, realclock = os.clock }, os = { clock = function() return FAKE_TIME end, time = os.time, realclock = os.clock },
+1 -1
View File
@@ -12,7 +12,7 @@ TMP = tempfile.mkdtemp(prefix="imgui_test_") # per process: parallel runs must
HERE = os.path.dirname(os.path.abspath(__file__)) HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(os.path.dirname(HERE)) ROOT = os.path.dirname(os.path.dirname(HERE))
LUAU = shutil.which("luau") or "/nix/store/2m2ja613nndihc8qm10f2rhq6znp1nh4-luau-0.734/bin/luau" LUAU = shutil.which("luau") or "/nix/store/2m2ja613nndihc8qm10f2rhq6znp1nh4-luau-0.734/bin/luau"
G = "game, workspace, Instance, Enum, Vector2, Vector3, UDim2, Color3, Content, warn, require, script, os" G = "game, workspace, Instance, Enum, Vector2, Vector3, UDim2, Color3, Content, UDim, CFrame, warn, require, script, os"
def build_run(args, flags): def build_run(args, flags):
subprocess.run([sys.executable, os.path.join(ROOT, "tools", "bundle.py"), TMP] + (["--no-demo"] if os.environ.get("NO_DEMO") else []), check=True, stdout=subprocess.DEVNULL) subprocess.run([sys.executable, os.path.join(ROOT, "tools", "bundle.py"), TMP] + (["--no-demo"] if os.environ.get("NO_DEMO") else []), check=True, stdout=subprocess.DEVNULL)