Draw list 1.93 strokes: _AddPolyline ported (texture AA lines, joins/miter/bevel, CapSquare, AALineEnds, Stroke Inside/Center/CenterBiased/Outside/Legacy), AddConvexPolyFilled AAFill, all primitives with 1.93 signatures/flags, PathRect/PathArcTo 1.93, baked line textures; Custom Rendering demo flags UI restored. check_all: t_pixels incremental==full redraw, headless screenshot (tools/test/shot.py)
This commit is contained in:
@@ -1 +1 @@
|
|||||||
[[46, "imgui.lua"], [21461, "imgui_demo.lua"], [33299, "imgui_draw.lua"], [39279, "imgui_h.lua"], [42185, "imgui_impl_roblox.lua"], [43833, "imgui_impl_roblox_fonts.lua"], [50236, "imgui_internal.lua"], [53945, "imgui_tables.lua"], [59004, "imgui_widgets.lua"], [70993, "imstb_rectpack.lua"], [71657, "imstb_textedit.lua"], [73199, "imstb_truetype.lua"], [75987, "imstd_minstdio.lua"]]
|
[[46, "imgui.lua"], [21461, "imgui_demo.lua"], [33313, "imgui_draw.lua"], [40456, "imgui_h.lua"], [43362, "imgui_impl_roblox.lua"], [45010, "imgui_impl_roblox_fonts.lua"], [51413, "imgui_internal.lua"], [55122, "imgui_tables.lua"], [60181, "imgui_widgets.lua"], [72170, "imstb_rectpack.lua"], [72834, "imstb_textedit.lua"], [74376, "imstb_truetype.lua"], [77164, "imstd_minstdio.lua"]]
|
||||||
+1783
-606
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
|||||||
[[183, "imgui.lua"], [21598, "imgui_demo.lua"], [33436, "imgui_draw.lua"], [39416, "imgui_h.lua"], [42322, "imgui_impl_love.lua"], [42862, "imgui_internal.lua"], [46571, "imgui_tables.lua"], [51630, "imgui_widgets.lua"], [63619, "imstb_rectpack.lua"], [64283, "imstb_textedit.lua"], [65825, "imstb_truetype.lua"], [68613, "imstd_minstdio.lua"]]
|
[[183, "imgui.lua"], [21598, "imgui_demo.lua"], [33450, "imgui_draw.lua"], [40593, "imgui_h.lua"], [43499, "imgui_impl_love.lua"], [44039, "imgui_internal.lua"], [47748, "imgui_tables.lua"], [52807, "imgui_widgets.lua"], [64796, "imstb_rectpack.lua"], [65460, "imstb_textedit.lua"], [67002, "imstb_truetype.lua"], [69790, "imstd_minstdio.lua"]]
|
||||||
+1783
-606
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -65,5 +65,5 @@ there, but keep this port's existing data structures and conventions. Read the s
|
|||||||
|
|
||||||
- **ImGuiAxis is 1-based in this port** (`None=0, X=1, Y=2`; upstream `None=-1, X=0, Y=1`). Use `v[axis]` to index an ImVec2 and `3 - axis` for the other axis. `ImGuiDir` keeps upstream values (`None=-1, Left=0, Right=1, Up=2, Down=3`).
|
- **ImGuiAxis is 1-based in this port** (`None=0, X=1, Y=2`; upstream `None=-1, X=0, Y=1`). Use `v[axis]` to index an ImVec2 and `3 - axis` for the other axis. `ImGuiDir` keeps upstream values (`None=-1, Left=0, Right=1, Up=2, Down=3`).
|
||||||
- Never write `cond and nil or x` in Lua: it always evaluates `x`. Use an `if`.
|
- Never write `cond and nil or x` in Lua: it always evaluates `x`. Use an `if`.
|
||||||
- Port signature quirk: `AddRect(min, max, col, rounding, thickness, flags)` (thickness BEFORE flags; upstream has flags first). Check the port's signature before porting any draw call that takes both.\n
|
- Draw calls taking both thickness and flags use upstream's 1.92.8+ order: thickness BEFORE flags, e.g. `AddRect(min, max, col, rounding, thickness, flags)`, `PathStroke(col, thickness, flags)`, `AddPolyline(points, count, col, thickness, flags)`.
|
||||||
- C++ default arguments (e.g. `bool x = true`) must be reproduced with `if x == nil then x = true end`; a missing Lua argument is nil/falsy.
|
- C++ default arguments (e.g. `bool x = true`) must be reproduced with `if x == nil then x = true end`; a missing Lua argument is nil/falsy.
|
||||||
|
|||||||
+662
-662
File diff suppressed because it is too large
Load Diff
+38
-24
@@ -10413,6 +10413,9 @@ S.ShowExampleAppCustomRendering = {
|
|||||||
curve_segments_override_v = 8,
|
curve_segments_override_v = 8,
|
||||||
colf_stroke = ImVec4(1.000, 0.384, 0.169, 1.000),
|
colf_stroke = ImVec4(1.000, 0.384, 0.169, 1.000),
|
||||||
colf_fill = ImVec4(0.416, 0.378, 0.420, 1.000),
|
colf_fill = ImVec4(0.416, 0.378, 0.420, 1.000),
|
||||||
|
prim_stroke_flags = ImDrawFlags.None,
|
||||||
|
prim_other_flags = ImDrawFlags.AALineEnds,
|
||||||
|
scope_flags = nil, -- First init copy current state (see below).
|
||||||
-- Canvas
|
-- Canvas
|
||||||
points = ImVector(),
|
points = ImVector(),
|
||||||
scrolling = ImVec2(0.0, 0.0),
|
scrolling = ImVec2(0.0, 0.0),
|
||||||
@@ -10496,25 +10499,35 @@ function ShowExampleAppCustomRendering(p_open)
|
|||||||
ImGui.ColorEdit4("Stroke Color", s.colf_stroke)
|
ImGui.ColorEdit4("Stroke Color", s.colf_stroke)
|
||||||
ImGui.ColorEdit4("Fill Color", s.colf_fill)
|
ImGui.ColorEdit4("Fill Color", s.colf_fill)
|
||||||
|
|
||||||
-- [Port] ImDrawFlags_StrokeInside/StrokeCenter/StrokeCenterBiased/StrokeOutside/StrokeLegacy, AAFill/AALines/AALineEnds,
|
|
||||||
-- [Port] JoinMiter/CapSquare, AllowInPushScope_ and ImDrawList::PushDrawFlag()/PopDrawFlag() don't exist in this port
|
|
||||||
-- [Port] (1.92 stroker): prim_stroke_flags/prim_other_flags/scope_flags and their widgets are not ported, flags = None.
|
|
||||||
ImGui.SeparatorText("Per primitive flags (AddXXX functions)")
|
ImGui.SeparatorText("Per primitive flags (AddXXX functions)")
|
||||||
ImGui.TextDisabled("(not supported by this port)") -- [Port]
|
_, s.prim_stroke_flags = ImGui.RadioButton("Default", s.prim_stroke_flags, ImDrawFlags.None); ImGui.SameLine()
|
||||||
|
_, s.prim_stroke_flags = ImGui.RadioButton("Inside", s.prim_stroke_flags, ImDrawFlags.StrokeInside); ImGui.SameLine()
|
||||||
|
_, s.prim_stroke_flags = ImGui.RadioButton("Center", s.prim_stroke_flags, ImDrawFlags.StrokeCenter); ImGui.SameLine()
|
||||||
|
_, s.prim_stroke_flags = ImGui.RadioButton("CenterBiased", s.prim_stroke_flags, ImDrawFlags.StrokeCenterBiased); ImGui.SameLine()
|
||||||
|
_, s.prim_stroke_flags = ImGui.RadioButton("Outside", s.prim_stroke_flags, ImDrawFlags.StrokeOutside); ImGui.SameLine()
|
||||||
|
_, s.prim_stroke_flags = ImGui.RadioButton("Legacy", s.prim_stroke_flags, ImDrawFlags.StrokeLegacy)
|
||||||
|
_, s.prim_other_flags = ImGui.CheckboxFlags("AAFill", s.prim_other_flags, ImDrawFlags.AAFill); ImGui.SameLine() -- Note: Only for functions taking flags.
|
||||||
|
_, s.prim_other_flags = ImGui.CheckboxFlags("AALines", s.prim_other_flags, ImDrawFlags.AALines); ImGui.SameLine() -- Note: Only for functions taking flags.
|
||||||
|
_, s.prim_other_flags = ImGui.CheckboxFlags("AALineEnds", s.prim_other_flags, ImDrawFlags.AALineEnds); ImGui.SameLine()
|
||||||
|
_, s.prim_other_flags = ImGui.CheckboxFlags("JoinMiter", s.prim_other_flags, ImDrawFlags.JoinMiter); ImGui.SameLine()
|
||||||
|
_, s.prim_other_flags = ImGui.CheckboxFlags("CapSquare", s.prim_other_flags, ImDrawFlags.CapSquare)
|
||||||
--ImGui.CheckboxFlags("UseTexForRoundCorners", &prim_other_flags, ImDrawFlags_UseTexForRoundCorners);
|
--ImGui.CheckboxFlags("UseTexForRoundCorners", &prim_other_flags, ImDrawFlags_UseTexForRoundCorners);
|
||||||
|
|
||||||
|
if s.scope_flags == nil then s.scope_flags = bit32.band(draw_list.Flags, ImDrawFlags.AllowInPushScope_) end -- First init copy current state.
|
||||||
ImGui.SeparatorText("Current ImDrawList flags (e.g. PushDrawFlag function)")
|
ImGui.SeparatorText("Current ImDrawList flags (e.g. PushDrawFlag function)")
|
||||||
ImGui.PushID("ScopeFlags")
|
ImGui.PushID("ScopeFlags")
|
||||||
ImGui.TextDisabled("(not supported by this port)") -- [Port]
|
_, s.scope_flags = ImGui.CheckboxFlags("AAFill", s.scope_flags, ImDrawFlags.AAFill); ImGui.SameLine()
|
||||||
|
_, s.scope_flags = ImGui.CheckboxFlags("AALines", s.scope_flags, ImDrawFlags.AALines); ImGui.SameLine()
|
||||||
|
_, s.scope_flags = ImGui.CheckboxFlags("AALineEnds", s.scope_flags, ImDrawFlags.AALineEnds); ImGui.SameLine()
|
||||||
|
_, s.scope_flags = ImGui.CheckboxFlags("StrokeLegacy", s.scope_flags, ImDrawFlags.StrokeLegacy)
|
||||||
--ImGui.CheckboxFlags("UseTexForRoundCorners", &scope_flags, ImDrawFlags_UseTexForRoundCorners);
|
--ImGui.CheckboxFlags("UseTexForRoundCorners", &scope_flags, ImDrawFlags_UseTexForRoundCorners);
|
||||||
ImGui.PopID()
|
ImGui.PopID()
|
||||||
ImGui.Spacing()
|
ImGui.Spacing()
|
||||||
|
|
||||||
-- [Port] draw_list->PushDrawFlag(ImDrawFlags_AllowInPushScope_, false); // Reset all existing (very unusual: done for this demo)
|
draw_list:PushDrawFlag(ImDrawFlags.AllowInPushScope_, false) -- Reset all existing (very unusual: done for this demo)
|
||||||
-- [Port] draw_list->PushDrawFlag(scope_flags, true);
|
draw_list:PushDrawFlag(s.scope_flags, true)
|
||||||
local flags = ImDrawFlags.None -- [Port] prim_stroke_flags | prim_other_flags
|
local flags = bit32.bor(s.prim_stroke_flags, s.prim_other_flags)
|
||||||
|
|
||||||
-- [Port] In this port AddNgon/AddCircle/AddEllipse/AddTriangle/AddLine*/AddBezier*/PathFillConvex take no flags argument (dropped below).
|
|
||||||
local sz = s.sz
|
local sz = s.sz
|
||||||
local start_pos = ImGui.GetCursorScreenPos()
|
local start_pos = ImGui.GetCursorScreenPos()
|
||||||
local pi = 3.141592
|
local pi = 3.141592
|
||||||
@@ -10582,7 +10595,7 @@ function ShowExampleAppCustomRendering(p_open)
|
|||||||
for n = 0, 4 - 1 do
|
for n = 0, 4 - 1 do
|
||||||
draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n + 1].x, y + half_sz + rotating_square[n + 1].y))
|
draw_list:PathLineTo(ImVec2(x + half_sz + rotating_square[n + 1].x, y + half_sz + rotating_square[n + 1].y))
|
||||||
end
|
end
|
||||||
draw_list:PathFillConvex(col) -- [Port] no flags argument
|
draw_list:PathFillConvex(col, flags)
|
||||||
x = x + step
|
x = x + step
|
||||||
|
|
||||||
-- Path
|
-- Path
|
||||||
@@ -10609,14 +10622,14 @@ function ShowExampleAppCustomRendering(p_open)
|
|||||||
-- First row uses a thickness of 1.0f, second row uses the configurable thickness
|
-- First row uses a thickness of 1.0f, second row uses the configurable thickness
|
||||||
local col = ImColor(s.colf_stroke):U32()
|
local col = ImColor(s.colf_stroke):U32()
|
||||||
local th = (row == 0) and 1.0 or thickness
|
local th = (row == 0) and 1.0 or thickness
|
||||||
draw_list:AddNgon(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments, th); x = x + step -- N-gon
|
draw_list:AddNgon(ImVec2(x + half_sz, y + half_sz), half_sz, col, s.ngon_segments, th, flags); x = x + step -- N-gon
|
||||||
draw_list:AddCircle(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments, th); x = x + step -- Circle
|
draw_list:AddCircle(ImVec2(x + half_sz, y + half_sz), half_sz, col, circle_segments, th, flags); x = x + step -- Circle
|
||||||
draw_list:AddEllipse(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments, th); x = x + step -- Ellipse
|
draw_list:AddEllipse(ImVec2(x + half_sz, y + half_sz), ImVec2(half_sz, sz * 0.3), col, -0.3, circle_segments, th, flags); x = x + step -- Ellipse
|
||||||
draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, th, flags); x = x + step -- Square
|
draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0, th, flags); x = x + step -- Square
|
||||||
draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, flags); x = x + step -- Square with all rounded corners
|
draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, flags); x = x + step -- Square with all rounded corners
|
||||||
draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, bit32.bor(flags, corners_tl_br)); x = x + step -- Square with two rounded corners
|
draw_list:AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, th, bit32.bor(flags, corners_tl_br)); x = x + step -- Square with two rounded corners
|
||||||
draw_list:AddTriangle(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col, th); x = x + step -- Triangle
|
draw_list:AddTriangle(ImVec2(x + sz * 0.5, y), ImVec2(x + sz, y + sz), ImVec2(x, y + sz), col, th, flags); x = x + step -- Triangle
|
||||||
draw_list:AddTriangle(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col, th); x = x + step - math.floor(sz * 0.6) -- Thin triangle
|
draw_list:AddTriangle(ImVec2(x + sz * 0.2, y), ImVec2(x + sz * 0.4, y + sz), ImVec2(x, y + sz), col, th, flags); x = x + step - math.floor(sz * 0.6) -- Thin triangle
|
||||||
|
|
||||||
-- Concave shape: U
|
-- Concave shape: U
|
||||||
for _, p in ipairs(concave_shape) do
|
for _, p in ipairs(concave_shape) do
|
||||||
@@ -10634,15 +10647,15 @@ function ShowExampleAppCustomRendering(p_open)
|
|||||||
|
|
||||||
-- Horizontal/Vertical/Diagonal lines
|
-- Horizontal/Vertical/Diagonal lines
|
||||||
local off = math.floor(sz * 0.4)
|
local off = math.floor(sz * 0.4)
|
||||||
draw_list:AddLineH(x, x + sz, y, col, th)
|
draw_list:AddLineH(x, x + sz, y, col, th, flags)
|
||||||
draw_list:AddLine(ImVec2(x, y + off), ImVec2(x + sz, y + off), col, th)
|
draw_list:AddLine(ImVec2(x, y + off), ImVec2(x + sz, y + off), col, th, flags)
|
||||||
x = x + step
|
x = x + step
|
||||||
draw_list:AddLineV(x, y, y + sz, col, th)
|
draw_list:AddLineV(x, y, y + sz, col, th, flags)
|
||||||
draw_list:AddLine(ImVec2(x + off, y + sz), ImVec2(x + off, y), col, th)
|
draw_list:AddLine(ImVec2(x + off, y + sz), ImVec2(x + off, y), col, th, flags)
|
||||||
x = x + step - math.floor(half_sz)
|
x = x + step - math.floor(half_sz)
|
||||||
if not (draw_fill and draw_strokes) then -- -V560
|
if not (draw_fill and draw_strokes) then -- -V560
|
||||||
draw_list:AddLine(ImVec2(x, y), ImVec2(x + half_sz, y + sz), col, th)
|
draw_list:AddLine(ImVec2(x, y), ImVec2(x + half_sz, y + sz), col, th, flags)
|
||||||
draw_list:AddLine(ImVec2(x, y + sz), ImVec2(x + half_sz, y), col, th)
|
draw_list:AddLine(ImVec2(x, y + sz), ImVec2(x + half_sz, y), col, th, flags)
|
||||||
end
|
end
|
||||||
x = x + step - math.floor(half_sz)
|
x = x + step - math.floor(half_sz)
|
||||||
|
|
||||||
@@ -10661,12 +10674,12 @@ function ShowExampleAppCustomRendering(p_open)
|
|||||||
x = x + step
|
x = x + step
|
||||||
|
|
||||||
-- Quadratic Bezier Curve (3 control points)
|
-- Quadratic Bezier Curve (3 control points)
|
||||||
draw_list:AddBezierQuadratic(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), col, th, curve_segments)
|
draw_list:AddBezierQuadratic(ImVec2(x + cp3[1].x, y + cp3[1].y), ImVec2(x + cp3[2].x, y + cp3[2].y), ImVec2(x + cp3[3].x, y + cp3[3].y), col, th, curve_segments, flags)
|
||||||
x = x + step
|
x = x + step
|
||||||
|
|
||||||
-- Cubic Bezier Curve (4 control points)
|
-- Cubic Bezier Curve (4 control points)
|
||||||
if not (draw_fill and draw_strokes) then -- -V560
|
if not (draw_fill and draw_strokes) then -- -V560
|
||||||
draw_list:AddBezierCubic(ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), ImVec2(x + cp4[4].x, y + cp4[4].y), col, th, curve_segments)
|
draw_list:AddBezierCubic(ImVec2(x + cp4[1].x, y + cp4[1].y), ImVec2(x + cp4[2].x, y + cp4[2].y), ImVec2(x + cp4[3].x, y + cp4[3].y), ImVec2(x + cp4[4].x, y + cp4[4].y), col, th, curve_segments, flags)
|
||||||
x = x + step
|
x = x + step
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -10674,7 +10687,8 @@ function ShowExampleAppCustomRendering(p_open)
|
|||||||
end
|
end
|
||||||
|
|
||||||
ImGui.Dummy(ImVec2(step * 15.5, step * 4.0))
|
ImGui.Dummy(ImVec2(step * 15.5, step * 4.0))
|
||||||
-- [Port] draw_list->PopDrawFlag(); x2
|
draw_list:PopDrawFlag()
|
||||||
|
draw_list:PopDrawFlag()
|
||||||
|
|
||||||
ImGui.Text("ImDrawList Vector Rendering Reference:")
|
ImGui.Text("ImDrawList Vector Rendering Reference:")
|
||||||
ImGui.TextLinkOpenURL("https://github.com/ocornut/imgui/wiki/Draw-List")
|
ImGui.TextLinkOpenURL("https://github.com/ocornut/imgui/wiki/Draw-List")
|
||||||
|
|||||||
+1744
-581
File diff suppressed because it is too large
Load Diff
@@ -32,6 +32,8 @@ CHECKS=(
|
|||||||
"libhash|LIBHASH|NO_DEMO=1 $R --main tools/test/scripts/t_libhash.luau --frames 120"
|
"libhash|LIBHASH|NO_DEMO=1 $R --main tools/test/scripts/t_libhash.luau --frames 120"
|
||||||
"demo_open|DRAWHASH|$R --main tools/test/scripts/t_drawhash.luau --frames 150 --open"
|
"demo_open|DRAWHASH|$R --main tools/test/scripts/t_drawhash.luau --frames 150 --open"
|
||||||
"demo_random|^|python3 tools/test/run.py --roblox --timeout 600 --frames 400 --open"
|
"demo_random|^|python3 tools/test/run.py --roblox --timeout 600 --frames 400 --open"
|
||||||
|
"pixels|PIXELS SAME|a=\$($R --main tools/test/scripts/t_pixels.luau --frames 600 | grep -P '^PIX\t'); b=\$(RUN_FLAGS=ARG_FORCE=true $R --main tools/test/scripts/t_pixels.luau --frames 600 | grep -P '^PIX\t'); [ -n \"\$a\" ] && [ \"\$a\" = \"\$b\" ] && echo PIXELS SAME"
|
||||||
|
"shot|wrote|python3 tools/test/shot.py /tmp/imgui_shot.png --app"
|
||||||
"love|DRAWHASH|python3 tools/bundle.py --target love >/dev/null && luajit tools/test/love/t_drawhash.lua 60 Widgets,Basic && luajit tools/test/love/t_examples.lua"
|
"love|DRAWHASH|python3 tools/bundle.py --target love >/dev/null && luajit tools/test/love/t_drawhash.lua 60 Widgets,Basic && luajit tools/test/love/t_examples.lua"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ set -e
|
|||||||
cd "$(dirname "$0")/../../.."
|
cd "$(dirname "$0")/../../.."
|
||||||
python3 tools/bundle.py --target love >/dev/null
|
python3 tools/bundle.py --target love >/dev/null
|
||||||
nix-shell -p luajit --run "luajit tools/test/love/t_drawhash.lua 150 Widgets,Basic && luajit tools/test/love/t_drawhash.lua 150 all && luajit tools/test/love/t_examples.lua"
|
nix-shell -p luajit --run "luajit tools/test/love/t_drawhash.lua 150 Widgets,Basic && luajit tools/test/love/t_drawhash.lua 150 all && luajit tools/test/love/t_examples.lua"
|
||||||
echo "expected (Luau, tools/test/scripts/t_drawhash.luau): 855922436 / 1889516030"
|
echo "expected (Luau, tools/test/scripts/t_drawhash.luau): 2057580240 / 2004376225"
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
-- Screenshot of a fixed scene (t_libhash's widgets + primitives, optionally the Custom Rendering example):
|
||||||
|
-- composites the ScreenGui like t_composite and prints "ROW y hex". tools/test/shot.py turns it into a PNG.
|
||||||
|
-- RUN_FLAGS: ARG_APP=true also opens ShowExampleAppCustomRendering (needs the demo).
|
||||||
|
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||||
|
local ImGui, ImVec2, ImVec4 = G.ImGui, G.ImVec2, G.ImVec4
|
||||||
|
ImGui.CreateContext(); G.ImGui_ImplRoblox.Init(); G.ImGui_ImplRoblox.SetRenderRate(0)
|
||||||
|
local io = ImGui.GetIO()
|
||||||
|
local W, H = 1280, 760
|
||||||
|
local frame = 0
|
||||||
|
local st = { b = false, f = 0.25, i = 42, c = ImVec4(0.2, 0.7, 0.4, 1.0), buf = ImGui.NewTextBuffer("hello", 64), r = 0, tab = 0, combo = 1, list = 2 }
|
||||||
|
local plot = {}
|
||||||
|
for i = 1, 40 do plot[i] = math.sin(i * 0.3) end
|
||||||
|
local poly = { ImVec2(0, 0), ImVec2(60, 10), ImVec2(30, 30), ImVec2(70, 60), ImVec2(0, 50) }
|
||||||
|
|
||||||
|
local function composite(gui)
|
||||||
|
local screen = buffer.create(W * H * 3)
|
||||||
|
local function walk(inst, ox, oy, kx0, ky0, kx1, ky1)
|
||||||
|
local kids = inst:GetChildren()
|
||||||
|
table.sort(kids, function(a, b) return (a.ZIndex or 1) < (b.ZIndex or 1) end) -- table.sort isn't stable, but siblings with equal ZIndex never overlap here
|
||||||
|
for _, c in ipairs(kids) do
|
||||||
|
if c.Visible ~= false then
|
||||||
|
local x, y = ox + (c.Position and c.Position.X or 0), oy + (c.Position and c.Position.Y or 0)
|
||||||
|
local cx0, cy0, cx1, cy1 = kx0, ky0, kx1, ky1
|
||||||
|
if c.ClipsDescendants then
|
||||||
|
cx0, cy0 = math.max(cx0, x), math.max(cy0, y)
|
||||||
|
cx1, cy1 = math.min(cx1, x + c.Size.X), math.min(cy1, y + c.Size.Y)
|
||||||
|
end
|
||||||
|
if c.ClassName == "ImageLabel" then
|
||||||
|
local img = c.ImageContent.Object
|
||||||
|
local px, sz = img.Pixels, img.Size.X
|
||||||
|
for ty = 0, sz - 1 do
|
||||||
|
local sy = y + ty
|
||||||
|
if sy >= ky0 and sy < ky1 then
|
||||||
|
for tx = 0, sz - 1 do
|
||||||
|
local sx = x + tx
|
||||||
|
if sx >= kx0 and sx < kx1 then
|
||||||
|
local o = (ty * sz + tx) * 4
|
||||||
|
local a = buffer.readu8(px, o + 3)
|
||||||
|
if a > 0 then
|
||||||
|
local d = (sy * W + sx) * 3
|
||||||
|
local fa = a / 255
|
||||||
|
for ch = 0, 2 do
|
||||||
|
local v = buffer.readu8(px, o + ch) * fa + buffer.readu8(screen, d + ch) * (1 - fa)
|
||||||
|
buffer.writeu8(screen, d + ch, math.floor(v + 0.5))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
walk(c, x, y, cx0, cy0, cx1, cy1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
walk(gui, 0, 0, 0, 0, W, H)
|
||||||
|
return screen
|
||||||
|
end
|
||||||
|
|
||||||
|
game:GetService("RunService").Stepped:Connect(function()
|
||||||
|
frame += 1
|
||||||
|
G.ImGui_ImplRoblox.NewFrame()
|
||||||
|
io.DeltaTime = 1 / 60
|
||||||
|
ImGui.NewFrame()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(10, 10), G.ImGuiCond.Always); ImGui.SetNextWindowSize(ImVec2(320, 560), G.ImGuiCond.Always)
|
||||||
|
ImGui.Begin("Widgets")
|
||||||
|
ImGui.Text("Text %d", 123); ImGui.TextColored(ImVec4(1, 0.5, 0, 1), "Colored"); ImGui.TextWrapped("Wrapped text that is long enough to wrap around the window edge at least once.")
|
||||||
|
ImGui.Button("Button"); ImGui.SameLine(); ImGui.SmallButton("Small"); ImGui.SameLine(); ImGui.ArrowButton("##a", G.ImGuiDir.Left)
|
||||||
|
st.b = ImGui.Checkbox("Checkbox", st.b)
|
||||||
|
st.r = ImGui.RadioButton("R0", st.r, 0); ImGui.SameLine(); st.r = ImGui.RadioButton("R1", st.r, 1)
|
||||||
|
st.f = ImGui.SliderFloat("Slider", st.f, 0, 1); st.i = ImGui.DragInt("Drag", st.i, 1, 0, 100)
|
||||||
|
ImGui.InputText("Input", st.buf, 64)
|
||||||
|
ImGui.ColorEdit4("Color", st.c)
|
||||||
|
st.combo = ImGui.Combo("Combo", st.combo, { "AAA", "BBB", "CCC" })
|
||||||
|
st.list = ImGui.ListBox("List", st.list, { "one", "two", "three", "four" }, 4, 3)
|
||||||
|
ImGui.ProgressBar(0.4, ImVec2(-1, 0)); ImGui.ProgressBar(-1.0 * frame / 60, ImVec2(-1, 0), "busy")
|
||||||
|
ImGui.PlotLines("Lines", plot, nil, #plot); ImGui.PlotHistogram("Hist", plot, nil, #plot, 0, nil, -1, 1, ImVec2(0, 40))
|
||||||
|
ImGui.Bullet(); ImGui.Text("bullet"); ImGui.Separator(); ImGui.SeparatorText("Sep")
|
||||||
|
if ImGui.TreeNode("Tree") then ImGui.Text("inside"); ImGui.TreePop() end
|
||||||
|
ImGui.SetNextItemOpen(true, G.ImGuiCond.Once)
|
||||||
|
if ImGui.CollapsingHeader("Header") then
|
||||||
|
if ImGui.BeginTabBar("tabs") then
|
||||||
|
if ImGui.BeginTabItem("Tab A") then ImGui.Text("A"); ImGui.EndTabItem() end
|
||||||
|
if ImGui.BeginTabItem("Tab B") then ImGui.Text("B"); ImGui.EndTabItem() end
|
||||||
|
ImGui.EndTabBar()
|
||||||
|
end
|
||||||
|
if ImGui.BeginTable("t", 3, bit32.bor(G.ImGuiTableFlags.Borders, G.ImGuiTableFlags.RowBg, G.ImGuiTableFlags.Resizable)) then
|
||||||
|
ImGui.TableSetupColumn("One"); ImGui.TableSetupColumn("Two"); ImGui.TableSetupColumn("Three"); ImGui.TableHeadersRow()
|
||||||
|
for row = 0, 4 do ImGui.TableNextRow(); for col = 0, 2 do ImGui.TableSetColumnIndex(col); ImGui.Text("r%d c%d", row, col) end end
|
||||||
|
ImGui.EndTable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ImGui.End()
|
||||||
|
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(340, 10), G.ImGuiCond.Always); ImGui.SetNextWindowSize(ImVec2(300, 560), G.ImGuiCond.Always)
|
||||||
|
ImGui.Begin("Draw")
|
||||||
|
local dl, p = ImGui.GetWindowDrawList(), ImGui.GetCursorScreenPos()
|
||||||
|
local x, y, col = p.x + 4, p.y + 4, 0xFF40C0FF
|
||||||
|
for i, th in { 1.0, 2.5, 6.0 } do
|
||||||
|
local yy = y + (i - 1) * 70
|
||||||
|
dl:AddRect(ImVec2(x, yy), ImVec2(x + 50, yy + 50), col, 10.0, th)
|
||||||
|
dl:AddRectFilled(ImVec2(x + 60, yy), ImVec2(x + 110, yy + 50), col, 10.0, G.ImDrawFlags.RoundTopLeft or G.ImDrawFlags.RoundCornersTopLeft) -- RoundCornersTopLeft: pre-1.93 revs (hashes.sh)
|
||||||
|
dl:AddCircle(ImVec2(x + 145, yy + 25), 25, col, 0, th)
|
||||||
|
dl:AddNgon(ImVec2(x + 200, yy + 25), 25, col, 6, th)
|
||||||
|
dl:AddTriangle(ImVec2(x + 230, yy + 50), ImVec2(x + 255, yy), ImVec2(x + 280, yy + 50), col, th)
|
||||||
|
dl:AddLine(ImVec2(x, yy + 60), ImVec2(x + 280, yy + 55), col, th)
|
||||||
|
end
|
||||||
|
y += 210
|
||||||
|
dl:AddBezierCubic(ImVec2(x, y), ImVec2(x + 60, y - 30), ImVec2(x + 120, y + 60), ImVec2(x + 180, y), col, 3.0)
|
||||||
|
dl:AddBezierQuadratic(ImVec2(x, y + 30), ImVec2(x + 90, y - 10), ImVec2(x + 180, y + 30), col, 2.0)
|
||||||
|
dl:AddEllipse(ImVec2(x + 230, y + 15), ImVec2(40, 15), col, 0.5, 0, 2.0)
|
||||||
|
y += 50
|
||||||
|
local pts = {}
|
||||||
|
for i, v in poly do pts[i] = ImVec2(x + v.x, y + v.y) end
|
||||||
|
dl:AddConcavePolyFilled(pts, #pts, 0xFF8080FF)
|
||||||
|
for i, v in poly do pts[i] = ImVec2(x + 100 + v.x, y + v.y) end
|
||||||
|
dl:AddPolyline(pts, #pts, col, 4.0, G.ImDrawFlags.Closed)
|
||||||
|
for i, v in poly do pts[i] = ImVec2(x + 200 + v.x, y + v.y) end
|
||||||
|
dl:AddPolyline(pts, #pts, col, 1.0, 0)
|
||||||
|
y += 80
|
||||||
|
dl:AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + 100, y + 40), 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF)
|
||||||
|
dl:AddCircleFilled(ImVec2(x + 140, y + 20), 20, col)
|
||||||
|
dl:AddEllipseFilled(ImVec2(x + 210, y + 20), ImVec2(30, 15), col, 0.3)
|
||||||
|
dl:AddText(ImVec2(x, y + 50), 0xFFFFFFFF, "AddText")
|
||||||
|
ImGui.End()
|
||||||
|
|
||||||
|
if ARG_APP then ImGui.SetNextWindowPos(ImVec2(650, 10), G.ImGuiCond.Always); ImGui.SetNextWindowSize(ImVec2(620, 740), G.ImGuiCond.Always); G.ShowExampleAppCustomRendering(true) end
|
||||||
|
ImGui.Render()
|
||||||
|
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||||
|
if frame == ARG_FRAMES - 1 then
|
||||||
|
local screen = composite(game:GetService("Players").LocalPlayer.PlayerGui:FindFirstChild("ImGui"))
|
||||||
|
for y = 0, H - 1 do
|
||||||
|
local t = table.create(W * 3)
|
||||||
|
for i = 0, W * 3 - 1 do t[i + 1] = string.format("%02x", buffer.readu8(screen, y * W * 3 + i)) end
|
||||||
|
print("ROW", y, table.concat(t))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Headless screenshot: tools/test/shot.py out.png [--app] (runs scripts/t_shot.luau, writes a PNG; stdlib only)"""
|
||||||
|
import os, subprocess, sys, struct, zlib
|
||||||
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
env = dict(os.environ, FULL_OUTPUT="1", RUN_FLAGS="ARG_APP=true" if "--app" in sys.argv else "")
|
||||||
|
out = subprocess.run([sys.executable, os.path.join(HERE, "run.py"), "--quiet", "--roblox", "--frames", "30", "--timeout", "600",
|
||||||
|
"--main", os.path.join(HERE, "scripts", "t_shot.luau")], env=env, capture_output=True, text=True).stdout
|
||||||
|
rows = {int(l.split()[1]): bytes.fromhex(l.split()[2]) for l in out.splitlines() if l.startswith("ROW")}
|
||||||
|
assert rows, out[-2000:]
|
||||||
|
w, h = len(rows[0]) // 3, len(rows)
|
||||||
|
raw = b"".join(b"\0" + rows[y] for y in range(h))
|
||||||
|
chunk = lambda t, d: struct.pack(">I", len(d)) + t + d + struct.pack(">I", zlib.crc32(t + d) & 0xffffffff)
|
||||||
|
open(sys.argv[1], "wb").write(b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0)) + chunk(b"IDAT", zlib.compress(raw, 6)) + chunk(b"IEND", b""))
|
||||||
|
print("wrote", sys.argv[1], w, h)
|
||||||
Reference in New Issue
Block a user