Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1431d2e19d | ||
|
|
7eb7d5fcbb |
+1
-1
@@ -116,7 +116,7 @@ The Style Editor (`ImGui.ShowStyleEditor()`) and the Metrics/Debugger (`ImGui.Sh
|
|||||||
|
|
||||||
### Getting Started & Integration (Roblox)
|
### Getting Started & Integration (Roblox)
|
||||||
|
|
||||||
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/[email protected].2"` under `[dependencies]` in your `wally.toml`, run `wally install`, then `require(ReplicatedStorage.Packages.ImGui)`. Or from source:
|
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/[email protected].3"` under `[dependencies]` in your `wally.toml`, run `wally install`, then `require(ReplicatedStorage.Packages.ImGui)`. Or from source:
|
||||||
|
|
||||||
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out) and `build/ImGuiTyped.luau`, a small typed entry module (Luau types for the public `ImGui.*` API, `ImVec2`/`ImVec4` and the flag enums) that requires `build/ImGui.luau` as its child `Impl`. The Wally package and the Rojo projects use that layout, so you get autocomplete and type errors in `--!strict` scripts. The single-file `ImGui.luau` also works on its own, just untyped.
|
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out) and `build/ImGuiTyped.luau`, a small typed entry module (Luau types for the public `ImGui.*` API, `ImVec2`/`ImVec4` and the flag enums) that requires `build/ImGui.luau` as its child `Impl`. The Wally package and the Rojo projects use that layout, so you get autocomplete and type errors in `--!strict` scripts. The single-file `ImGui.luau` also works on its own, just untyped.
|
||||||
2. Sync with [Rojo](https://rojo.space): [`default.project.json`](/default.project.json) puts the module in `ReplicatedStorage.ImGui` and the example LocalScript in `StarterPlayerScripts`.
|
2. Sync with [Rojo](https://rojo.space): [`default.project.json`](/default.project.json) puts the module in `ReplicatedStorage.ImGui` and the example LocalScript in `StarterPlayerScripts`.
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ The Style Editor (`ImGui.ShowStyleEditor()`) and the Metrics/Debugger (`ImGui.Sh
|
|||||||
|
|
||||||
### Getting Started & Integration (Roblox)
|
### Getting Started & Integration (Roblox)
|
||||||
|
|
||||||
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/[email protected].2"` under `[dependencies]` in your `wally.toml`, run `wally install`, then `require(ReplicatedStorage.Packages.ImGui)`. Or from source:
|
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/[email protected].3"` under `[dependencies]` in your `wally.toml`, run `wally install`, then `require(ReplicatedStorage.Packages.ImGui)`. Or from source:
|
||||||
|
|
||||||
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out) and `build/ImGuiTyped.luau`, a small typed entry module (Luau types for the public `ImGui.*` API, `ImVec2`/`ImVec4` and the flag enums) that requires `build/ImGui.luau` as its child `Impl`. The Wally package and the Rojo projects use that layout, so you get autocomplete and type errors in `--!strict` scripts. The single-file `ImGui.luau` also works on its own, just untyped.
|
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out) and `build/ImGuiTyped.luau`, a small typed entry module (Luau types for the public `ImGui.*` API, `ImVec2`/`ImVec4` and the flag enums) that requires `build/ImGui.luau` as its child `Impl`. The Wally package and the Rojo projects use that layout, so you get autocomplete and type errors in `--!strict` scripts. The single-file `ImGui.luau` also works on its own, just untyped.
|
||||||
2. Sync with [Rojo](https://rojo.space): [`default.project.json`](default.project.json) puts the module in `ReplicatedStorage.ImGui` and the example LocalScript in `StarterPlayerScripts`.
|
2. Sync with [Rojo](https://rojo.space): [`default.project.json`](default.project.json) puts the module in `ReplicatedStorage.ImGui` and the example LocalScript in `StarterPlayerScripts`.
|
||||||
|
|||||||
@@ -862,7 +862,8 @@ 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 table.clear(bd.Overlays); PE(); return end
|
-- Skipped: kept pending, so if no new frame comes (the app stopped rendering) Heartbeat still draws it
|
||||||
|
if now + 0.002 < bd.NextRender then bd.Pending = draw_data; PE(); return end
|
||||||
bd.NextRender = math.max(bd.NextRender + 1 / rate, now)
|
bd.NextRender = math.max(bd.NextRender + 1 / rate, now)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1129,6 +1130,16 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
|||||||
|
|
||||||
bd.PendingChars = {}
|
bd.PendingChars = {}
|
||||||
|
|
||||||
|
-- Render rate cap trailing edge: the last frame submitted is always drawn, even if it was skipped and the app
|
||||||
|
-- then stopped calling NewFrame (e.g. it rendered one empty frame to hide its windows)
|
||||||
|
connect(game:GetService("RunService").Heartbeat, function()
|
||||||
|
local d = bd.Pending
|
||||||
|
if d and os.clock() + 0.002 >= bd.NextRender then
|
||||||
|
bd.Pending = nil
|
||||||
|
ImGui_ImplRoblox_RenderDrawData(d)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
connect(UserInputService.WindowFocused, function() ImGui.GetIO():AddFocusEvent(true) end)
|
connect(UserInputService.WindowFocused, function() ImGui.GetIO():AddFocusEvent(true) end)
|
||||||
connect(UserInputService.WindowFocusReleased, function() ImGui.GetIO():AddFocusEvent(false) end)
|
connect(UserInputService.WindowFocusReleased, function() ImGui.GetIO():AddFocusEvent(false) end)
|
||||||
end
|
end
|
||||||
@@ -1188,6 +1199,7 @@ function ImGui_ImplRoblox_NewFrame()
|
|||||||
PB("ImGui NewFrame (backend)")
|
PB("ImGui NewFrame (backend)")
|
||||||
local io = ImGui.GetIO()
|
local io = ImGui.GetIO()
|
||||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||||
|
if bd.Pending then bd.Pending = nil; table.clear(bd.Overlays) end -- skipped frame superseded (its draw lists get reset)
|
||||||
|
|
||||||
local screen = bd.Gui.AbsoluteSize
|
local screen = bd.Gui.AbsoluteSize
|
||||||
local w, h = floor(screen.X * bd.Scale), floor(screen.Y * bd.Scale)
|
local w, h = floor(screen.X * bd.Scale), floor(screen.Y * bd.Scale)
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[[12, "imgui.lua"], [18510, "imgui_demo.lua"], [25795, "imgui_draw.lua"], [31033, "imgui_h.lua"], [33231, "imgui_impl_roblox.lua"], [34571, "imgui_impl_roblox_fonts.lua"], [40974, "imgui_internal.lua"], [44150, "imgui_tables.lua"], [48497, "imgui_widgets.lua"], [58252, "imstb_rectpack.lua"], [58698, "imstb_textedit.lua"], [59939, "imstb_truetype.lua"], [62407, "imstd_minstdio.lua"]]
|
[[12, "imgui.lua"], [18514, "imgui_demo.lua"], [25799, "imgui_draw.lua"], [31037, "imgui_h.lua"], [33235, "imgui_impl_roblox.lua"], [34587, "imgui_impl_roblox_fonts.lua"], [40990, "imgui_internal.lua"], [44166, "imgui_tables.lua"], [48513, "imgui_widgets.lua"], [58268, "imstb_rectpack.lua"], [58714, "imstb_textedit.lua"], [59955, "imstb_truetype.lua"], [62423, "imstd_minstdio.lua"]]
|
||||||
+18
-2
@@ -8637,9 +8637,13 @@ local function RenderWindowDecorations(window, title_bar_rect, title_bar_is_high
|
|||||||
end
|
end
|
||||||
|
|
||||||
if override_alpha then
|
if override_alpha then
|
||||||
bg_col = bit32.band(bg_col, bit32.bnot(IM_COL32_A_MASK)) or bit32.lshift(IM_F32_TO_INT8_SAT(alpha), IM_COL32_A_SHIFT)
|
bg_col = bit32.bor(bit32.band(bg_col, bit32.bnot(IM_COL32_A_MASK)), bit32.lshift(IM_F32_TO_INT8_SAT(alpha), IM_COL32_A_SHIFT))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Render, for docked windows and host windows we ensure BG goes before decorations
|
||||||
|
if window.DockIsActive then window.DockNode.LastBgColor = bg_col end
|
||||||
|
if bit32.band(flags, ImGuiWindowFlags.DockNodeHost) ~= 0 then bg_col = 0 end
|
||||||
|
|
||||||
if bit32.band(bg_col, IM_COL32_A_MASK) ~= 0 then
|
if bit32.band(bg_col, IM_COL32_A_MASK) ~= 0 then
|
||||||
local bg_rect = ImRect(window.Pos + ImVec2(0, window.TitleBarHeight), window.Pos + window.Size)
|
local bg_rect = ImRect(window.Pos + ImVec2(0, window.TitleBarHeight), window.Pos + window.Size)
|
||||||
local bg_rounding_flags
|
local bg_rounding_flags
|
||||||
@@ -34092,7 +34096,8 @@ 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 table.clear(bd.Overlays); PE(); return end
|
-- Skipped: kept pending, so if no new frame comes (the app stopped rendering) Heartbeat still draws it
|
||||||
|
if now + 0.002 < bd.NextRender then bd.Pending = draw_data; PE(); return end
|
||||||
bd.NextRender = math.max(bd.NextRender + 1 / rate, now)
|
bd.NextRender = math.max(bd.NextRender + 1 / rate, now)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -34359,6 +34364,16 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
|||||||
|
|
||||||
bd.PendingChars = {}
|
bd.PendingChars = {}
|
||||||
|
|
||||||
|
-- Render rate cap trailing edge: the last frame submitted is always drawn, even if it was skipped and the app
|
||||||
|
-- then stopped calling NewFrame (e.g. it rendered one empty frame to hide its windows)
|
||||||
|
connect(game:GetService("RunService").Heartbeat, function()
|
||||||
|
local d = bd.Pending
|
||||||
|
if d and os.clock() + 0.002 >= bd.NextRender then
|
||||||
|
bd.Pending = nil
|
||||||
|
ImGui_ImplRoblox_RenderDrawData(d)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
connect(UserInputService.WindowFocused, function() ImGui.GetIO():AddFocusEvent(true) end)
|
connect(UserInputService.WindowFocused, function() ImGui.GetIO():AddFocusEvent(true) end)
|
||||||
connect(UserInputService.WindowFocusReleased, function() ImGui.GetIO():AddFocusEvent(false) end)
|
connect(UserInputService.WindowFocusReleased, function() ImGui.GetIO():AddFocusEvent(false) end)
|
||||||
end
|
end
|
||||||
@@ -34418,6 +34433,7 @@ function ImGui_ImplRoblox_NewFrame()
|
|||||||
PB("ImGui NewFrame (backend)")
|
PB("ImGui NewFrame (backend)")
|
||||||
local io = ImGui.GetIO()
|
local io = ImGui.GetIO()
|
||||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||||
|
if bd.Pending then bd.Pending = nil; table.clear(bd.Overlays) end -- skipped frame superseded (its draw lists get reset)
|
||||||
|
|
||||||
local screen = bd.Gui.AbsoluteSize
|
local screen = bd.Gui.AbsoluteSize
|
||||||
local w, h = floor(screen.X * bd.Scale), floor(screen.Y * bd.Scale)
|
local w, h = floor(screen.X * bd.Scale), floor(screen.Y * bd.Scale)
|
||||||
|
|||||||
@@ -8626,9 +8626,13 @@ local function RenderWindowDecorations(window, title_bar_rect, title_bar_is_high
|
|||||||
end
|
end
|
||||||
|
|
||||||
if override_alpha then
|
if override_alpha then
|
||||||
bg_col = bit32.band(bg_col, bit32.bnot(IM_COL32_A_MASK)) or bit32.lshift(IM_F32_TO_INT8_SAT(alpha), IM_COL32_A_SHIFT)
|
bg_col = bit32.bor(bit32.band(bg_col, bit32.bnot(IM_COL32_A_MASK)), bit32.lshift(IM_F32_TO_INT8_SAT(alpha), IM_COL32_A_SHIFT))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Render, for docked windows and host windows we ensure BG goes before decorations
|
||||||
|
if window.DockIsActive then window.DockNode.LastBgColor = bg_col end
|
||||||
|
if bit32.band(flags, ImGuiWindowFlags.DockNodeHost) ~= 0 then bg_col = 0 end
|
||||||
|
|
||||||
if bit32.band(bg_col, IM_COL32_A_MASK) ~= 0 then
|
if bit32.band(bg_col, IM_COL32_A_MASK) ~= 0 then
|
||||||
local bg_rect = ImRect(window.Pos + ImVec2(0, window.TitleBarHeight), window.Pos + window.Size)
|
local bg_rect = ImRect(window.Pos + ImVec2(0, window.TitleBarHeight), window.Pos + window.Size)
|
||||||
local bg_rounding_flags
|
local bg_rounding_flags
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
-- Docked windows (floating split node) stop being submitted: the host lingers one frame, its bodies must be filled
|
||||||
|
-- with the windows' bg colour (node.LastBgColor), not white, and everything must be gone within a few frames.
|
||||||
|
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||||
|
local RunService = game:GetService("RunService")
|
||||||
|
local G = require(ReplicatedStorage:WaitForChild("ImGui"))
|
||||||
|
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
||||||
|
ImGui.CreateContext()
|
||||||
|
local io = ImGui.GetIO()
|
||||||
|
io.ConfigFlags = bit32.bor(io.ConfigFlags, G.ImGuiConfigFlags.DockingEnable)
|
||||||
|
G.ImGui_ImplRoblox.Init()
|
||||||
|
local frame, closed_at, done = 0, 31, false
|
||||||
|
RunService.Stepped:Connect(function()
|
||||||
|
if done then return end
|
||||||
|
frame += 1
|
||||||
|
G.ImGui_ImplRoblox.NewFrame()
|
||||||
|
ImGui.NewFrame()
|
||||||
|
if frame == 2 then
|
||||||
|
local id = ImGui.GetID("floating")
|
||||||
|
ImGui.DockBuilderRemoveNode(id)
|
||||||
|
ImGui.DockBuilderAddNode(id, 0)
|
||||||
|
ImGui.DockBuilderSetNodePos(id, ImVec2(100, 100))
|
||||||
|
ImGui.DockBuilderSetNodeSize(id, ImVec2(600, 400))
|
||||||
|
local left, right = ImGui.DockBuilderSplitNode(id, G.ImGuiDir.Left, 0.5)
|
||||||
|
ImGui.DockBuilderDockWindow("A", left)
|
||||||
|
ImGui.DockBuilderDockWindow("B", right)
|
||||||
|
ImGui.DockBuilderFinish(id)
|
||||||
|
end
|
||||||
|
if frame < closed_at then
|
||||||
|
for _, n in { "A", "B" } do
|
||||||
|
if ImGui.Begin(n) then ImGui.Text("window " .. n) end
|
||||||
|
ImGui.End()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if frame == closed_at - 1 then
|
||||||
|
local a, b = ImGui.FindWindowByName("A"), ImGui.FindWindowByName("B")
|
||||||
|
assert(a.DockNode and b.DockNode and a.DockNode ~= b.DockNode and a.DockNode.HostWindow, "A, B docked side by side")
|
||||||
|
end
|
||||||
|
ImGui.Render()
|
||||||
|
local dd = ImGui.GetDrawData()
|
||||||
|
if frame >= closed_at then
|
||||||
|
for _, dl in dd.CmdLists:iter() do
|
||||||
|
-- white vertices spanning a big area = a white body fill (white text glyphs are small)
|
||||||
|
local vb, x0, y0, x1, y1 = dl.VtxBuffer.Buf, math.huge, math.huge, -math.huge, -math.huge
|
||||||
|
for _, pcmd in dl.CmdBuffer:iter() do
|
||||||
|
for i = pcmd.IdxOffset + 1, pcmd.IdxOffset + pcmd.ElemCount do
|
||||||
|
local o = (pcmd.VtxOffset + dl.IdxBuffer.Data[i] - 1) * G.VTX_STRIDE
|
||||||
|
if buffer.readu32(vb, o + 32) == 0xFFFFFFFF then
|
||||||
|
local x, y = buffer.readf64(vb, o), buffer.readf64(vb, o + 8)
|
||||||
|
x0, y0, x1, y1 = math.min(x0, x), math.min(y0, y), math.max(x1, x), math.max(y1, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(not (x1 - x0 > 100 and y1 - y0 > 100), "white fill on frame " .. frame)
|
||||||
|
end
|
||||||
|
if dd.TotalVtxCount == 0 then
|
||||||
|
G.ImGui_ImplRoblox.RenderDrawData(dd)
|
||||||
|
for _, set in io.BackendPlatformUserData.Layers do
|
||||||
|
for kind = 1, 3 do assert(not (set[kind] and set[kind].Visible), "backend layer still visible after close") end
|
||||||
|
end
|
||||||
|
print("DOCK CLOSE OK after", frame - closed_at + 1, "frames")
|
||||||
|
done = true
|
||||||
|
return
|
||||||
|
else
|
||||||
|
assert(frame < closed_at + 3, "docked windows still drawn " .. (frame - closed_at + 1) .. " frames after close")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
G.ImGui_ImplRoblox.RenderDrawData(dd)
|
||||||
|
end)
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "4dbug/imgui-luau"
|
name = "4dbug/imgui-luau"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
registry = "https://github.com/UpliftGames/wally-index"
|
registry = "https://github.com/UpliftGames/wally-index"
|
||||||
realm = "shared"
|
realm = "shared"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
Reference in New Issue
Block a user