Add cimgui
This commit is contained in:
466
engine/libs/cimgui/generator/generator.lua
Normal file
466
engine/libs/cimgui/generator/generator.lua
Normal file
@@ -0,0 +1,466 @@
|
||||
--------------------------------------------------------------------------
|
||||
--script for auto_funcs.h and auto_funcs.cpp generation
|
||||
--expects LuaJIT
|
||||
--------------------------------------------------------------------------
|
||||
assert(_VERSION=='Lua 5.1',"Must use LuaJIT")
|
||||
assert(bit,"Must use LuaJIT")
|
||||
local script_args = {...}
|
||||
local COMPILER = script_args[1]
|
||||
local INTERNAL_GENERATION = script_args[2]:match("internal") and true or false
|
||||
local FREETYPE_GENERATION = script_args[2]:match("freetype") and true or false
|
||||
local COMMENTS_GENERATION = script_args[2]:match("comments") and true or false
|
||||
local NOCHAR = script_args[2]:match("nochar") and true or false
|
||||
local NOIMSTRV = script_args[2]:match("noimstrv") and true or false
|
||||
local IMGUI_PATH = os.getenv"IMGUI_PATH" or "../imgui"
|
||||
local CFLAGS = ""
|
||||
local CPRE,CTEST
|
||||
--get implementations
|
||||
local implementations = {}
|
||||
for i=3,#script_args do
|
||||
if script_args[i]:match(COMPILER == "cl" and "^/" or "^%-") then
|
||||
local key, value = script_args[i]:match("^(.+)=(.+)$")
|
||||
if key and value then
|
||||
CFLAGS = CFLAGS .. " " .. key .. "=\"" .. value:gsub("\"", "\\\"") .. "\"";
|
||||
else
|
||||
CFLAGS = CFLAGS .. " " .. script_args[i]
|
||||
end
|
||||
else
|
||||
table.insert(implementations,script_args[i])
|
||||
end
|
||||
end
|
||||
|
||||
if FREETYPE_GENERATION then
|
||||
CFLAGS = CFLAGS .. " -DIMGUI_ENABLE_FREETYPE "
|
||||
end
|
||||
|
||||
if COMPILER == "gcc" or COMPILER == "clang" then
|
||||
CPRE = COMPILER..[[ -E -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_API="" -DIMGUI_IMPL_API="" ]] .. CFLAGS
|
||||
CTEST = COMPILER.." --version"
|
||||
elseif COMPILER == "cl" then
|
||||
CPRE = COMPILER..[[ /E /DIMGUI_DISABLE_OBSOLETE_FUNCTIONS /DIMGUI_DEBUG_PARANOID /DIMGUI_API="" /DIMGUI_IMPL_API="" ]] .. CFLAGS
|
||||
CTEST = COMPILER
|
||||
else
|
||||
print("Working without compiler ")
|
||||
error("cant work with "..COMPILER.." compiler")
|
||||
end
|
||||
--test compiler present
|
||||
local HAVE_COMPILER = false
|
||||
|
||||
local pipe,err = io.popen(CTEST,"r")
|
||||
if pipe then
|
||||
local str = pipe:read"*a"
|
||||
print(str)
|
||||
pipe:close()
|
||||
if str=="" then
|
||||
HAVE_COMPILER = false
|
||||
else
|
||||
HAVE_COMPILER = true
|
||||
end
|
||||
else
|
||||
HAVE_COMPILER = false
|
||||
print(err)
|
||||
end
|
||||
assert(HAVE_COMPILER,"gcc, clang or cl needed to run script")
|
||||
|
||||
|
||||
print("HAVE_COMPILER",HAVE_COMPILER)
|
||||
print("INTERNAL_GENERATION",INTERNAL_GENERATION)
|
||||
print("FREETYPE_GENERATION",FREETYPE_GENERATION)
|
||||
print("COMMENTS_GENERATION",COMMENTS_GENERATION)
|
||||
print("CPRE",CPRE)
|
||||
--------------------------------------------------------------------------
|
||||
--this table has the functions to be skipped in generation
|
||||
--------------------------------------------------------------------------
|
||||
local cimgui_manuals = {
|
||||
igLogText = true,
|
||||
ImGuiTextBuffer_appendf = true,
|
||||
--igColorConvertRGBtoHSV = true,
|
||||
--igColorConvertHSVtoRGB = true
|
||||
}
|
||||
local cimgui_skipped = {
|
||||
--igShowDemoWindow = true
|
||||
}
|
||||
--------------------------------------------------------------------------
|
||||
--this table is a dictionary to force a naming of function overloading (instead of algorythmic generated)
|
||||
--first level is cimguiname without postfix, second level is the signature of the function, value is the
|
||||
--desired name
|
||||
---------------------------------------------------------------------------
|
||||
local cimgui_overloads = {
|
||||
--igPushID = {
|
||||
--["(const char*)"] = "igPushIDStr",
|
||||
--["(const char*,const char*)"] = "igPushIDRange",
|
||||
--["(const void*)"] = "igPushIDPtr",
|
||||
--["(int)"] = "igPushIDInt"
|
||||
--},
|
||||
}
|
||||
|
||||
--------------------------header definitions
|
||||
local cimgui_header =
|
||||
[[//This file is automatically generated by generator.lua from https://github.com/cimgui/cimgui
|
||||
//based on imgui.h file version XXX from Dear ImGui https://github.com/ocornut/imgui
|
||||
]]
|
||||
local gdefines = {} --for FLT_MAX and others
|
||||
--------------------------------------------------------------------------
|
||||
--helper functions
|
||||
--------------------------------functions for C generation
|
||||
--load parser module
|
||||
local cpp2ffi = require"cpp2ffi"
|
||||
local read_data = cpp2ffi.read_data
|
||||
local save_data = cpp2ffi.save_data
|
||||
local copyfile = cpp2ffi.copyfile
|
||||
local serializeTableF = cpp2ffi.serializeTableF
|
||||
|
||||
local function func_header_impl_generate(FP)
|
||||
|
||||
local outtab = {}
|
||||
|
||||
for _,t in ipairs(FP.funcdefs) do
|
||||
if t.cimguiname then
|
||||
local cimf = FP.defsT[t.cimguiname]
|
||||
local def = cimf[t.signature]
|
||||
local addcoment = def.comment or ""
|
||||
if def.constructor then
|
||||
-- it happens with vulkan impl but constructor ImGui_ImplVulkanH_Window is not needed
|
||||
--assert(def.stname ~= "","constructor without struct")
|
||||
--table.insert(outtab,"CIMGUI_API "..def.stname.."* "..def.ov_cimguiname ..(empty and "(void)" or --def.args)..";"..addcoment.."\n")
|
||||
elseif def.destructor then
|
||||
--table.insert(outtab,"CIMGUI_API void "..def.ov_cimguiname..def.args..";"..addcoment.."\n")
|
||||
else
|
||||
|
||||
if def.stname == "" then --ImGui namespace or top level
|
||||
local empty = def.args:match("^%(%)") --no args
|
||||
table.insert(outtab,"CIMGUI_API".." "..def.ret.." "..def.ov_cimguiname..(empty and "(void)" or def.args)..";"..addcoment.."\n")
|
||||
else
|
||||
cpp2ffi.prtable(def)
|
||||
error("class function in implementations")
|
||||
end
|
||||
end
|
||||
else --not cimguiname
|
||||
table.insert(outtab,t.comment:gsub("%%","%%%%").."\n")-- %% substitution for gsub
|
||||
end
|
||||
end
|
||||
local cfuncsstr = table.concat(outtab)
|
||||
cfuncsstr = cfuncsstr:gsub("\n+","\n") --several empty lines to one empty line
|
||||
return cfuncsstr
|
||||
end
|
||||
|
||||
local func_header_generate = cpp2ffi.func_header_generate
|
||||
local func_implementation = cpp2ffi.func_implementation
|
||||
|
||||
-------------------functions for getting and setting defines
|
||||
local function get_defines(t)
|
||||
local compiler_cmd = COMPILER == "cl"
|
||||
and COMPILER..[[ /TP /nologo /c /Fo"NUL" /DIMGUI_DISABLE_OBSOLETE_FUNCTIONS ]]..CFLAGS..[[ /I"]]..IMGUI_PATH..[[" print_defines.cpp]]
|
||||
or COMPILER..[[ -E -dM -DIMGUI_DISABLE_OBSOLETE_FUNCTIONS -DIMGUI_API="" -DIMGUI_IMPL_API="" ]]..IMGUI_PATH..[[/imgui.h]]..CFLAGS
|
||||
print(compiler_cmd)
|
||||
local pipe,err = io.popen(compiler_cmd,"r")
|
||||
local defines = {}
|
||||
local compiler_output = {"There were fails in compilation."}
|
||||
while true do
|
||||
local line = pipe:read"*l"
|
||||
if not line then break end
|
||||
local key,value = line:match([[^#define%s+(%S+)%s*(.*)]])
|
||||
if not key then --or not value then
|
||||
table.insert(compiler_output, line)
|
||||
--print(line)
|
||||
else
|
||||
defines[key]=value or ""
|
||||
end
|
||||
end
|
||||
pipe:close()
|
||||
--require"anima.utils"
|
||||
--prtable(defines)
|
||||
assert(next(defines), table.concat(compiler_output, "\n"))
|
||||
local ret = {}
|
||||
for i,v in ipairs(t) do
|
||||
local aa = defines[v]
|
||||
while true do
|
||||
local tmp = defines[aa]
|
||||
if not tmp then
|
||||
break
|
||||
else
|
||||
aa = tmp
|
||||
end
|
||||
end
|
||||
ret[v] = aa
|
||||
end
|
||||
return ret
|
||||
end
|
||||
--subtitution of FLT_MAX value for FLT_MAX or FLT_MIN
|
||||
local function set_defines(fdefs)
|
||||
local FLT_MINpat = gdefines.FLT_MIN:gsub("([%.%-])","%%%1")
|
||||
for k,defT in pairs(fdefs) do
|
||||
for i,def in ipairs(defT) do
|
||||
for name,default in pairs(def.defaults) do
|
||||
if default == gdefines.FLT_MAX then
|
||||
def.defaults[name] = "FLT_MAX"
|
||||
elseif default:match(FLT_MINpat) then
|
||||
def.defaults[name] = default:gsub(FLT_MINpat,"FLT_MIN")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--this creates defsBystruct in case you need to list by struct container
|
||||
local function DefsByStruct(FP)
|
||||
local structs = {}
|
||||
for fun,defs in pairs(FP.defsT) do
|
||||
local stname = defs[1].stname
|
||||
structs[stname] = structs[stname] or {}
|
||||
table.insert(structs[stname],defs)--fun)
|
||||
end
|
||||
FP.defsBystruct = structs
|
||||
end
|
||||
|
||||
|
||||
--generate cimgui.cpp cimgui.h
|
||||
local function cimgui_generation(parser)
|
||||
|
||||
--[[
|
||||
-- clean ImVector:contains() for not applicable types
|
||||
local clean_f = {}
|
||||
for k,v in pairs(parser.defsT) do
|
||||
if k:match"ImVector" and k:match"contains" then
|
||||
--cpp2ffi.prtable(k,v)
|
||||
local stname = v[1].stname
|
||||
if not(stname:match"float" or stname:match"int" or stname:match"char") then
|
||||
parser.defsT[k] = nil
|
||||
--delete also from funcdefs
|
||||
for i,t in ipairs(parser.funcdefs) do
|
||||
if t.cimguiname == k then
|
||||
table.remove(parser.funcdefs, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--]]
|
||||
--------------------------------------------------
|
||||
local hstrfile = read_data"./cimgui_template.h"
|
||||
|
||||
local outpre,outpost = parser.structs_and_enums[1],parser.structs_and_enums[2]
|
||||
cpp2ffi.prtable(parser.templates)
|
||||
cpp2ffi.prtable(parser.typenames)
|
||||
|
||||
|
||||
local tdt = parser:generate_templates()
|
||||
local cstructsstr = outpre..tdt..outpost
|
||||
|
||||
if gdefines.IMGUI_HAS_DOCK then
|
||||
cstructsstr = cstructsstr.."\n#define IMGUI_HAS_DOCK 1\n"
|
||||
end
|
||||
if gdefines.IMGUI_HAS_IMSTR then
|
||||
if not (NOCHAR or NOIMSTRV) then
|
||||
cstructsstr = cstructsstr.."\n#define IMGUI_HAS_IMSTR 1\n"
|
||||
end
|
||||
end
|
||||
|
||||
hstrfile = hstrfile:gsub([[#include "imgui_structs%.h"]],cstructsstr)
|
||||
local cfuncsstr = func_header_generate(parser)
|
||||
hstrfile = hstrfile:gsub([[#include "auto_funcs%.h"]],cfuncsstr)
|
||||
save_data("./output/cimgui.h",cimgui_header,hstrfile)
|
||||
|
||||
--merge it in cimgui_template.cpp to cimgui.cpp
|
||||
local cimplem = func_implementation(parser)
|
||||
|
||||
local hstrfile = read_data"./cimgui_template.cpp"
|
||||
|
||||
hstrfile = hstrfile:gsub([[#include "auto_funcs%.cpp"]],cimplem)
|
||||
local ftdef = FREETYPE_GENERATION and "#define IMGUI_ENABLE_FREETYPE\n" or ""
|
||||
save_data("./output/cimgui.cpp",cimgui_header, ftdef, hstrfile)
|
||||
|
||||
end
|
||||
--------------------------------------------------------
|
||||
-----------------------------do it----------------------
|
||||
--------------------------------------------------------
|
||||
--get imgui.h version and IMGUI_HAS_DOCK--------------------------
|
||||
--defines for the cl compiler must be present in the print_defines.cpp file
|
||||
gdefines = get_defines{"IMGUI_VERSION","IMGUI_VERSION_NUM","FLT_MAX","FLT_MIN","IMGUI_HAS_DOCK","IMGUI_HAS_IMSTR"}
|
||||
|
||||
if gdefines.IMGUI_HAS_DOCK then gdefines.IMGUI_HAS_DOCK = true end
|
||||
if gdefines.IMGUI_HAS_IMSTR then gdefines.IMGUI_HAS_IMSTR = true end
|
||||
|
||||
cimgui_header = cimgui_header:gsub("XXX",gdefines.IMGUI_VERSION .. " "..(gdefines.IMGUI_VERSION_NUM or ""))
|
||||
if INTERNAL_GENERATION then
|
||||
cimgui_header = cimgui_header..[[//with imgui_internal.h api
|
||||
]]
|
||||
end
|
||||
if FREETYPE_GENERATION then
|
||||
cimgui_header = cimgui_header..[[//with imgui_freetype.h api
|
||||
]]
|
||||
end
|
||||
if gdefines.IMGUI_HAS_DOCK then
|
||||
cimgui_header = cimgui_header..[[//docking branch
|
||||
]]
|
||||
|
||||
end
|
||||
assert(not NOCHAR or not NOIMSTRV,"nochar and noimstrv cant be set at the same time")
|
||||
print("IMGUI_HAS_IMSTR",gdefines.IMGUI_HAS_IMSTR)
|
||||
print("NOCHAR",NOCHAR)
|
||||
print("NOIMSTRV",NOIMSTRV)
|
||||
print("IMGUI_HAS_DOCK",gdefines.IMGUI_HAS_DOCK)
|
||||
print("IMGUI_VERSION",gdefines.IMGUI_VERSION)
|
||||
|
||||
|
||||
--funtion for parsing imgui headers
|
||||
local function parseImGuiHeader(header,names)
|
||||
--prepare parser
|
||||
local parser = cpp2ffi.Parser()
|
||||
|
||||
parser.getCname = function(stname,funcname,namespace)
|
||||
local pre = (stname == "") and (namespace and (namespace=="ImGui" and "ig" or namespace.."_") or "ig") or stname.."_"
|
||||
return pre..funcname
|
||||
end
|
||||
parser.cname_overloads = cimgui_overloads
|
||||
parser.manuals = cimgui_manuals
|
||||
parser.skipped = cimgui_skipped
|
||||
parser.UDTs = {"ImVec2","ImVec4","ImColor","ImRect"}
|
||||
--parser.gen_template_typedef = gen_template_typedef --use auto
|
||||
parser.COMMENTS_GENERATION = COMMENTS_GENERATION
|
||||
parser.NOCHAR = NOCHAR
|
||||
parser.NOIMSTRV = NOIMSTRV
|
||||
local defines = parser:take_lines(CPRE..header,names,COMPILER)
|
||||
|
||||
return parser
|
||||
end
|
||||
--generation
|
||||
print("------------------generation with "..COMPILER.."------------------------")
|
||||
local parser1
|
||||
local headers = [[#include "]]..IMGUI_PATH..[[/imgui.h"
|
||||
]]
|
||||
local headersT = {[[imgui]]}
|
||||
if INTERNAL_GENERATION then
|
||||
headers = headers .. [[#include "]]..IMGUI_PATH..[[/imgui_internal.h"
|
||||
]]
|
||||
headersT[#headersT + 1] = [[imgui_internal]]
|
||||
headersT[#headersT + 1] = [[imstb_textedit]]
|
||||
end
|
||||
if FREETYPE_GENERATION then
|
||||
headers = headers .. [[
|
||||
#include "]]..IMGUI_PATH..[[/misc/freetype/imgui_freetype.h"
|
||||
]]
|
||||
headersT[#headersT + 1] = [[imgui_freetype]]
|
||||
end
|
||||
save_data("headers.h",headers)
|
||||
local include_cmd = COMPILER=="cl" and [[ /I ]] or [[ -I ]]
|
||||
local extra_includes = include_cmd.." " ..IMGUI_PATH.." "
|
||||
local parser1 = parseImGuiHeader(extra_includes .. [[headers.h]],headersT)
|
||||
os.remove("headers.h")
|
||||
parser1:do_parse()
|
||||
|
||||
--to debug items parsing
|
||||
--save_data("./itemsarr2.txt",cpp2ffi.ToStr(parser1.itemsarr))
|
||||
save_data("./output/overloads.txt",parser1.overloadstxt)
|
||||
cimgui_generation(parser1)
|
||||
|
||||
----------save struct and enums lua table in structs_and_enums.lua for using in bindings
|
||||
|
||||
local structs_and_enums_table = parser1.structs_and_enums_table
|
||||
structs_and_enums_table.templated_structs = parser1.templated_structs
|
||||
structs_and_enums_table.typenames = parser1.typenames
|
||||
structs_and_enums_table.templates_done = parser1.templates_done
|
||||
|
||||
save_data("./output/structs_and_enums.lua",serializeTableF(structs_and_enums_table))
|
||||
save_data("./output/typedefs_dict.lua",serializeTableF(parser1.typedefs_dict))
|
||||
|
||||
----------save fundefs in definitions.lua for using in bindings
|
||||
--DefsByStruct(pFP)
|
||||
set_defines(parser1.defsT)
|
||||
save_data("./output/definitions.lua",serializeTableF(parser1.defsT))
|
||||
|
||||
--check every function has ov_cimguiname
|
||||
-- for k,v in pairs(parser1.defsT) do
|
||||
-- for _,def in ipairs(v) do
|
||||
-- assert(def.ov_cimguiname)
|
||||
-- end
|
||||
-- end
|
||||
|
||||
--=================================Now implementations
|
||||
local backends_folder
|
||||
local ff,err = io.open (IMGUI_PATH .. "/examples/imgui_impl_glfw.h" ,"r")
|
||||
if ff then
|
||||
backends_folder = IMGUI_PATH .. "/examples/"
|
||||
ff:close()
|
||||
else
|
||||
backends_folder = IMGUI_PATH .. "/backends/"
|
||||
end
|
||||
|
||||
local parser2
|
||||
|
||||
if #implementations > 0 then
|
||||
print("------------------implementations generation with "..COMPILER.."------------------------")
|
||||
parser2 = cpp2ffi.Parser()
|
||||
|
||||
local config = require"config_generator"
|
||||
local impl_str = ""
|
||||
for i,impl in ipairs(implementations) do
|
||||
local source = backends_folder .. [[imgui_impl_]].. impl .. ".h "
|
||||
local locati = [[imgui_impl_]].. impl
|
||||
|
||||
local define_cmd = COMPILER=="cl" and [[ /E /D]] or [[ -E -D]]
|
||||
local extra_defines = ""
|
||||
if impl == "opengl3" then extra_defines = define_cmd .. "IMGUI_IMPL_OPENGL_LOADER_GL3W " end
|
||||
local include_cmd = COMPILER=="cl" and [[ /I ]] or [[ -I ]]
|
||||
local extra_includes = include_cmd.." ".. IMGUI_PATH .." "
|
||||
if config[impl] then
|
||||
for j,inc in ipairs(config[impl]) do
|
||||
extra_includes = extra_includes .. include_cmd .. inc .. " "
|
||||
end
|
||||
end
|
||||
|
||||
local defines = parser2:take_lines(CPRE..extra_defines..extra_includes..source, {locati}, COMPILER)
|
||||
|
||||
local parser3 = cpp2ffi.Parser()
|
||||
parser3:take_lines(CPRE..extra_defines..extra_includes..source, {locati}, COMPILER)
|
||||
parser3:do_parse()
|
||||
local cfuncsstr = func_header_impl_generate(parser3)
|
||||
local cstructstr1,cstructstr2 = parser3.structs_and_enums[1], parser3.structs_and_enums[2]
|
||||
impl_str = impl_str .. "#ifdef CIMGUI_USE_".. string.upper(impl).."\n" .. cstructstr1 .. cstructstr2 .. cfuncsstr .. "\n#endif\n"
|
||||
end
|
||||
|
||||
parser2:do_parse()
|
||||
|
||||
-- save ./cimgui_impl.h
|
||||
--local cfuncsstr = func_header_impl_generate(parser2)
|
||||
--local cstructstr1,cstructstr2 = parser2.structs_and_enums[1], parser2.structs_and_enums[2]
|
||||
--save_data("./output/cimgui_impl.h",cstructstr1,cstructstr2,cfuncsstr)
|
||||
save_data("./output/cimgui_impl.h",impl_str)
|
||||
|
||||
----------save fundefs in impl_definitions.lua for using in bindings
|
||||
save_data("./output/impl_definitions.lua",serializeTableF(parser2.defsT))
|
||||
|
||||
end -- #implementations > 0 then
|
||||
|
||||
-------------------------------json saving
|
||||
--avoid mixed tables (with string and integer keys)
|
||||
local function json_prepare(defs)
|
||||
--delete signatures in function
|
||||
for k,def in pairs(defs) do
|
||||
for k2,v in pairs(def) do
|
||||
if type(k2)=="string" then
|
||||
def[k2] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
return defs
|
||||
end
|
||||
---[[
|
||||
local json = require"json"
|
||||
save_data("./output/definitions.json",json.encode(json_prepare(parser1.defsT),{dict_on_empty={defaults=true}}))
|
||||
--delete extra info for json
|
||||
--structs_and_enums_table.templated_structs = nil
|
||||
--structs_and_enums_table.typenames = nil
|
||||
--structs_and_enums_table.templates_done = nil
|
||||
save_data("./output/structs_and_enums.json",json.encode(structs_and_enums_table))
|
||||
save_data("./output/typedefs_dict.json",json.encode(parser1.typedefs_dict))
|
||||
if parser2 then
|
||||
save_data("./output/impl_definitions.json",json.encode(json_prepare(parser2.defsT),{dict_on_empty={defaults=true}}))
|
||||
end
|
||||
--]]
|
||||
-------------------copy C files to repo root
|
||||
copyfile("./output/cimgui.h", "../cimgui.h")
|
||||
copyfile("./output/cimgui.cpp", "../cimgui.cpp")
|
||||
os.remove("./output/cimgui.h")
|
||||
os.remove("./output/cimgui.cpp")
|
||||
print"all done!!"
|
||||
Reference in New Issue
Block a user