summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bgfx/scripts/codegen.lua
diff options
context:
space:
mode:
author Julian Sikorski <belegdol+github@gmail.com>2019-10-13 13:50:38 +0200
committer R. Belmont <rb6502@users.noreply.github.com>2019-10-13 07:50:38 -0400
commit0837e7451a84f95c29dbdb9bd6b8b931fee1635d (patch)
tree626bcbd250a7fbebdf5958a288d2f438d4f9fb5a /3rdparty/bgfx/scripts/codegen.lua
parentc913ccb59d713ce0b91135520719ac5385e54358 (diff)
WIP: sync bgfx, bx and bimg with latest upstream (#5723)
* Sync with bgfx upstream revision b91d0b6 * Sync with bx upstream revision d60912b * Sync with bimg upstream revision bd81f60 * Add astc-codec decoder * Rename VertexDecl to VertexLayout * Rename UniformType enum Int1 to Sampler. * Add NVN stub * Fix unused-const-variable error on macOS * Drop redundant explicit language parameters buildoptions_cpp are only applied to c++ files and buildoptions_objcpp are only applied to objective c++ files. As such, hardcoding -x offers no benefit while preventing overrides (such as one needed by 3rdparty/bgfx/src/renderer_vk.cpp on macOS) from working. * Re-introduce -x c++ in places where C code is compiled as C++ to prevent clang from throwing a warning * Build bgfx as Objective-C++ on macOS It is needed due to included headers * Enable Direct3D12 and Vulkan bgfx rendering backends * Enable building of spirv shaders * Properly escape /c in cmd call * Comment out dx12 bgfx renderer * Honor VERBOSE setting during shaders build * Only invert hlsl shader XYZ_TO_sRGB matrix for opengl * Add spirv shaders * OpenGL ES needs transposed matrix too * Metal needs transposed matrix as well
Diffstat (limited to '3rdparty/bgfx/scripts/codegen.lua')
-rw-r--r--3rdparty/bgfx/scripts/codegen.lua994
1 files changed, 994 insertions, 0 deletions
diff --git a/3rdparty/bgfx/scripts/codegen.lua b/3rdparty/bgfx/scripts/codegen.lua
new file mode 100644
index 00000000000..3b6a3a937ce
--- /dev/null
+++ b/3rdparty/bgfx/scripts/codegen.lua
@@ -0,0 +1,994 @@
+-- Copyright 2019 云风 https://github.com/cloudwu . All rights reserved.
+-- License (the same with bgfx) : https://github.com/bkaradzic/bgfx/blob/master/LICENSE
+
+local codegen = {}
+
+local NAMEALIGN = 20
+
+local function namealign(name, align)
+ align = align or NAMEALIGN
+ return string.rep(" ", align - #name)
+end
+
+local function camelcase_to_underscorecase(name)
+ local tmp = {}
+ for v in name:gmatch "[%u%d]+%l*" do
+ tmp[#tmp+1] = v:lower()
+ end
+ return table.concat(tmp, "_")
+end
+
+local function to_underscorecase(name)
+ local tmp = {}
+ for v in name:gmatch "[_%u][%l%d]*" do
+ if v:byte() == 95 then -- '_'
+ v = v:sub(2) -- remove _
+ end
+ tmp[#tmp+1] = v
+ end
+ return table.concat(tmp, "_")
+end
+
+local function underscorecase_to_camelcase(name)
+ local tmp = {}
+ for v in name:gmatch "[^_]+" do
+ tmp[#tmp+1] = v:sub(1,1):upper() .. v:sub(2)
+ end
+ return table.concat(tmp)
+end
+
+local function convert_funcname(name)
+ name = name:gsub("^%l", string.upper) -- Change to upper CamlCase
+ return camelcase_to_underscorecase(name)
+end
+
+local function convert_arg(all_types, arg, namespace)
+ local fulltype, array = arg.fulltype:match "(.-)%s*(%[%s*[%d%a_:]*%s*%])"
+ if array then
+ arg.fulltype = fulltype
+ arg.array = array
+ local enum, value = array:match "%[%s*([%a%d]+)::([%a%d]+)%]"
+ if enum then
+ local typedef = all_types[ enum .. "::Enum" ]
+ if typedef == nil then
+ error ("Unknown Enum " .. enum)
+ end
+ arg.carray = "[BGFX_" .. camelcase_to_underscorecase(enum):upper() .. "_" .. value:upper() .. "]"
+ end
+ end
+ local t, postfix = arg.fulltype:match "(%a[%a%d_:]*)%s*([*&]+)%s*$"
+ if t then
+ arg.type = t
+ if postfix == "&" then
+ arg.ref = true
+ end
+ else
+ local prefix, t = arg.fulltype:match "^%s*(%a+)%s+(%S+)"
+ if prefix then
+ arg.type = t
+ else
+ arg.type = arg.fulltype
+ end
+ end
+ local ctype
+ local substruct = namespace.substruct
+ if substruct then
+ ctype = substruct[arg.type]
+ end
+ if not ctype then
+ ctype = all_types[arg.type]
+ end
+ if not ctype then
+ error ("Undefined type " .. arg.fulltype .. " in " .. namespace.name)
+ end
+ arg.ctype = arg.fulltype:gsub(arg.type, ctype.cname):gsub("&", "*")
+ if ctype.cname ~= arg.type then
+ arg.cpptype = arg.fulltype:gsub(arg.type, "bgfx::"..arg.type)
+ else
+ arg.cpptype = arg.fulltype
+ end
+ if arg.ref then
+ arg.ptype = arg.cpptype:gsub("&", "*")
+ end
+end
+
+local function alternative_name(name)
+ if name:sub(1,1) == "_" then
+ return name:sub(2)
+ else
+ return name .. "_"
+ end
+end
+
+local function gen_arg_conversion(all_types, arg)
+ if arg.ctype == arg.fulltype then
+ -- do not need conversion
+ return
+ end
+ local ctype = all_types[arg.type]
+ if ctype.handle and arg.type == arg.fulltype then
+ local aname = alternative_name(arg.name)
+ arg.aname = aname .. ".cpp"
+ arg.aname_cpp2c = aname .. ".c"
+ arg.conversion = string.format(
+ "union { %s c; bgfx::%s cpp; } %s = { %s };" ,
+ ctype.cname, arg.type, aname, arg.name)
+ arg.conversion_back = string.format(
+ "union { bgfx::%s cpp; %s c; } %s = { %s };" ,
+ arg.type, ctype.cname, aname, arg.name)
+ elseif arg.ref then
+ if ctype.cname == arg.type then
+ arg.aname = "*" .. arg.name
+ arg.aname_cpp2c = "&" .. arg.name
+ elseif arg.out and ctype.enum then
+ local aname = alternative_name(arg.name)
+ local cpptype = arg.cpptype:match "(.-)%s*&" -- remove &
+ local c99type = arg.ctype:match "(.-)%s*%*" -- remove *
+ arg.aname = aname
+ arg.aname_cpp2c = "&" .. aname
+ arg.conversion = string.format("%s %s;", cpptype, aname)
+ arg.conversion_back = string.format("%s %s;", c99type, aname);
+ arg.out_conversion = string.format("*%s = (%s)%s;", arg.name, ctype.cname, aname)
+ arg.out_conversion_back = string.format("%s = (%s)%s;", arg.name, c99type, aname)
+ else
+ arg.aname = alternative_name(arg.name)
+ arg.aname_cpp2c = string.format("(%s)&%s" , arg.ctype , arg.name)
+ arg.conversion = string.format(
+ "%s %s = *(%s)%s;",
+ arg.cpptype, arg.aname, arg.ptype, arg.name)
+ end
+ else
+ local cpptype = arg.cpptype
+ local ctype = arg.ctype
+ if arg.array then
+ cpptype = cpptype .. "*"
+ ctype = ctype .. "*"
+ end
+ arg.aname = string.format(
+ "(%s)%s",
+ cpptype, arg.name)
+ arg.aname_cpp2c = string.format(
+ "(%s)%s",
+ ctype, arg.name)
+ end
+end
+
+local function gen_ret_conversion(all_types, func)
+ local postfix = { func.vararg and "va_end(argList);" }
+ local postfix_cpp2c = { postfix[1] }
+ func.ret_postfix = postfix
+ func.ret_postfix_cpp2c = postfix_cpp2c
+
+ for _, arg in ipairs(func.args) do
+ if arg.out_conversion then
+ postfix[#postfix+1] = arg.out_conversion
+ postfix_cpp2c[#postfix_cpp2c+1] = arg.out_conversion_back
+ end
+ end
+
+ local ctype = all_types[func.ret.type]
+ if ctype.handle then
+ func.ret_conversion = string.format(
+ "union { %s c; bgfx::%s cpp; } handle_ret;" ,
+ ctype.cname, ctype.name)
+ func.ret_conversion_cpp2c = string.format(
+ "union { bgfx::%s cpp; %s c; } handle_ret;" ,
+ ctype.name, ctype.cname)
+ func.ret_prefix = "handle_ret.cpp = "
+ func.ret_prefix_cpp2c = "handle_ret.c = "
+ postfix[#postfix+1] = "return handle_ret.c;"
+ postfix_cpp2c[#postfix_cpp2c+1] = "return handle_ret.cpp;"
+ elseif func.ret.fulltype ~= "void" then
+ local ctype_conversion = ""
+ local conversion_back = ""
+ if ctype.name ~= ctype.cname then
+ if func.ret.ref then
+ ctype_conversion = "(" .. func.ret.ctype .. ")&"
+ conversion_back = "*(" .. func.ret.ptype .. ")"
+ else
+ ctype_conversion = "(" .. func.ret.ctype .. ")"
+ conversion_back = "(" .. func.ret.cpptype .. ")"
+ end
+ end
+ if #postfix > 0 then
+ func.ret_prefix = string.format("%s retValue = %s", func.ret.ctype , ctype_conversion)
+ func.ret_prefix_cpp2c = string.format("%s retValue = %s", func.ret.cpptype , conversion_back)
+ local ret = "return retValue;"
+ postfix[#postfix+1] = ret
+ postfix_cpp2c[#postfix_cpp2c+1] = ret
+ else
+ func.ret_prefix = string.format("return %s", ctype_conversion)
+ func.ret_prefix_cpp2c = string.format("return %s", conversion_back)
+ end
+ end
+end
+
+local function convert_vararg(v)
+ if v.vararg then
+ local args = v.args
+ local vararg = {
+ name = "",
+ fulltype = "...",
+ type = "...",
+ ctype = "...",
+ aname = "argList",
+ conversion = string.format(
+ "va_list argList;\n\tva_start(argList, %s);",
+ args[#args].name),
+ }
+ args[#args + 1] = vararg
+ v.alter_name = v.vararg
+ end
+end
+
+local function calc_flag_values(flag)
+ local shift = flag.shift
+ local base = flag.base or 0
+ local cap = 1 << (flag.range or 0)
+
+ if flag.range then
+ if flag.range == 64 then
+ flag.mask = 0xffffffffffffffff
+ else
+ flag.mask = ((1 << flag.range) - 1) << shift
+ end
+ end
+
+ local values = {}
+ for index, item in ipairs(flag.flag) do
+ local value = item.value
+ if flag.const then
+ -- use value directly
+ elseif shift then
+ if value then
+ if value > 0 then
+ value = value - 1
+ end
+ else
+ value = index + base - 1
+ end
+ if value >= cap then
+ error (string.format("Out of range for %s.%s (%d/%d)", flag.name, item.name, value, cap))
+ end
+ value = value << shift
+ elseif #item == 0 then
+ if value then
+ if value > 0 then
+ value = 1 << (value - 1)
+ end
+ else
+ local s = index + base - 2
+ if s >= 0 then
+ value = 1 << s
+ else
+ value = 0
+ end
+ end
+ end
+ if not value then
+ -- It's a combine flags
+ value = 0
+ for _, name in ipairs(item) do
+ local v = values[name]
+ if v then
+ value = value | v
+ else
+ -- todo : it's a undefined flag
+ value = nil
+ break
+ end
+ end
+ end
+ item.value = value
+ values[item.name] = value
+ end
+end
+
+function codegen.nameconversion(all_types, all_funcs)
+ for _,v in ipairs(all_types) do
+ local name = v.name
+ local cname = v.cname
+ if cname == nil then
+ if name:match "^%u" then
+ cname = camelcase_to_underscorecase(name)
+ elseif not v.flag then
+ v.cname = name
+ end
+ end
+ if cname and not v.flag then
+ if v.namespace then
+ cname = camelcase_to_underscorecase(v.namespace) .. "_" .. cname
+ end
+ v.cname = "bgfx_".. cname .. "_t"
+ end
+ if v.enum then
+ v.typename = v.name
+ v.name = v.name .. "::Enum"
+ end
+ if v.flag then
+ calc_flag_values(v)
+ end
+ end
+
+ -- make index
+ for _,v in ipairs(all_types) do
+ if not v.namespace then
+ if all_types[v.name] then
+ error ("Duplicate type " .. v.name)
+ elseif not v.flag then
+ all_types[v.name] = v
+ end
+ end
+ end
+
+ -- make sub struct index
+ for _,v in ipairs(all_types) do
+ if v.namespace then
+ local super = all_types[v.namespace]
+ if not super then
+ error ("Define " .. v.namespace .. " first")
+ end
+ local substruct = super.substruct
+ if not substruct then
+ substruct = {}
+ super.substruct = substruct
+ end
+ if substruct[v.name] then
+ error ( "Duplicate sub struct " .. v.name .. " in " .. v.namespace)
+ end
+ v.parent_class = super
+ substruct[#substruct+1] = v
+ substruct[v.name] = v
+ end
+ end
+
+ for _,v in ipairs(all_types) do
+ if v.struct then
+ for _, item in ipairs(v.struct) do
+ convert_arg(all_types, item, v)
+ end
+ elseif v.args then
+ -- funcptr
+ for _, arg in ipairs(v.args) do
+ convert_arg(all_types, arg, v)
+ end
+ convert_vararg(v)
+ convert_arg(all_types, v.ret, v)
+ end
+ end
+
+ local funcs = {}
+ local funcs_conly = {}
+ local funcs_alter = {}
+
+ for _,v in ipairs(all_funcs) do
+ if v.cname == nil then
+ v.cname = convert_funcname(v.name)
+ end
+ if v.class then
+ v.cname = convert_funcname(v.class) .. "_" .. v.cname
+ local classtype = all_types[v.class]
+ if classtype then
+ local methods = classtype.methods
+ if not methods then
+ methods = {}
+ classtype.methods = methods
+ end
+ methods[#methods+1] = v
+ end
+ elseif not v.conly then
+ funcs[v.name] = v
+ end
+
+ if v.conly then
+ table.insert(funcs_conly, v)
+ end
+
+ for _, arg in ipairs(v.args) do
+ convert_arg(all_types, arg, v)
+ gen_arg_conversion(all_types, arg)
+ end
+ convert_vararg(v)
+ if v.alter_name then
+ funcs_alter[#funcs_alter+1] = v
+ end
+ convert_arg(all_types, v.ret, v)
+ gen_ret_conversion(all_types, v)
+ local namespace = v.class
+ if namespace then
+ local classname = namespace
+ if v.const then
+ classname = "const " .. classname
+ end
+ local classtype = { fulltype = classname .. "*" }
+ convert_arg(all_types, classtype, v)
+ v.this = classtype.ctype
+ v.this_type = classtype
+ v.this_conversion = string.format( "%s This = (%s)_this;", classtype.cpptype, classtype.cpptype)
+ v.this_to_c = string.format("(%s)this", classtype.ctype)
+ end
+ end
+
+ for _, v in ipairs(funcs_conly) do
+ local func = funcs[v.name]
+ if func then
+ func.multicfunc = func.multicfunc or { func.cname }
+ table.insert(func.multicfunc, v.cname)
+ end
+ end
+
+ for _, v in ipairs(funcs_alter) do
+ local func = funcs[v.alter_name]
+ v.alter_cname = func.cname
+ end
+end
+
+local function lines(tbl)
+ if not tbl or #tbl == 0 then
+ return "//EMPTYLINE"
+ else
+ return table.concat(tbl, "\n\t")
+ end
+end
+
+local function remove_emptylines(txt)
+ return (txt:gsub("\t//EMPTYLINE\n", ""))
+end
+
+local function codetemp(func)
+ local conversion = {}
+ local conversion_c2cpp = {}
+ local args = {}
+ local cargs = {}
+ local callargs_conversion = {}
+ local callargs_conversion_back = {}
+ local callargs = {}
+ local cppfunc
+ local classname
+
+ if func.class then
+ -- It's a member function
+ cargs[1] = func.this .. " _this"
+ conversion[1] = func.this_conversion
+ cppfunc = "This->" .. func.name
+ callargs[1] = "_this"
+ callargs_conversion_back[1] = func.this_to_c
+ classname = func.class .. "::"
+ else
+ cppfunc = "bgfx::" .. tostring(func.alter_name or func.name)
+ classname = ""
+ end
+ for _, arg in ipairs(func.args) do
+ conversion[#conversion+1] = arg.conversion
+ conversion_c2cpp[#conversion_c2cpp+1] = arg.conversion_back
+ local cname = arg.ctype .. " " .. arg.name
+ if arg.array then
+ cname = cname .. (arg.carray or arg.array)
+ end
+ local name = arg.fulltype .. " " .. arg.name
+ if arg.array then
+ name = name .. arg.array
+ end
+ if arg.default ~= nil then
+ name = name .. " = " .. tostring(arg.default)
+ end
+ cargs[#cargs+1] = cname
+ args[#args+1] = name
+ callargs_conversion[#callargs_conversion+1] = arg.aname or arg.name
+ callargs_conversion_back[#callargs_conversion_back+1] = arg.aname_cpp2c or arg.name
+ callargs[#callargs+1] = arg.name
+ end
+ conversion[#conversion+1] = func.ret_conversion
+ conversion_c2cpp[#conversion_c2cpp+1] = func.ret_conversion_cpp2c
+
+ local ARGS
+ local args_n = #args
+ if args_n == 0 then
+ ARGS = ""
+ elseif args_n == 1 then
+ ARGS = args[1]
+ else
+ ARGS = "\n\t " .. table.concat(args, "\n\t, ") .. "\n\t"
+ end
+
+ local preret_c2c
+ local postret_c2c = {}
+ local conversion_c2c = {}
+ local callfunc_c2c
+
+ if func.vararg then
+ postret_c2c[1] = "va_end(argList);"
+ local vararg = func.args[#func.args]
+ callargs[#callargs] = vararg.aname
+ callargs_conversion_back[#callargs_conversion_back] = vararg.aname
+ conversion_c2c[1] = vararg.conversion
+ conversion_c2cpp[1] = vararg.conversion
+
+ if func.ret.fulltype == "void" then
+ preret_c2c = ""
+ else
+ preret_c2c = func.ret.ctype .. " retValue = "
+ postret_c2c[#postret_c2c+1] = "return retValue;"
+ end
+ callfunc_c2c = func.alter_cname or func.cname
+ else
+ if func.ret.fulltype == "void" then
+ preret_c2c = ""
+ else
+ preret_c2c = "return "
+ end
+ callfunc_c2c = func.cname
+ end
+
+ outCargs = table.concat(cargs, ", ")
+ if outCargs == "" then
+ outCargs = "void"
+ end
+
+ return {
+ RET = func.ret.fulltype,
+ CRET = func.ret.ctype,
+ CFUNCNAME = func.cname,
+ CFUNCNAMEUPPER = func.cname:upper(),
+ CFUNCNAMECAML = underscorecase_to_camelcase(func.cname),
+ FUNCNAME = func.name,
+ CARGS = outCargs,
+ CPPARGS = table.concat(args, ", "),
+ ARGS = ARGS,
+ CONVERSION = lines(conversion),
+ CONVERSIONCTOC = lines(conversion_c2c),
+ CONVERSIONCTOCPP = lines(conversion_c2cpp),
+ PRERET = func.ret_prefix or "",
+ PRERETCPPTOC = func.ret_prefix_cpp2c or "",
+ CPPFUNC = cppfunc,
+ CALLFUNCCTOC = callfunc_c2c,
+ CALLARGSCTOCPP = table.concat(callargs_conversion, ", "),
+ CALLARGSCPPTOC = table.concat(callargs_conversion_back, ", "),
+ CALLARGS = table.concat(callargs, ", "),
+ POSTRET = lines(func.ret_postfix),
+ POSTRETCPPTOC = lines(func.ret_postfix_cpp2c),
+ PRERETCTOC = preret_c2c,
+ POSTRETCTOC = lines(postret_c2c),
+ CLASSNAME = classname,
+ CONST = func.const and " const" or "",
+ }
+end
+
+local function apply_template(func, temp)
+ func.codetemp = func.codetemp or codetemp(func)
+ return (temp:gsub("$(%u+)", func.codetemp))
+end
+
+function codegen.apply_functemp(func, temp)
+ return remove_emptylines(apply_template(func, temp))
+end
+
+function codegen.gen_funcptr(funcptr)
+ return apply_template(funcptr, "typedef $RET (*$FUNCNAME)($ARGS);")
+end
+
+function codegen.gen_cfuncptr(funcptr)
+ return apply_template(funcptr, "typedef $CRET (*$CFUNCNAME)($CARGS);")
+end
+
+local function doxygen_funcret(r, func, prefix)
+ if not func or func.ret.fulltype == "void" or func.ret.comment == nil then
+ return
+ end
+ r[#r+1] = prefix
+ r[#r+1] = string.format("%s @returns %s", prefix, func.ret.comment[1])
+ for i = 2,#func.ret.comment do
+ r[#r+1] = string.format("%s %s", prefix, func.ret.comment[i])
+ end
+ return r
+end
+
+local function doxygen_func(r, func, prefix)
+ if not func or not func.args or #func.args == 0 then
+ return
+ end
+ r[#r+1] = prefix
+ for _, arg in ipairs(func.args) do
+ local inout
+ if arg.out then
+ inout = "out"
+ elseif arg.inout then
+ inout = "inout"
+ else
+ inout = "in"
+ end
+ local comment = string.format("%s @param[%s] %s", prefix, inout, arg.name)
+ if arg.comment then
+ r[#r+1] = comment .. " " .. arg.comment[1]
+ for i = 2,#arg.comment do
+ r[#r+1] = string.format("%s %s", prefix, arg.comment[i])
+ end
+ else
+ r[#r+1] = comment
+ end
+ end
+ doxygen_funcret(r, func, prefix)
+ return r
+end
+
+function codegen.doxygen_type(doxygen, func, cname)
+ if doxygen == nil then
+ return
+ end
+ local result = {}
+ for _, line in ipairs(doxygen) do
+ result[#result+1] = "/// " .. line
+ end
+ doxygen_func(result, func, "///")
+ if cname then
+ result[#result+1] = "///"
+ if type(cname) == "string" then
+ result[#result+1] = string.format("/// @attention C99 equivalent is `%s`.", cname)
+ else
+ local names = {}
+ for _, v in ipairs(cname) do
+ names[#names+1] = "`" .. v .. "`"
+ end
+ result[#result+1] = string.format("/// @attention C99 equivalent are %s.", table.concat(names, ","))
+ end
+ end
+ result[#result+1] = "///"
+ return table.concat(result, "\n")
+end
+
+function codegen.doxygen_ctype(doxygen, func)
+ if doxygen == nil then
+ return
+ end
+ local result = {
+ "/**",
+ }
+ for _, line in ipairs(doxygen) do
+ result[#result+1] = " * " .. line
+ end
+ doxygen_func(result, func, " *")
+ result[#result+1] = " *"
+ result[#result+1] = " */"
+ return table.concat(result, "\n")
+end
+
+local enum_temp = [[
+struct $NAME
+{
+ $COMMENT
+ enum Enum
+ {
+ $ITEMS
+
+ Count
+ };
+};
+]]
+
+function codegen.gen_enum_define(enum)
+ assert(type(enum.enum) == "table", "Not an enum")
+ local items = {}
+ for _, item in ipairs(enum.enum) do
+ local text
+ if not item.comment then
+ text = item.name .. ","
+ else
+ local comment = table.concat(item.comment, " ")
+ text = string.format("%s,%s //!< %s",
+ item.name, namealign(item.name), comment)
+ end
+ items[#items+1] = text
+ end
+ local comment = ""
+ if enum.comment then
+ comment = "/// " .. enum.comment
+ end
+ local temp = {
+ NAME = enum.typename,
+ COMMENT = comment,
+ ITEMS = table.concat(items, "\n\t\t"),
+ }
+ return (enum_temp:gsub("$(%u+)", temp))
+end
+
+local cenum_temp = [[
+typedef enum $NAME
+{
+ $ITEMS
+
+ $COUNT
+
+} $NAME_t;
+]]
+function codegen.gen_enum_cdefine(enum)
+ assert(type(enum.enum) == "table", "Not an enum")
+ local cname = enum.cname:match "(.-)_t$"
+ local uname = cname:upper()
+ local items = {}
+ for index , item in ipairs(enum.enum) do
+ local comment = ""
+ if item.comment then
+ comment = table.concat(item.comment, " ")
+ end
+ local ename = item.cname
+ if not ename then
+ if enum.underscore then
+ ename = camelcase_to_underscorecase(item.name)
+ else
+ ename = item.name
+ end
+ ename = ename:upper()
+ end
+ local name = uname .. "_" .. ename
+ items[#items+1] = string.format("%s,%s /** (%2d) %s%s */",
+ name,
+ namealign(name, 40),
+ index - 1,
+ comment,
+ namealign(comment, 30))
+ end
+
+ local temp = {
+ NAME = cname,
+ COUNT = uname .. "_COUNT",
+ ITEMS = table.concat(items, "\n\t"),
+ }
+
+ return (cenum_temp:gsub("$(%u+)", temp))
+end
+
+local function flag_format(flag)
+ if not flag.format then
+ flag.format = "%0" .. (flag.bits // 4) .. "x"
+ end
+end
+
+function codegen.gen_flag_cdefine(flag)
+ assert(type(flag.flag) == "table", "Not a flag")
+ flag_format(flag)
+ local cname = "BGFX_" .. (flag.cname or to_underscorecase(flag.name):upper())
+ local s = {}
+ local shift = flag.shift
+ for index, item in ipairs(flag.flag) do
+ local name
+ if item.cname then
+ name = cname .. "_" .. item.cname
+ else
+ name = cname .. "_" .. to_underscorecase(item.name):upper()
+ end
+ local value = item.value
+
+ -- combine flags
+ if #item > 0 then
+ if item.comment then
+ for _, c in ipairs(item.comment) do
+ s[#s+1] = "/// " .. c
+ end
+ end
+ local sets = { "" }
+ for _, v in ipairs(item) do
+ sets[#sets+1] = cname .. "_" .. to_underscorecase(v):upper()
+ end
+ s[#s+1] = string.format("#define %s (0%s \\\n\t)\n", name, table.concat(sets, " \\\n\t| "))
+ else
+ local comment = ""
+ if item.comment then
+ if #item.comment > 1 then
+ for _, c in ipairs(item.comment) do
+ s[#s+1] = "/// " .. c
+ end
+ else
+ comment = " //!< " .. item.comment[1]
+ end
+ end
+ value = string.format(flag.format, value)
+ local code = string.format("#define %s %sUINT%d_C(0x%s)%s",
+ name, namealign(name, 35), flag.bits, value, comment)
+ s[#s+1] = code
+ end
+ end
+
+ local mask
+ if flag.mask then
+ mask = string.format(flag.format, flag.mask)
+ mask = string.format("UINT%d_C(0x%s)", flag.bits, mask)
+ end
+
+ if shift then
+ local name = cname .. "_SHIFT"
+ local comment = flag.desc or ""
+ local shift_align = tostring(shift)
+ shift_align = shift_align .. namealign(shift_align, #mask)
+ local comment = ""
+ if flag.desc then
+ comment = string.format(" //!< %s bit shift", flag.desc)
+ end
+ local code = string.format("#define %s %s%s%s", name, namealign(name, 35), shift_align, comment)
+ s[#s+1] = code
+ end
+ if flag.range then
+ local name = cname .. "_MASK"
+ local comment = ""
+ if flag.desc then
+ comment = string.format(" //!< %s bit mask", flag.desc)
+ end
+ local code = string.format("#define %s %s%s%s", name, namealign(name, 35), mask, comment)
+ s[#s+1] = code
+ end
+
+ if flag.helper then
+ s[#s+1] = string.format(
+ "#define %s(v) ( ( (uint%d_t)(v)<<%s )&%s)",
+ cname,
+ flag.bits,
+ (cname .. "_SHIFT"),
+ (cname .. "_MASK"))
+ end
+
+ s[#s+1] = ""
+
+ return table.concat(s, "\n")
+end
+
+local function text_with_comments(items, item, cstyle, is_classmember)
+ local name = item.name
+ if item.array then
+ if cstyle then
+ name = name .. (item.carray or item.array)
+ else
+ name = name .. item.array
+ end
+ end
+ local typename
+ if cstyle then
+ typename = item.ctype
+ else
+ typename = item.fulltype
+ end
+ if is_classmember then
+ name = "m_" .. name
+ end
+ local text = string.format("%s%s %s;", typename, namealign(typename), name)
+ if item.comment then
+ if #item.comment > 1 then
+ table.insert(items, "")
+ if cstyle then
+ table.insert(items, "/**")
+ for _, c in ipairs(item.comment) do
+ table.insert(items, " * " .. c)
+ end
+ table.insert(items, " */")
+ else
+ for _, c in ipairs(item.comment) do
+ table.insert(items, "/// " .. c)
+ end
+ end
+ else
+ text = string.format(
+ cstyle and "%s %s/** %s%s */" or "%s %s//!< %s",
+ text, namealign(text, 40), item.comment[1], namealign(item.comment[1], 40))
+ end
+ end
+ items[#items+1] = text
+end
+
+local struct_temp = [[
+struct $NAME
+{
+ $METHODS
+ $SUBSTRUCTS
+ $ITEMS
+};
+]]
+
+function codegen.gen_struct_define(struct, methods)
+ assert(type(struct.struct) == "table", "Not a struct")
+ local items = {}
+ for _, item in ipairs(struct.struct) do
+ text_with_comments(items, item, false, methods ~= nil and not struct.shortname)
+ end
+ local ctor = {}
+ if struct.ctor then
+ ctor[1] = struct.name .. "();"
+ ctor[2] = ""
+ end
+ if methods then
+ for _, m in ipairs(methods) do
+ if m:sub(-1) ~= "\n" then
+ m = m .. "\n"
+ end
+ for line in m:gmatch "(.-)\n" do
+ ctor[#ctor+1] = line
+ end
+ ctor[#ctor+1] = ""
+ end
+ end
+ local subs = {}
+ if struct.substruct then
+ for _, v in ipairs(struct.substruct) do
+ local s = codegen.gen_struct_define(v)
+ s = s:gsub("\n", "\n\t")
+ subs[#subs+1] = s
+ end
+ end
+
+ local temp = {
+ NAME = struct.name,
+ SUBSTRUCTS = lines(subs),
+ ITEMS = table.concat(items, "\n\t"),
+ METHODS = lines(ctor),
+ }
+ return remove_emptylines(struct_temp:gsub("$(%u+)", temp))
+end
+
+local cstruct_temp = [[
+typedef struct $NAME_s
+{
+ $ITEMS
+
+} $NAME_t;
+]]
+local cstruct_empty_temp = [[
+struct $NAME_s;
+typedef struct $NAME_s $NAME_t;
+]]
+function codegen.gen_struct_cdefine(struct)
+ assert(type(struct.struct) == "table", "Not a struct")
+ local cname = struct.cname:match "(.-)_t$"
+ local items = {}
+ for _, item in ipairs(struct.struct) do
+ text_with_comments(items, item, true)
+ end
+ local temp = {
+ NAME = cname,
+ ITEMS = table.concat(items, "\n\t"),
+ }
+ local codetemp = #struct.struct == 0 and cstruct_empty_temp or cstruct_temp
+ return (codetemp:gsub("$(%u+)", temp))
+end
+
+local chandle_temp = [[
+typedef struct $NAME_s { uint16_t idx; } $NAME_t;
+]]
+function codegen.gen_chandle(handle)
+ assert(handle.handle, "Not a handle")
+ return (chandle_temp:gsub("$(%u+)", { NAME = handle.cname:match "(.-)_t$" }))
+end
+
+local handle_temp = [[
+struct $NAME { uint16_t idx; };
+inline bool isValid($NAME _handle) { return bgfx::kInvalidHandle != _handle.idx; }
+]]
+function codegen.gen_handle(handle)
+ assert(handle.handle, "Not a handle")
+ return (handle_temp:gsub("$(%u+)", { NAME = handle.name }))
+end
+
+local idl = require "idl"
+local doxygen = require "doxygen"
+local conversion
+local idlfile = {}
+
+function codegen.load(filename)
+ assert(conversion == nil, "Don't call codegen.load() after codegen.idl()")
+ assert(idlfile[filename] == nil, "Duplicate load " .. filename)
+ local source = doxygen.load(filename)
+
+ local f = assert(load(source, filename , "t", idl))
+ f()
+ idlfile[filename] = true
+end
+
+function codegen.idl(filename)
+ if conversion == nil then
+ if filename and not idlfile[filename] then
+ codegen.load(filename)
+ end
+ assert(next(idlfile), "call codegen.load() first")
+ conversion = true
+ codegen.nameconversion(idl.types, idl.funcs)
+ end
+ return idl
+end
+
+return codegen