add a script to transpile imgui header from cpp to lua
This commit is contained in:
parent
ff2b85184e
commit
99f3e039dc
23
cmake/imgui4lua.cmake
Normal file
23
cmake/imgui4lua.cmake
Normal file
@ -0,0 +1,23 @@
|
||||
function(_imgui4lua_main)
|
||||
set(dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||
set(py "${PROJECT_SOURCE_DIR}/cmake/imgui4lua.py")
|
||||
set(src "${imgui_SOURCE_DIR}/imgui.h")
|
||||
set(dst "${dir}/imgui4lua.inc")
|
||||
|
||||
find_program(SH sh REQUIRED)
|
||||
find_program(PYTHON3 python3 REQUIRED)
|
||||
find_program(CLANGXX clang++ REQUIRED)
|
||||
|
||||
make_directory("${dir}")
|
||||
add_custom_command(
|
||||
COMMAND ${SH} -c "${PYTHON3} '${py}' '${src}' > '${dst}'"
|
||||
OUTPUT "${dst}"
|
||||
DEPENDS "${src}" "${py}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_library(imgui4lua INTERFACE)
|
||||
target_sources(imgui4lua PUBLIC "${dst}")
|
||||
target_include_directories(imgui4lua INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endfunction()
|
||||
_imgui4lua_main()
|
133
cmake/imgui4lua.py
Executable file
133
cmake/imgui4lua.py
Executable file
@ -0,0 +1,133 @@
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# ---- GENERATOR DEFINITIONS
|
||||
def gen_func(item):
|
||||
name = item["name"]
|
||||
if name not in kFuncWhitelist:
|
||||
return
|
||||
|
||||
pops = []
|
||||
params = []
|
||||
pcount = 0
|
||||
for arg in item.get("inner", []):
|
||||
pop, param, push = gen_argument(pcount, arg)
|
||||
pcount += 1
|
||||
pops .extend(pop)
|
||||
params.extend(param)
|
||||
push .extend(push)
|
||||
|
||||
pushes = gen_return(item)
|
||||
use_ret = 0 < len(pushes)
|
||||
|
||||
# text output
|
||||
nl = "\n "
|
||||
cm = ", "
|
||||
if 0 < len(pops) or 0 < len(pushes):
|
||||
print("lua_pushcfunction(L, [](auto L) {")
|
||||
else:
|
||||
print("lua_pushcfunction(L, [](auto) {")
|
||||
if 0 < len(pops):
|
||||
print(f" {nl.join(pops)}")
|
||||
if use_ret:
|
||||
print(f" const auto r = ImGui::{name}({cm.join(params)});")
|
||||
else:
|
||||
print(f" ImGui::{name}({cm.join(params)});")
|
||||
if 0 < len(pushes):
|
||||
print(f" {nl.join(pushes)}")
|
||||
print(f" return {len(pushes)};")
|
||||
print("});")
|
||||
print(f"lua_setfield(L, -2, \"{name}\");")
|
||||
print()
|
||||
|
||||
def gen_return(item):
|
||||
ftype = item["type"]["qualType"]
|
||||
type = ftype[0:ftype.find("(")-1]
|
||||
|
||||
if "void" == type:
|
||||
return []
|
||||
if "bool" == type:
|
||||
return ["lua_pushboolean(L, r);"]
|
||||
if "float" == type:
|
||||
return ["lua_pushnumber(L, static_cast<lua_Number>(r));"]
|
||||
if "ImVec2" == type:
|
||||
return [
|
||||
"lua_pushnumber(L, static_cast<lua_Number>(r.x));",
|
||||
"lua_pushnumber(L, static_cast<lua_Number>(r.y));",
|
||||
]
|
||||
|
||||
print(f"unknown return type: {type}", file=sys.stderr)
|
||||
return []
|
||||
|
||||
def gen_argument(pc, item):
|
||||
type = item["type"].get("desugaredQualType", item["type"]["qualType"])
|
||||
n = pc+1
|
||||
pn = f"p{pc}"
|
||||
|
||||
if type in ["int", "unsigned int"]:
|
||||
return ([f"const int {pn} = static_cast<{type}>(luaL_checkinteger(L, {n}));"], [pn], [])
|
||||
|
||||
if "bool" == type:
|
||||
return ([f"const bool {pn} = lua_toboolean(L, {n});"], [pn], [])
|
||||
|
||||
if "const char *" == type:
|
||||
return ([f"const char* {pn} = luaL_checkstring(L, {n});"], [pn], [])
|
||||
|
||||
if "const ImVec2 &" == type:
|
||||
return ([
|
||||
f"const float {pn}_1 = static_cast<float>(luaL_checknumber(L, {n}));",
|
||||
f"const float {pn}_2 = static_cast<float>(luaL_checknumber(L, {n}));",
|
||||
], [f"ImVec2 {{{pn}_1, {pn}_2}}"], [])
|
||||
|
||||
if "bool *" == type:
|
||||
return ([f"bool {pn};"], [f"&{pn}"], [f"lua_pushboolean(L, {pn});"])
|
||||
|
||||
print(f"unknown argument type: {type}", file=sys.stderr)
|
||||
return ([], [], [])
|
||||
|
||||
|
||||
# ---- WALKER DEFINITIONS
|
||||
def walk_symbols(item):
|
||||
kind = item.get("kind")
|
||||
|
||||
if kind == "FunctionDecl":
|
||||
gen_func(item)
|
||||
else:
|
||||
walk(item)
|
||||
|
||||
def walk(item):
|
||||
kind = item.get("kind")
|
||||
|
||||
w = walk
|
||||
if kind == "NamespaceDecl":
|
||||
w = walk_symbols
|
||||
|
||||
for child in item.get("inner", []):
|
||||
w(child)
|
||||
|
||||
|
||||
# ---- DATA DEFINITIONS
|
||||
kFuncWhitelist = [
|
||||
"Begin",
|
||||
"End",
|
||||
"BeginChild",
|
||||
"EndChild",
|
||||
"IsWindowAppearing",
|
||||
"IsWindowCollapsed",
|
||||
"IsWindowFocused",
|
||||
"IsWindowHovered",
|
||||
"GetWindowPos",
|
||||
"GetWindowSize",
|
||||
"GetWindowWidth",
|
||||
"GetWindowHeight",
|
||||
]
|
||||
|
||||
|
||||
# ---- ENTRYPOINT
|
||||
proc = subprocess.run(["clang++", "-x", "c++", "-std=c++2b", "-Xclang", "-ast-dump=json", "-fsyntax-only", sys.argv[1]], capture_output=True)
|
||||
if 0 == proc.returncode:
|
||||
walk(json.loads(proc.stdout))
|
||||
else:
|
||||
print(proc.stderr.decode("utf-8"))
|
||||
exit(1)
|
@ -3,6 +3,7 @@ target_link_libraries(nf7_core
|
||||
PUBLIC
|
||||
git_hash
|
||||
imgui
|
||||
imgui4lua
|
||||
luajit
|
||||
nf7_config
|
||||
nf7_iface
|
||||
|
1
thirdparty/CMakeLists.txt
vendored
1
thirdparty/CMakeLists.txt
vendored
@ -19,6 +19,7 @@ FetchContent_Declare(
|
||||
)
|
||||
FetchContent_Populate(imgui)
|
||||
include(imgui.cmake)
|
||||
include(../cmake/imgui4lua.cmake)
|
||||
|
||||
# ---- luajit (MIT)
|
||||
FetchContent_Declare(
|
||||
|
Loading…
x
Reference in New Issue
Block a user