LÖVE backend + build target (compat/luajit.lua shims, Roblox build unchanged), examples/example_love, examples/example_shared (same app on Roblox and LÖVE), LuaJIT checksum tests
This commit is contained in:
+20
-7
@@ -1,6 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
# Bundles the root *.lua (library + imgui_demo.lua), backends/ and fonts/ into ONE ModuleScript: build/ImGui.luau
|
||||
# --no-demo: library only (imgui_demo.lua left out, like not compiling imgui_demo.cpp)
|
||||
# --target love: build/imgui_love.lua for LÖVE/LuaJIT instead (LÖVE backend, compat/luajit.lua shims, @native stripped).
|
||||
# The default (roblox) build is unaffected by it.
|
||||
# Why: ModuleScripts don't share globals, and the setfenv() alternative turns off Luau's fast paths / native codegen.
|
||||
# Each source file becomes a function in __FILES; IM_INCLUDE(name) runs it once and caches the result.
|
||||
# The module returns a table with every global the library defines (ImGui, ImVec2, ImGuiConfigFlags, ImGui_ImplRoblox, ...).
|
||||
@@ -9,21 +11,31 @@ import os, re
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
import sys
|
||||
NO_DEMO = "--no-demo" in sys.argv
|
||||
LOVE = False
|
||||
if "--target" in sys.argv:
|
||||
i = sys.argv.index("--target"); LOVE = sys.argv[i + 1] == "love"; del sys.argv[i:i + 2]
|
||||
sys.argv = [a for a in sys.argv if a != "--no-demo"]
|
||||
BACKEND = "imgui_impl_love.lua" if LOVE else "imgui_impl_roblox.lua"
|
||||
SKIP = {"imgui_impl_roblox.lua", "imgui_impl_roblox_fonts.lua"} if LOVE else {"imgui_impl_love.lua"}
|
||||
FILES = {}
|
||||
for d in (ROOT, os.path.join(ROOT, "backends"), os.path.join(ROOT, "fonts")):
|
||||
for f in sorted(os.listdir(d)):
|
||||
if f.endswith(".lua") and not (NO_DEMO and f == "imgui_demo.lua"):
|
||||
FILES[f] = open(os.path.join(d, f)).read()
|
||||
if f.endswith(".lua") and not (NO_DEMO and f == "imgui_demo.lua") and f not in SKIP:
|
||||
src = open(os.path.join(d, f)).read()
|
||||
if LOVE: src = re.sub(r"^@native$", "", src, flags=re.M) # keep line numbers
|
||||
FILES[f] = src
|
||||
|
||||
ENTRY = ["imgui.lua", "imgui_impl_roblox.lua"] + ([] if NO_DEMO else ["imgui_demo.lua"]) # run order
|
||||
ENTRY = ["imgui.lua", BACKEND] + ([] if NO_DEMO else ["imgui_demo.lua"]) # run order
|
||||
|
||||
names = set()
|
||||
for src in FILES.values():
|
||||
names.update(re.findall(r"^function ([A-Za-z_]\w*)\s*\(", src, re.M))
|
||||
names.update(re.findall(r"^([A-Za-z_]\w*)\s*=[^=]", src, re.M))
|
||||
|
||||
out = ["--!optimize 2", "-- GENERATED by tools/bundle.py from *.lua, backends/, fonts/ - do not edit", "",
|
||||
out = ["--!optimize 2", "-- GENERATED by tools/bundle.py from *.lua, backends/, fonts/ - do not edit", ""]
|
||||
if LOVE:
|
||||
out = ["-- GENERATED by tools/bundle.py --target love - do not edit", open(os.path.join(ROOT, "compat", "luajit.lua")).read(), ""]
|
||||
out += [
|
||||
"local __FILES, __LOADED = {}, {}",
|
||||
"function IM_INCLUDE(name)",
|
||||
" local r = __LOADED[name]",
|
||||
@@ -48,7 +60,8 @@ out.append("}")
|
||||
import sys
|
||||
OUT = sys.argv[1] if len(sys.argv) > 1 else os.path.join(ROOT, "build")
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
open(os.path.join(OUT, "ImGui.luau"), "w").write("\n".join(out) + "\n")
|
||||
NAME = "imgui_love.lua" if LOVE else "ImGui.luau"
|
||||
open(os.path.join(OUT, NAME), "w").write("\n".join(out) + "\n")
|
||||
import json
|
||||
json.dump(linemap, open(os.path.join(OUT, "ImGui.linemap.json"), "w"))
|
||||
print("wrote build/ImGui.luau (%d files, %d exports)" % (len(FILES), len(names)))
|
||||
json.dump(linemap, open(os.path.join(OUT, NAME.rsplit(".", 1)[0] + ".linemap.json"), "w"))
|
||||
print("wrote build/%s (%d files, %d exports)" % (NAME, len(FILES), len(names)))
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
-- Minimal headless `love` for running build/imgui_love.lua under plain LuaJIT (tools/test/love/run.sh).
|
||||
local ffi = require("ffi")
|
||||
local W, H = 1920, 1080
|
||||
local t = 0
|
||||
local function obj(extra) local o = { release = function() end }; for k, v in pairs(extra or {}) do o[k] = v end; return o end
|
||||
local function bytedata(n)
|
||||
local mem = ffi.new("uint8_t[?]", n)
|
||||
return obj({ getFFIPointer = function() return mem end, getSize = function() return n end })
|
||||
end
|
||||
love = {
|
||||
timer = { getTime = function() return t end, step = function(dt) t = t + dt end },
|
||||
graphics = {
|
||||
getDimensions = function() return W, H end,
|
||||
newImage = function() return obj({ setFilter = function() end, replacePixels = function() end }) end,
|
||||
newMesh = function() return obj({ setVertices = function() end, setVertexMap = function() end, setTexture = function() end, setDrawRange = function() end }) end,
|
||||
push = function() end, pop = function() end, setBlendMode = function() end, setColor = function() end,
|
||||
translate = function() end, setScissor = function() end, draw = function() MOCK_DRAWS = (MOCK_DRAWS or 0) + 1 end,
|
||||
},
|
||||
image = { newImageData = function(w, h) return bytedata(w * h * 4) end },
|
||||
data = { newByteData = function(n) return bytedata(n) end },
|
||||
keyboard = { isDown = function() return false end, setTextInput = function() end, setKeyRepeat = function() end },
|
||||
mouse = { setCursor = function() end, getSystemCursor = function() return {} end, setVisible = function() end },
|
||||
system = { getClipboardText = function() return "" end, setClipboardText = function() end, openURL = function() end },
|
||||
filesystem = { getInfo = function() return nil end, read = function() return nil end },
|
||||
}
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
# LÖVE/LuaJIT checks: build the love bundle, compare draw checksums with the Luau ones, run both LÖVE examples headless.
|
||||
set -e
|
||||
cd "$(dirname "$0")/../../.."
|
||||
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"
|
||||
echo "expected (Luau, tools/test/scripts/t_drawhash.luau): 1385106188 / 1292122782"
|
||||
@@ -0,0 +1,41 @@
|
||||
-- LuaJIT twin of tools/test/scripts/t_drawhash.luau: same input, same checksum => compat shims behave like Luau.
|
||||
-- usage: luajit tools/test/love/t_drawhash.lua <frames> [Widgets,Basic | all]
|
||||
dofile("tools/test/love/mock_love.lua")
|
||||
local G = dofile("build/imgui_love.lua")
|
||||
local ImGui = G.ImGui
|
||||
local FRAMES, OPEN = tonumber(arg[1] or 150), arg[2] or ""
|
||||
local open = {}
|
||||
for n in OPEN:gmatch("[^,]+") do open[n] = true end
|
||||
for _, fname in ipairs({ "TreeNode", "CollapsingHeader" }) do
|
||||
local real = ImGui[fname]
|
||||
ImGui[fname] = function(label, ...)
|
||||
if open[label] or OPEN == "all" then ImGui.SetNextItemOpen(true, G.ImGuiCond.Always) end
|
||||
return real(label, ...)
|
||||
end
|
||||
end
|
||||
ImGui.CreateContext()
|
||||
G.ImGui_ImplLove.Init({ root = "./" })
|
||||
local io = ImGui.GetIO()
|
||||
local h = 0
|
||||
local function mix(v) h = (h * 31 + math.floor(v * 64 + 0.5)) % 2147483647 end
|
||||
for frame = 1, FRAMES do
|
||||
love.timer.step(1 / 60)
|
||||
G.ImGui_ImplLove.NewFrame()
|
||||
io.DeltaTime = 1 / 60
|
||||
if frame == 1 then io:AddMousePosEvent(0, 0) end -- (the Roblox backend reports the initial mouse position)
|
||||
io:AddMousePosEvent(100 + (frame * 37) % 500, 60 + (frame * 53) % 600)
|
||||
if frame % 7 == 0 then io:AddMouseButtonEvent(0, frame % 14 == 0) end
|
||||
if frame % 11 == 0 then io:AddMouseWheelEvent(0, -1) end
|
||||
ImGui.NewFrame()
|
||||
ImGui.ShowDemoWindow(true)
|
||||
ImGui.Render()
|
||||
for _, dl in ImGui.GetDrawData().CmdLists:iter() do
|
||||
local vb, id = dl.VtxBuffer.Buf, dl.IdxBuffer.Data
|
||||
for i = 1, dl.VtxBuffer.Size do local o = (i - 1) * 36; mix(buffer.readf64(vb, o)); mix(buffer.readf64(vb, o + 8)); mix(buffer.readf64(vb, o + 16) * 4096); mix(buffer.readf64(vb, o + 24) * 4096); mix(buffer.readu32(vb, o + 32) / 64) end
|
||||
for i = 1, dl.IdxBuffer.Size do mix(id[i]) end
|
||||
for _, c in dl.CmdBuffer:iter() do mix(c.ClipRect.x); mix(c.ClipRect.y); mix(c.ClipRect.z); mix(c.ClipRect.w); mix(c.ElemCount) end
|
||||
end
|
||||
G.ImGui_ImplLove.RenderDrawData(ImGui.GetDrawData())
|
||||
if frame == FRAMES - 1 then print("DRAWHASH", string.format("%d", h)) end
|
||||
end
|
||||
print("draws", MOCK_DRAWS)
|
||||
@@ -0,0 +1,15 @@
|
||||
-- Runs examples/example_love and examples/example_shared main.lua headless under LuaJIT (mock love) for some frames.
|
||||
for _, ex in ipairs({ "examples/example_love", "examples/example_shared" }) do
|
||||
dofile("tools/test/love/mock_love.lua")
|
||||
love.filesystem.getSource = function() return ex end
|
||||
love.filesystem.load = function(p) return assert(loadfile(ex .. "/" .. p)) end
|
||||
love.graphics.clear = function() end
|
||||
dofile(ex .. "/main.lua")
|
||||
love.load()
|
||||
for i = 1, 30 do
|
||||
love.timer.step(1 / 60)
|
||||
love.mousemoved(100 + i, 100); love.update(1 / 60); love.draw()
|
||||
end
|
||||
love.keypressed("a"); love.textinput("a"); love.keyreleased("a"); love.update(1 / 60); love.draw()
|
||||
print(ex, "OK", MOCK_DRAWS)
|
||||
end
|
||||
Reference in New Issue
Block a user