9612f6d147
* Reformatted comments; fixed a couple of oversights * D bindings: deterministic sub-struct order * Added missing default to IDL * Fixed sub-struct linkage; regenerate D binds * Culled D bindings for header-only C++ functions * Added missing default to bgfx.idl * cppinline now supported by all auto-gen bindings The pattern "func.cppinline and not func.conly" is to make sure that C bindings for `bgfx_vertex_layout_has` are still generated. * Fix mangling issue; use updated BindBC-Common API
894 lines
24 KiB
Lua
894 lines
24 KiB
Lua
local codegen = require "codegen"
|
|
local idl = codegen.idl "bgfx.idl"
|
|
|
|
local template = [[
|
|
/+
|
|
+ ┌==============================┐
|
|
+ │ AUTO GENERATED! DO NOT EDIT! │
|
|
+ └==============================┘
|
|
+/
|
|
module bgfx;
|
|
|
|
import bindbc.bgfx.config;
|
|
|
|
import bindbc.common.types: c_int64, c_uint64, va_list;
|
|
static import bgfx.fakeenum;
|
|
|
|
$version
|
|
|
|
alias ViewID = ushort;
|
|
|
|
enum invalidHandle(T) = T(ushort.max);
|
|
|
|
alias ReleaseFn = void function(void* ptr, void* userData);
|
|
|
|
$types
|
|
pragma(inline,true) nothrow @nogc pure @safe{
|
|
StateBlend_ blendFuncSeparate(StateBlend_ srcRGB, StateBlend_ dstRGB, StateBlend_ srcA, StateBlend_ dstA){
|
|
return (srcRGB | ((dstRGB) << 4)) | ((srcA | (dstA << 4)) << 8);
|
|
}
|
|
|
|
///Blend equation separate.
|
|
StateBlendEquation_ blendEquationSeparate(StateBlendEquation_ equationRGB, StateBlendEquation_ equationA){
|
|
return equationRGB | (equationA << 3);
|
|
}
|
|
|
|
///Blend function.
|
|
StateBlend_ blendFunc(StateBlend_ src, StateBlend_ dst){ return blendFuncSeparate(src, dst, src, dst); }
|
|
|
|
///Blend equation.
|
|
StateBlendEquation_ blendEquation(StateBlendEquation_ equation){ return blendEquationSeparate(equation, equation); }
|
|
|
|
///Utility predefined blend modes.
|
|
enum StateBlendFunc: StateBlend_{
|
|
///Additive blending.
|
|
add = blendFunc(StateBlend.one, StateBlend.one),
|
|
|
|
///Alpha blend.
|
|
alpha = blendFunc(StateBlend.srcAlpha, StateBlend.invSrcAlpha),
|
|
|
|
///Selects darker color of blend.
|
|
darken = blendFunc(StateBlend.one, StateBlend.one) | blendEquation(StateBlendEquation.min),
|
|
|
|
///Selects lighter color of blend.
|
|
lighten = blendFunc(StateBlend.one, StateBlend.one) | blendEquation(StateBlendEquation.max),
|
|
|
|
///Multiplies colors.
|
|
multiply = blendFunc(StateBlend.dstColor, StateBlend.zero),
|
|
|
|
///Opaque pixels will cover the pixels directly below them without any math or algorithm applied to them.
|
|
normal = blendFunc(StateBlend.one, StateBlend.invSrcAlpha),
|
|
|
|
///Multiplies the inverse of the blend and base colors.
|
|
screen = blendFunc(StateBlend.one, StateBlend.invSrcColor),
|
|
|
|
///Decreases the brightness of the base color based on the value of the blend color.
|
|
linearBurn = blendFunc(StateBlend.dstColor, StateBlend.invDstColor) | blendEquation(StateBlendEquation.sub),
|
|
}
|
|
|
|
StateBlend_ blendFuncRTx(StateBlend_ src, StateBlend_ dst){
|
|
return cast(uint)(src >> StateBlend.shift) | (cast(uint)(dst >> StateBlend.shift) << 4);
|
|
}
|
|
|
|
StateBlend_ blendFuncRTxE(StateBlend_ src, StateBlend_ dst, StateBlendEquation_ equation){
|
|
return blendFuncRTx(src, dst) | (cast(uint)(equation >> StateBlendEquation.shift) << 8);
|
|
}
|
|
|
|
StateBlend_ blendFuncRT1(StateBlend_ src, StateBlend_ dst){ return blendFuncRTx(src, dst) << 0; }
|
|
StateBlend_ blendFuncRT2(StateBlend_ src, StateBlend_ dst){ return blendFuncRTx(src, dst) << 11; }
|
|
StateBlend_ blendFuncRT3(StateBlend_ src, StateBlend_ dst){ return blendFuncRTx(src, dst) << 22; }
|
|
|
|
StateBlend_ blendFuncRT1E(StateBlend_ src, StateBlend_ dst, StateBlendEquation_ equation){
|
|
return blendFuncRTxE(src, dst, equation) << 0;
|
|
}
|
|
StateBlend_ blendFuncRT2E(StateBlend_ src, StateBlend_ dst, StateBlendEquation_ equation){
|
|
return blendFuncRTxE(src, dst, equation) << 11;
|
|
}
|
|
StateBlend_ blendFuncRT3E(StateBlend_ src, StateBlend_ dst, StateBlendEquation_ equation){
|
|
return blendFuncRTxE(src, dst, equation) << 22;
|
|
}
|
|
}
|
|
|
|
$structs
|
|
mixin(joinFnBinds((){
|
|
FnBind[] ret = [
|
|
$funcs
|
|
];
|
|
return ret;
|
|
}()));
|
|
|
|
static if(!staticBinding):
|
|
import bindbc.loader;
|
|
|
|
debug{
|
|
mixin(makeDynloadFns("Bgfx", makeLibPaths(["bgfx-shared-libDebug", "bgfxDebug", "bgfx"]), [__MODULE__]));
|
|
}else{
|
|
mixin(makeDynloadFns("Bgfx", makeLibPaths(["bgfx-shared-libRelease", "bgfxRelease", "bgfx"]), [__MODULE__]));
|
|
}
|
|
]]
|
|
|
|
local dKeywords = {"abstract", "alias", "align", "asm", "assert", "auto", "bool", "break", "byte", "case", "cast", "catch", "char", "class", "const", "continue", "dchar", "debug", "default", "delegate", "deprecated", "do", "double", "else", "enum", "export", "extern", "false", "final", "finally", "float", "for", "foreach", "foreach_reverse", "function", "goto", "if", "immutable", "import", "in", "inout", "int", "interface", "invariant", "is", "lazy", "long", "macro", "mixin", "module", "new", "nothrow", "null", "out", "override", "package", "pragma", "private", "protected", "public", "pure", "real", "ref", "return", "scope", "shared", "short", "static", "struct", "super", "switch", "synchronized", "template", "this", "throw", "true", "try", "typeid", "typeof", "ubyte", "uint", "ulong", "union", "unittest", "ushort", "version", "void", "wchar", "while", "with"}
|
|
|
|
local function contains(table, val)
|
|
for i=1,#table do
|
|
if table[i] == val then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function hasPrefix(str, prefix)
|
|
return prefix == "" or str:sub(1, #prefix) == prefix
|
|
end
|
|
|
|
local function hasSuffix(str, suffix)
|
|
return suffix == "" or str:sub(-#suffix) == suffix
|
|
end
|
|
|
|
local enumTypes = {}
|
|
local membersWithFns = ""
|
|
|
|
local capsWords = {"Mip", "Id", "Rw", "Vb", "Ib", "Cb", "Rt", "Pci", "Srgb", "Pt", "Ccw", "2d", "3d", "Msaa"}
|
|
local capsRepl = {
|
|
hidpi = "hiDPI", lineaa = "lineAA", maxanisotropy = "maxAnisotropy",
|
|
notequal = "notEqual", gequal = "gEqual", Lequal = "LEqual", lequal = "lEqual",
|
|
decrsat = "decrSat", incrsat = "incrSat", revsub = "revSub",
|
|
linestrip = "lineStrip", tristrip = "triStrip",
|
|
bstencil = "bStencil", fstencil = "fStencil",
|
|
}
|
|
|
|
local function abbrevsToUpper(name)
|
|
if name:len() >= 3 then
|
|
for _, abbrev in pairs(capsWords) do
|
|
name = name:gsub(abbrev, function(s0)
|
|
return s0:upper()
|
|
end)
|
|
end
|
|
for from, to in pairs(capsRepl) do
|
|
name = name:gsub(from, to)
|
|
end
|
|
end
|
|
return name
|
|
end
|
|
|
|
local function toCamelCase(name)
|
|
if name:len() >= 3 then
|
|
name = name:sub(0, 1) .. name:sub(2, -2):gsub("_", "") .. name:sub(-1)
|
|
end
|
|
if name:find("%u%u+%l") then
|
|
name = name:gsub("(%u-)(%u%l)", function(s0, s1)
|
|
return s0:lower() .. s1
|
|
end)
|
|
else
|
|
name = (name:gsub("^([^%l]*)(%l?)", function(s0, s1)
|
|
if s1 ~= nil then
|
|
return s0:lower() .. s1
|
|
end
|
|
return s0:lower()
|
|
end))
|
|
end
|
|
return abbrevsToUpper(name)
|
|
end
|
|
|
|
-- local function toPascalCase(name)
|
|
-- return (name:gsub("^%l", string.upper))
|
|
-- end
|
|
|
|
local usEnSubs = {
|
|
color = "colour", Color = "Colour",
|
|
rasterize = "rasterise", Rasterize = "Rasterise",
|
|
initialize = "initialise", Initialize = "Initialise",
|
|
normalize = "normalise", Normalize = "Normalise",
|
|
normalized = "normalised", Normalized = "Normalised",
|
|
ccw = "acw", CCW = "ACW",
|
|
}
|
|
local function toIntlEn(name)
|
|
local change = false
|
|
for us, intl in pairs(usEnSubs) do
|
|
if name:find(us) then
|
|
name = (name:gsub(us, intl))
|
|
change = true
|
|
end
|
|
end
|
|
if change then
|
|
return name
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
-- Unconditionally convert
|
|
local function toIntlEnUncond(name)
|
|
local newName = toIntlEn(name)
|
|
if newName ~= nil then
|
|
return newName
|
|
end
|
|
return name
|
|
end
|
|
|
|
local function hexStr(val, bits)
|
|
local digits = bits / 4
|
|
local str = string.format(string.format("%%0%iX", digits), val)
|
|
local i = 4
|
|
while i < str:len() do
|
|
str = str:sub(0, i) .. "_" .. str:sub(i+1)
|
|
i = i + 5
|
|
end
|
|
|
|
return "0x" .. str
|
|
end
|
|
|
|
local function convArray(array)
|
|
if string.find(array, "::") then
|
|
return string.gsub(array, "::.*", ".") .. toCamelCase(string.gsub(array, ".-::", ""))
|
|
else
|
|
return array
|
|
end
|
|
end
|
|
|
|
local typeSubs = {
|
|
uint32_t = "uint", int32_t = "int",
|
|
uint16_t = "ushort", int16_t = "short",
|
|
uint64_t = "c_uint64", int64_t = "c_int64",
|
|
uint8_t = "ubyte", int8_t = "byte",
|
|
uintptr_t = "size_t"
|
|
}
|
|
local function convSomeType(arg, isFnArg)
|
|
local type = arg.fulltype
|
|
if type == "bx::AllocatorI*" or type == "CallbackI*" then
|
|
type = "void*"
|
|
else
|
|
for from, to in pairs(typeSubs) do
|
|
if type:find(from) then
|
|
type = type:gsub(from, to)
|
|
break
|
|
end
|
|
end
|
|
type = type:gsub("::Enum", "") --fix enums
|
|
type = type:gsub("%s+%*", "*") --remove spacing before `*`
|
|
|
|
if isFnArg then
|
|
for _, enum in pairs(enumTypes) do --fix C++ linkage errors
|
|
if type == enum then
|
|
type = string.format("bgfx.fakeenum.%s.Enum", enum)
|
|
else
|
|
type = (type:gsub("(" .. enum .. ")([^A-Za-z0-9_])", function(s0, s1)
|
|
return string.format("bgfx.fakeenum.%s.Enum", enum) .. s1
|
|
end))
|
|
end
|
|
end
|
|
type = type:gsub("([^&]-)%s?&", "ref %1") --change `&` suffix to `ref` prefix
|
|
if arg.array ~= nil then
|
|
type = type .. "*" --append *
|
|
end
|
|
else
|
|
type = type:gsub("([^&]-)%s?&", "%1*") --change `&` to `*`
|
|
if arg.array ~= nil then
|
|
type = type .. convArray(arg.array) --append [n]
|
|
end
|
|
end
|
|
type = type:gsub("const%s+([A-Za-z_][A-Za-z0-9_]*)%s*%*", "const(%1)*") --change `const x*` to `const(x)*`
|
|
type = abbrevsToUpper(type)
|
|
end
|
|
|
|
return type
|
|
end
|
|
|
|
local function convType(arg)
|
|
return convSomeType(arg, false)
|
|
end
|
|
|
|
local function convFnArgType(arg)
|
|
return convSomeType(arg, true)
|
|
end
|
|
|
|
local valSubs = {
|
|
NULL = "null",
|
|
UINT8_MAX = "ubyte.max",
|
|
UINT16_MAX = "ushort.max",
|
|
UINT32_MAX = "uint.max",
|
|
|
|
BGFX_INVALID_HANDLE = "invalidHandle",
|
|
|
|
BGFX_DISCARD_ALL = "Discard.all",
|
|
BGFX_BUFFER_NONE = "Buffer.none",
|
|
BGFX_STENCIL_NONE = "Stencil.none",
|
|
BGFX_TEXTURE_NONE = "Texture.none",
|
|
BGFX_SAMPLER_NONE = "Sampler.none",
|
|
BGFX_RESET_NONE = "Reset.none",
|
|
BGFX_SAMPLER_U_CLAMP = "SamplerU.clamp",
|
|
BGFX_SAMPLER_V_CLAMP = "SamplerV.clamp",
|
|
BGFX_RESOLVE_AUTO_GEN_MIPS = "Resolve.autoGenMIPs",
|
|
["ViewMode::Default"] = "ViewMode.default_",
|
|
}
|
|
local function convVal(arg, type)
|
|
local val = string.format("%s", arg)
|
|
for from, to in pairs(valSubs) do
|
|
if val:find(from) then
|
|
if from == "BGFX_INVALID_HANDLE" then
|
|
val = val:gsub(from, to .. "!" .. type)
|
|
else
|
|
val = val:gsub(from, to)
|
|
end
|
|
end
|
|
end
|
|
if val:find("INT32_MAX") then
|
|
val = val:gsub("INT32_MAX", "int.max")
|
|
end
|
|
val = convArray(val)
|
|
|
|
return val
|
|
end
|
|
|
|
local function convStructType(arg)
|
|
return convType(arg)
|
|
end
|
|
|
|
local function convName(name)
|
|
name = abbrevsToUpper(name)
|
|
if contains(dKeywords, name) then
|
|
return name .. "_"
|
|
end
|
|
return name
|
|
end
|
|
|
|
local function convStructMember(member)
|
|
return convStructType(member) .. " " .. convName(member.name)
|
|
end
|
|
|
|
local allStructs = {}
|
|
|
|
local function genVersion()
|
|
return "enum uint apiVersion = " .. (idl._version or 0) .. ";"
|
|
end
|
|
|
|
local function genStructMemberFn(func) --NOTE: this does not work on nested structs
|
|
if func.class ~= nil and func.conly == nil and func.cppinline == nil then
|
|
local st = allStructs[func.class]
|
|
local attribs = ""
|
|
if func.comments ~= nil then
|
|
if #st.fns > 0 then
|
|
table.insert(st.fns, "")
|
|
end
|
|
table.insert(st.fns, "/**")
|
|
for _, line in ipairs(func.comments) do
|
|
local line = line:gsub("@remarks", "Remarks:")
|
|
line = line:gsub("@remark", "Remarks:")
|
|
line = line:gsub("@(%l)(%l+)", function(a, b) return a:upper() .. b .. ":" end)
|
|
table.insert(st.fns, line)
|
|
end
|
|
|
|
local hasParamsComments = false
|
|
for _, arg in ipairs(func.args) do
|
|
if arg.comment ~= nil then
|
|
hasParamsComments = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if hasParamsComments then
|
|
table.insert(st.fns, "Params:")
|
|
end
|
|
|
|
for _, arg in ipairs(func.args) do
|
|
if arg.comment ~= nil then
|
|
table.insert(st.fns, "\t" .. toIntlEnUncond(convName(arg.name:sub(2))) .. " = " .. arg.comment[1])
|
|
for i, comment in ipairs(arg.comment) do
|
|
if i > 1 then
|
|
table.insert(st.fns, comment)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
table.insert(st.fns, "*/")
|
|
end
|
|
|
|
local args = {}
|
|
for _, arg in ipairs(func.args) do
|
|
local def = ""
|
|
if arg.default ~= nil then
|
|
def = string.format("=%s", convVal(arg.default, convFnArgType(arg)))
|
|
end
|
|
if arg.fulltype == "..." then
|
|
table.insert(args, "..." .. def)
|
|
else
|
|
table.insert(args, convFnArgType(arg) .. " " .. toIntlEnUncond(convName(arg.name:sub(2))) .. def)
|
|
end
|
|
end
|
|
|
|
if func.const ~= nil then
|
|
attribs = "const"
|
|
end
|
|
if attribs ~= "" then
|
|
attribs = ", memAttr: q{" .. attribs .. "}"
|
|
end
|
|
|
|
table.insert(st.fns, string.format("{q{%s}, q{%s}, q{%s}, ext: `C++`%s},", convType(func.ret), func.name, table.concat(args, ", "), attribs))
|
|
end
|
|
end
|
|
|
|
local converter = {}
|
|
local yield = coroutine.yield
|
|
local gen = {}
|
|
|
|
gen.fakeEnumFile = [[
|
|
/+
|
|
+ ┌==============================┐
|
|
+ │ AUTO GENERATED! DO NOT EDIT! │
|
|
+ └==============================┘
|
|
+/
|
|
module bgfx.fakeenum;
|
|
|
|
//NOTE: Do NOT use this module! Use the enums with the same names in `bgfx/package.d` instead.
|
|
package:
|
|
]]
|
|
|
|
function gen.gen()
|
|
local indent = ""
|
|
local idx = 1;
|
|
local r = template:gsub("$([a-zA-Z_]+)", function(what)
|
|
local tmp = {}
|
|
|
|
local ind_end = template:find("$"..what, idx, true)
|
|
local ind_start = ind_end
|
|
for j = 1, ind_end-1 do
|
|
local i = 1+ind_end-1-j
|
|
local c = string.sub(template, i, i)
|
|
if c ~= ' ' and c ~= '\t' then
|
|
ind_start = i
|
|
break
|
|
end
|
|
end
|
|
|
|
indent = string.sub(template, ind_start+1, ind_end-1)
|
|
|
|
if what == "version" then
|
|
return genVersion()
|
|
elseif what == "structs" then
|
|
for _, fn in ipairs(idl.funcs) do
|
|
genStructMemberFn(fn)
|
|
end
|
|
for _, object in ipairs(idl["types"]) do
|
|
if object.struct ~= nil and object.namespace == nil then
|
|
local co = coroutine.create(converter[what])
|
|
local any
|
|
while true do
|
|
local ok, v = coroutine.resume(co, allStructs[object.name], object.name, true, indent:len())
|
|
assert(ok, debug.traceback(co, v))
|
|
if not v then
|
|
break
|
|
end
|
|
table.insert(tmp, v)
|
|
any = true
|
|
end
|
|
if any and tmp[#tmp] ~= "" then
|
|
table.insert(tmp, "")
|
|
end
|
|
end
|
|
end
|
|
elseif what == "membersWithFns" then
|
|
table.insert(tmp, "\"" .. membersWithFns .. "\"")
|
|
else
|
|
for _, object in ipairs(idl[what]) do
|
|
local co = coroutine.create(converter[what])
|
|
local any
|
|
while true do
|
|
local ok, v = coroutine.resume(co, object)
|
|
assert(ok, debug.traceback(co, v))
|
|
if not v then
|
|
break
|
|
end
|
|
table.insert(tmp, v)
|
|
any = true
|
|
end
|
|
if any and tmp[#tmp] ~= "" then
|
|
table.insert(tmp, "")
|
|
end
|
|
end
|
|
end
|
|
return table.concat(tmp, "\n" .. indent)
|
|
end)
|
|
return r
|
|
end
|
|
|
|
function converter.structs(st, name, topLvl)
|
|
for _, line in ipairs(st.comments) do
|
|
yield(line)
|
|
end
|
|
|
|
if topLvl then
|
|
yield("extern(C++, \"bgfx\") struct " .. name .. "{")
|
|
else
|
|
yield("extern(C++) struct " .. name .. "{")
|
|
end
|
|
|
|
local subN = 0
|
|
for _, subStruct in ipairs(st.subs) do
|
|
subN = subN + 1
|
|
local co = coroutine.create(converter.structs)
|
|
while true do
|
|
local ok, v = coroutine.resume(co, subStruct, subStruct.name, false)
|
|
assert(ok, debug.traceback(co, v))
|
|
if not v then
|
|
break
|
|
end
|
|
yield("\t" .. v)
|
|
end
|
|
end
|
|
if subN > 0 then
|
|
yield("\t")
|
|
end
|
|
|
|
for _, line in ipairs(st.fields) do
|
|
yield(line)
|
|
end
|
|
|
|
if #st.fns > 0 then
|
|
membersWithFns = membersWithFns .. name .. ", "
|
|
yield("\textern(D) mixin(joinFnBinds((){")
|
|
yield("\t\tFnBind[] ret = [")
|
|
for _, line in ipairs(st.fns) do
|
|
yield("\t\t\t" .. line)
|
|
end
|
|
yield("\t\t];")
|
|
yield("\t\treturn ret;")
|
|
yield("\t}()));")
|
|
end
|
|
|
|
yield("}")
|
|
end
|
|
|
|
function converter.types(typ)
|
|
if typ.comments ~= nil and not typ.struct then
|
|
if #typ.comments == 1 then
|
|
yield("///" .. typ.comments[1])
|
|
else
|
|
yield("/**")
|
|
for _, comment in ipairs(typ.comments) do
|
|
yield(comment)
|
|
end
|
|
yield("*/")
|
|
end
|
|
end
|
|
|
|
if typ.handle then ---hnadle
|
|
yield("extern(C++, \"bgfx\") struct " .. typ.name .. "{")
|
|
yield("\tushort idx;")
|
|
yield("}")
|
|
--yield(typ.name .. " invalidHandle(){ return " .. typ.name .. "(ushort.max); }")
|
|
|
|
-- For some reason, this has never worked, so I'm commenting it out just in case it does start working suddenly. :P
|
|
--[[
|
|
elseif typ.funcptr then
|
|
local args = {}
|
|
for _, arg in ipairs(typ.args) do
|
|
if arg.fulltype == "..." then
|
|
table.insert(args, "..." .. def)
|
|
else
|
|
table.insert(args, convFnArgType(arg) .. " " .. convName(arg.name:sub(2)) .. def)
|
|
end
|
|
end
|
|
|
|
yield(string.format("alias %s = extern(C++) %s function(%s);", typ.name, convType(typ.ret), table.concat(args, ", ")))
|
|
--]]
|
|
elseif typ.enum then
|
|
local typeName = abbrevsToUpper(typ.name:gsub("::Enum", ""))
|
|
local otherName = string.format("bgfx.fakeenum.%s.Enum", typ.name:gsub("::Enum", ""))
|
|
|
|
yield("enum " .. typeName .. ": " .. otherName .. "{")
|
|
table.insert(enumTypes, typeName)
|
|
|
|
local vals = ""
|
|
for idx, enum in ipairs(typ.enum) do
|
|
local comments = ""
|
|
if enum.comment ~= nil then
|
|
if #enum.comment == 1 then
|
|
comments = " ///" .. enum.comment[1];
|
|
else
|
|
yield("\t/**")
|
|
for _, comment in ipairs(enum.comment) do
|
|
yield("\t" .. comment)
|
|
end
|
|
yield("\t*/")
|
|
end
|
|
end
|
|
local name = convName(toCamelCase(enum.name))
|
|
yield("\t" .. name .. " = " .. otherName .. "." .. name .. ",")
|
|
vals = vals .. name .. ","
|
|
|
|
local intlName = toIntlEn(enum.name)
|
|
if intlName ~= nil then
|
|
yield("\t" .. convName(toCamelCase(intlName)) .. " = " .. otherName .. "." .. name .. ",")
|
|
end
|
|
end
|
|
|
|
gen.fakeEnumFile = gen.fakeEnumFile .. string.format([[
|
|
extern(C++, "bgfx") package final abstract class %s{
|
|
enum Enum{
|
|
%scount
|
|
}
|
|
}
|
|
]], typeName, vals)
|
|
|
|
yield("\t" .. "count = " .. otherName .. ".count,")
|
|
yield("}")
|
|
|
|
elseif typ.bits ~= nil then
|
|
local typeName = convName(typ.name)
|
|
if typeName == "Caps" then
|
|
typeName = "CapFlags"
|
|
end
|
|
|
|
local enumType = "uint"
|
|
if typ.bits == 64 then
|
|
enumType = "ulong"
|
|
elseif typ.bits == 32 then
|
|
enumType = "uint"
|
|
elseif typ.bits == 16 then
|
|
enumType = "ushort"
|
|
elseif typ.bits == 8 then
|
|
enumType = "ubyte"
|
|
end
|
|
|
|
local maxLen = 0
|
|
if typ.shift then
|
|
maxLen = string.len("shift")
|
|
elseif typ.range then
|
|
maxLen = string.len("mask")
|
|
end
|
|
for _, flag in ipairs(typ.flag) do
|
|
maxLen = math.max(maxLen, flag.name:len())
|
|
end
|
|
|
|
yield("alias " .. typeName .. "_ = " .. enumType .. ";")
|
|
yield("enum " .. typeName .. ": " .. typeName .. "_{")
|
|
|
|
local function getValOr(name)
|
|
local t = typeName
|
|
if typeName == "State" then
|
|
if hasPrefix(name, "Write") then
|
|
t = t .. name:sub(1, 5)
|
|
name = name:sub(6)
|
|
elseif hasPrefix(name, "DepthTest") then
|
|
t = t .. name:sub(1, 9)
|
|
name = name:sub(10)
|
|
elseif hasPrefix(name, "Cull") then
|
|
t = t .. name:sub(1, 4)
|
|
name = name:sub(5)
|
|
end
|
|
elseif typeName == "Sampler" then
|
|
if hasPrefix(name, "Min") then
|
|
t = t .. name:sub(1, 3)
|
|
name = name:sub(4)
|
|
elseif hasPrefix(name, "Mag") then
|
|
t = t .. name:sub(1, 3)
|
|
name = name:sub(4)
|
|
elseif hasPrefix(name, "Mip") then
|
|
t = t .. name:sub(1, 3)
|
|
name = name:sub(4)
|
|
elseif hasPrefix(name, "U") then
|
|
t = t .. name:sub(1, 1)
|
|
name = name:sub(2)
|
|
elseif hasPrefix(name, "V") then
|
|
t = t .. name:sub(1, 1)
|
|
name = name:sub(2)
|
|
elseif hasPrefix(name, "W") then
|
|
t = t .. name:sub(1, 1)
|
|
name = name:sub(2)
|
|
elseif hasPrefix(name, "Compare") then
|
|
t = t .. name:sub(1, 7)
|
|
name = name:sub(8)
|
|
end
|
|
end
|
|
return abbrevsToUpper(t) .. "." .. convName(toCamelCase(name))
|
|
end
|
|
|
|
for idx, flag in ipairs(typ.flag) do
|
|
local value = flag.value
|
|
if value ~= nil then
|
|
value = hexStr(value, typ.bits)
|
|
else
|
|
for _, name in ipairs(flag) do
|
|
if value ~= nil then
|
|
value = value .. " | " .. getValOr(name)
|
|
else
|
|
value = getValOr(name)
|
|
end
|
|
end
|
|
end
|
|
|
|
local comments = ""
|
|
if flag.comment ~= nil then
|
|
if #flag.comment == 1 then
|
|
comments = " ///" .. flag.comment[1]
|
|
else
|
|
yield("\t/**")
|
|
for _, comment in ipairs(flag.comment) do
|
|
yield("\t" .. comment)
|
|
end
|
|
yield("\t*/")
|
|
end
|
|
end
|
|
|
|
local name = convName(toCamelCase(flag.name))
|
|
yield("\t" .. name .. string.rep(" ", maxLen+2 - name:len()) .. "= " .. value .. "," .. comments)
|
|
|
|
local intlName = toIntlEn(name)
|
|
if intlName ~= nil then
|
|
intlName = intlName
|
|
yield("\t" .. intlName .. string.rep(" ", maxLen+2 - intlName:len()) .. "= " .. name .. ",")
|
|
end
|
|
end
|
|
|
|
if typ.shift then
|
|
local name = convName("shift")
|
|
local value = typ.shift
|
|
local comments = ""
|
|
if typ.desc then
|
|
comments = string.format(" ///%s bit shift", typ.desc)
|
|
end
|
|
yield("\t" .. name .. string.rep(" ", maxLen+2 - name:len()) .. "= " .. value .. "," .. comments)
|
|
end
|
|
if typ.range then
|
|
local name = convName("mask")
|
|
local value = hexStr(typ.mask, typ.bits)
|
|
local comments = ""
|
|
if typ.desc then
|
|
comments = string.format(" ///%s bit mask", typ.desc)
|
|
end
|
|
yield("\t" .. name .. string.rep(" ", maxLen+2 - name:len()) .. "= " .. value .. "," .. comments)
|
|
end
|
|
yield("}")
|
|
|
|
local intlName = toIntlEn(typeName)
|
|
if intlName ~= nil then
|
|
yield("alias " .. intlName .. " = " .. typeName .. ";")
|
|
end
|
|
|
|
if typ.helper then
|
|
yield(string.format(
|
|
"%s_ to%s(%s v){ return (v << %s) & %s; }",
|
|
typeName,
|
|
typeName,
|
|
enumType,
|
|
(typeName .. ".shift"),
|
|
(typeName .. ".mask")))
|
|
if intlName ~= nil then
|
|
yield("alias to" .. intlName .. " = to" .. typeName .. ";")
|
|
end
|
|
end
|
|
elseif typ.struct ~= nil then
|
|
local st = {name = typ.name, comments = {}, fields = {}, fns = {}, subs = {}}
|
|
|
|
if typ.comments ~= nil then
|
|
if #typ.comments == 1 then
|
|
table.insert(st.comments, "///" .. typ.comments[1])
|
|
else
|
|
table.insert(st.comments, "/**")
|
|
for _, comment in ipairs(typ.comments) do
|
|
table.insert(st.comments, comment)
|
|
end
|
|
table.insert(st.comments, "*/")
|
|
end
|
|
end
|
|
|
|
for _, member in ipairs(typ.struct) do
|
|
local comments = ""
|
|
if member.comment ~= nil then
|
|
if #member.comment == 1 then
|
|
comments = " ///" .. member.comment[1]
|
|
else
|
|
if #st.fields > 0 then
|
|
table.insert(st.fields, "\t")
|
|
end
|
|
table.insert(st.fields, "\t/**")
|
|
for _, comment in ipairs(member.comment) do
|
|
table.insert(st.fields, "\t" .. comment)
|
|
end
|
|
table.insert(st.fields, "\t*/")
|
|
end
|
|
end
|
|
table.insert(st.fields, "\t" .. convStructMember(member) .. ";" .. comments)
|
|
end
|
|
|
|
if typ.ctor ~= nil and typ.name ~= "PlatformData" then
|
|
table.insert(st.fns, "{q{void}, q{this}, q{}, ext: `C++`},")
|
|
end
|
|
|
|
if typ.namespace ~= nil then --if this is a sub-struct
|
|
if allStructs[typ.namespace] ~= nil then
|
|
table.insert(allStructs[typ.namespace].subs, st)
|
|
else
|
|
allStructs[typ.namespace] = {subs = {st}}
|
|
end
|
|
else --otherwise it's top-level
|
|
if allStructs[typ.name] ~= nil then
|
|
st.subs = allStructs[typ.name].subs
|
|
end
|
|
allStructs[typ.name] = st
|
|
end
|
|
end
|
|
end
|
|
|
|
function converter.funcs(func)
|
|
if func.class == nil and func.conly == nil and func.cppinline == nil then
|
|
local extern = "C++, \"bgfx\""
|
|
local attribs = ""
|
|
if func.cfunc ~= nil and func.name ~= "init" then --what the is "cfunc" even meant to mean?
|
|
return
|
|
end
|
|
if func.comments ~= nil then
|
|
yield("/**")
|
|
for _, line in ipairs(func.comments) do
|
|
local line = line:gsub("@remarks", "Remarks:")
|
|
line = line:gsub("@remark", "Remarks:")
|
|
line = line:gsub("@(%l)(%l+)", function(a, b) return a:upper() .. b .. ":" end)
|
|
yield("* " .. line)
|
|
end
|
|
|
|
local hasParamsComments = false
|
|
for _, arg in ipairs(func.args) do
|
|
if arg.comment ~= nil then
|
|
hasParamsComments = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if hasParamsComments then
|
|
yield("Params:")
|
|
end
|
|
|
|
for _, arg in ipairs(func.args) do
|
|
if arg.comment ~= nil then
|
|
yield("\t" .. toIntlEnUncond(convName(arg.name:sub(2))) .. " = " .. arg.comment[1])
|
|
for i, comment in ipairs(arg.comment) do
|
|
if i > 1 then
|
|
yield(comment)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
yield("*/")
|
|
end
|
|
|
|
local args = {}
|
|
for _, arg in ipairs(func.args) do
|
|
local def = ""
|
|
if arg.default ~= nil then
|
|
def = string.format("=%s", convVal(arg.default, convFnArgType(arg)))
|
|
end
|
|
if arg.fulltype == "..." then
|
|
table.insert(args, "..." .. def)
|
|
else
|
|
table.insert(args, convFnArgType(arg) .. " " .. toIntlEnUncond(convName(arg.name:sub(2))) .. def)
|
|
end
|
|
end
|
|
|
|
if attribs ~= "" then
|
|
attribs = ", memAttr: q{" .. attribs .. "}"
|
|
end
|
|
|
|
yield(string.format("{q{%s}, q{%s}, q{%s}, ext: `%s`%s},", convType(func.ret), func.name, table.concat(args, ", "), extern, attribs))
|
|
end
|
|
end
|
|
|
|
-- printtable("idl types", idl.types)
|
|
-- printtable("idl funcs", idl.funcs)
|
|
|
|
function gen.write(codes, outputfile)
|
|
local out = assert(io.open(outputfile, "wb"))
|
|
out:write(codes)
|
|
out:close()
|
|
print("Generating: " .. outputfile)
|
|
end
|
|
|
|
if (...) == nil then
|
|
-- run `lua bindings-d.lua` in command line
|
|
print(gen.gen(dTemplate))
|
|
end
|
|
|
|
return gen
|