bindings-d.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. local codegen = require "codegen"
  2. local idl = codegen.idl "bgfx.idl"
  3. local d_types_template = [[
  4. /*
  5. *
  6. * AUTO GENERATED! DO NOT EDIT!
  7. *
  8. */
  9. module bindbc.bgfx.types;
  10. public import core.stdc.stdarg : va_list;
  11. enum expandEnum(EnumType, string fqnEnumType = EnumType.stringof) = (){
  12. string expandEnum;
  13. foreach(m; __traits(allMembers, EnumType)){
  14. expandEnum ~= "alias " ~ m ~ " = " ~ fqnEnumType ~ "." ~ m ~ ";";
  15. }
  16. return expandEnum;
  17. }();
  18. extern(C) @nogc nothrow:
  19. $version
  20. alias bgfx_view_id_t = ushort;
  21. //NOTE: TEMPORARY fix to some missing preprocessor function-macros...
  22. static BGFX_STATE_BLEND_FUNC_SEPARATE(ulong _srcRGB, ulong _dstRGB, ulong _srcA, ulong _dstA){
  23. return (0UL
  24. | ( ( cast(ulong)_srcRGB | ( cast(ulong)_dstRGB<<4) ) )
  25. | ( ( cast(ulong)_srcA | ( cast(ulong)_dstA <<4) )<<8)
  26. );
  27. }
  28. /// Blend equation separate.
  29. static BGFX_STATE_BLEND_EQUATION_SEPARATE(ulong _equationRGB, ulong _equationA){ return ( cast(ulong)_equationRGB | (cast(ulong)_equationA<<3) ); }
  30. /// Blend function.
  31. static BGFX_STATE_BLEND_FUNC(ulong _src, ulong _dst){ return BGFX_STATE_BLEND_FUNC_SEPARATE(_src, _dst, _src, _dst); }
  32. /// Blend equation.
  33. static BGFX_STATE_BLEND_EQUATION(ulong _equation){ return BGFX_STATE_BLEND_EQUATION_SEPARATE(_equation, _equation); }
  34. /// Utility predefined blend modes.
  35. /// Additive blending.
  36. static BGFX_STATE_BLEND_ADD(){ return (0 | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE)); }
  37. /// Alpha blend.
  38. static BGFX_STATE_BLEND_ALPHA(){ return (0 | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA)); }
  39. $types
  40. ]]
  41. local d_funcs_template = [[
  42. /*
  43. *
  44. * AUTO GENERATED! DO NOT EDIT!
  45. *
  46. */
  47. module bindbc.bgfx.funcs;
  48. private import bindbc.bgfx.types;
  49. extern(C) @nogc nothrow:
  50. version(BindBgfx_Static)
  51. {
  52. $funcs_static
  53. }
  54. else
  55. {
  56. __gshared
  57. {
  58. $funcs_dynamic
  59. }
  60. }
  61. ]]
  62. local function hasPrefix(str, prefix)
  63. return prefix == "" or str:sub(1, #prefix) == prefix
  64. end
  65. local function hasSuffix(str, suffix)
  66. return suffix == "" or str:sub(-#suffix) == suffix
  67. end
  68. local function to_underscorecase(name)
  69. local tmp = {}
  70. for v in name:gmatch "[_%u][%l%d]*" do
  71. if v:byte() == 95 then -- '_'
  72. v = v:sub(2) -- remove _
  73. end
  74. tmp[#tmp+1] = v
  75. end
  76. return table.concat(tmp, "_")
  77. end
  78. local function convert_array(member)
  79. if string.find(member.array, "::") then
  80. local name = "bgfx_" .. to_underscorecase(string.gsub(member.array, "::.*", "")):lower() .. "_t"
  81. return "[" .. name .. ".BGFX_" .. to_underscorecase(member.array):upper() .. "]"
  82. else
  83. return member.array
  84. end
  85. end
  86. local function convert_type(arg)
  87. local ctype = arg.ctype:gsub("%s%*", "*")
  88. if arg.fulltype == "bx::AllocatorI*" or arg.fulltype == "CallbackI*" or arg.fulltype == "ReleaseFn" then
  89. ctype = "void*"
  90. elseif hasPrefix(ctype, "uint64_t") then
  91. ctype = ctype:gsub("uint64_t", "ulong")
  92. elseif hasPrefix(ctype, "int64_t") then
  93. ctype = ctype:gsub("int64_t", "long")
  94. elseif hasPrefix(ctype, "uint32_t") then
  95. ctype = ctype:gsub("uint32_t", "uint")
  96. elseif hasPrefix(ctype, "int32_t") then
  97. ctype = ctype:gsub("int32_t", "int")
  98. elseif hasPrefix(ctype, "uint16_t") then
  99. ctype = ctype:gsub("uint16_t", "ushort")
  100. elseif hasPrefix(ctype, "uint8_t") then
  101. ctype = ctype:gsub("uint8_t", "ubyte")
  102. elseif hasPrefix(ctype, "uintptr_t") then
  103. ctype = ctype:gsub("uintptr_t", "ulong")
  104. elseif hasPrefix(ctype, "const ") and hasSuffix(ctype, "*") then
  105. ctype = "const(" .. string.sub(ctype:gsub("const ", "", 1), 1, -2) .. ")*"
  106. end
  107. if arg.array ~= nil then
  108. ctype = ctype .. convert_array(arg)
  109. end
  110. return ctype
  111. end
  112. local function convert_struct_type(arg)
  113. return convert_type(arg)
  114. end
  115. local function convert_ret_type(arg)
  116. return convert_type(arg)
  117. end
  118. local function convert_name(arg)
  119. if arg == "debug" then
  120. return arg .. "_"
  121. end
  122. return arg
  123. end
  124. local function convert_struct_member(member)
  125. return convert_struct_type(member) .. " " .. convert_name(member.name)
  126. end
  127. local function gen_version()
  128. return "enum uint BGFX_API_VERSION = " .. (idl._version or 0) .. ";"
  129. end
  130. local converter = {}
  131. local yield = coroutine.yield
  132. local gen = {}
  133. function gen.gen(template)
  134. local indent = ""
  135. local idx = 1;
  136. local r = template:gsub("$([a-zA-Z_]+)", function(what)
  137. local tmp = {}
  138. local ind_end = template:find("$"..what, idx, true)
  139. local ind_start = ind_end
  140. for j = 1, ind_end-1 do
  141. local i = 1+ind_end-1-j
  142. local c = string.sub(template, i, i)
  143. if c ~= ' ' and c ~= '\t' then
  144. ind_start = i
  145. break
  146. end
  147. end
  148. indent = string.sub(template, ind_start+1, ind_end-1)
  149. local what_idl = what:gsub("funcs_dynamic", "funcs"):gsub("funcs_static", "funcs")
  150. if (what == "version") then
  151. return gen_version()
  152. end
  153. for _, object in ipairs(idl[what_idl]) do
  154. local co = coroutine.create(converter[what])
  155. local any
  156. while true do
  157. local ok, v = coroutine.resume(co, object)
  158. assert(ok, debug.traceback(co, v))
  159. if not v then
  160. break
  161. end
  162. table.insert(tmp, v)
  163. any = true
  164. end
  165. if any and tmp[#tmp] ~= "" then
  166. table.insert(tmp, "")
  167. end
  168. end
  169. return table.concat(tmp, "\n" .. indent)
  170. end)
  171. return r
  172. end
  173. function gen.gen_types()
  174. return gen.gen(d_types_template)
  175. end
  176. function gen.gen_funcs()
  177. return gen.gen(d_funcs_template)
  178. end
  179. function converter.types(typ)
  180. if typ.comments ~= nil then
  181. if #typ.comments == 1 then
  182. yield("/// " .. typ.comments[1])
  183. else
  184. yield("/**")
  185. for _, comment in ipairs(typ.comments) do
  186. yield(" * " .. comment)
  187. end
  188. yield(" */")
  189. end
  190. end
  191. if typ.handle then
  192. yield("struct " .. typ.cname .. " { ushort idx; }")
  193. elseif typ.enum then
  194. local prefix = "BGFX_" .. to_underscorecase(string.gsub(typ.name, "::Enum", "")):upper()
  195. yield("enum " .. typ.cname)
  196. yield("{")
  197. for idx, enum in ipairs(typ.enum) do
  198. local comments = ""
  199. if enum.comment ~= nil then
  200. if #enum.comment == 1 then
  201. comments = " /// " .. enum.comment[1];
  202. else
  203. yield("\t/**")
  204. for _, comment in ipairs(enum.comment) do
  205. yield("\t * " .. comment)
  206. end
  207. yield("\t */")
  208. end
  209. end
  210. local enumname
  211. if enum.underscore then
  212. enumname = to_underscorecase(enum.name):upper()
  213. else
  214. enumname = enum.name:upper()
  215. end
  216. yield("\t" .. prefix .. "_" .. enumname .. "," .. comments)
  217. end
  218. yield("");
  219. --yield("\t" .. prefix .. "_COUNT = " .. #typ.enum)
  220. yield("\t" .. prefix .. "_COUNT")
  221. yield("}")
  222. yield("mixin(expandEnum!" .. typ.cname .. ");")
  223. elseif typ.bits ~= nil then
  224. local prefix = "BGFX_" .. to_underscorecase(typ.name):upper()
  225. local enumType = "uint"
  226. format = "%u"
  227. if typ.bits == 64 then
  228. format = "0x%016x"
  229. enumType = "ulong"
  230. elseif typ.bits == 32 then
  231. format = "0x%08x"
  232. enumType = "uint"
  233. elseif typ.bits == 16 then
  234. format = "0x%04x"
  235. enumType = "ushort"
  236. elseif typ.bits == 8 then
  237. format = "0x%02x"
  238. enumType = "ubyte"
  239. end
  240. for idx, flag in ipairs(typ.flag) do
  241. local value = flag.value
  242. if value ~= nil then
  243. value = string.format(flag.format or format, value)
  244. else
  245. for _, name in ipairs(flag) do
  246. local fixedname = prefix .. "_" .. to_underscorecase(name):upper()
  247. if value ~= nil then
  248. value = value .. " | " .. fixedname
  249. else
  250. value = fixedname
  251. end
  252. end
  253. end
  254. local comments = ""
  255. if flag.comment ~= nil then
  256. if #flag.comment == 1 then
  257. comments = " /// " .. flag.comment[1]
  258. else
  259. yield("/**")
  260. for _, comment in ipairs(flag.comment) do
  261. yield(" * " .. comment)
  262. end
  263. yield(" */")
  264. end
  265. end
  266. yield("enum " .. enumType .. " " .. prefix .. "_" .. to_underscorecase(flag.name):upper() .. " = " .. value .. ";" .. comments)
  267. end
  268. if typ.shift then
  269. local name = prefix .. "_SHIFT"
  270. local value = typ.shift
  271. local comments = ""
  272. if typ.desc then
  273. comments = string.format(" /// %s bit shift", typ.desc)
  274. end
  275. yield("enum " .. enumType .. " " .. name .. " = " .. value .. ";" .. comments)
  276. end
  277. if typ.range then
  278. local name = prefix .. "_MASK"
  279. local value = string.format(format, typ.mask)
  280. local comments = ""
  281. if typ.desc then
  282. comments = string.format(" /// %s bit mask", typ.desc)
  283. end
  284. yield("enum " .. enumType .. " " .. name .. " = " .. value .. ";" .. comments)
  285. end
  286. if typ.helper then
  287. yield(string.format(
  288. "%s %s (%s v) { return (v << %s) & %s; }",
  289. enumType,
  290. prefix,
  291. enumType,
  292. (prefix .. "_SHIFT"),
  293. (prefix .. "_MASK")))
  294. end
  295. elseif typ.struct ~= nil then
  296. yield("struct " .. typ.cname)
  297. yield("{")
  298. for _, member in ipairs(typ.struct) do
  299. local comments = ""
  300. if member.comment ~= nil then
  301. if #member.comment == 1 then
  302. comments = " /// " .. member.comment[1]
  303. else
  304. yield("\n\t/**")
  305. for _, comment in ipairs(member.comment) do
  306. yield("\t * " .. comment)
  307. end
  308. yield("\t */")
  309. end
  310. end
  311. yield("\t" .. convert_struct_member(member) .. ";" .. comments)
  312. end
  313. yield("}")
  314. end
  315. end
  316. function converter.funcs_static(func)
  317. return converter.funcs(func, true)
  318. end
  319. function converter.funcs_dynamic(func)
  320. return converter.funcs(func, false)
  321. end
  322. function converter.funcs(func, static)
  323. if func.cpponly then
  324. return
  325. end
  326. if func.comments ~= nil then
  327. yield("/**")
  328. for _, line in ipairs(func.comments) do
  329. local line = line:gsub("@remarks", "Remarks:")
  330. line = line:gsub("@remark", "Remarks:")
  331. line = line:gsub("@(%l)(%l+)", function(a, b) return a:upper()..b..":" end)
  332. yield(" * " .. line)
  333. end
  334. local hasParamsComments = false
  335. for _, arg in ipairs(func.args) do
  336. if arg.comment ~= nil then
  337. hasParamsComments = true
  338. break
  339. end
  340. end
  341. if hasParamsComments then
  342. yield(" * Params:")
  343. end
  344. for _, arg in ipairs(func.args) do
  345. if arg.comment ~= nil then
  346. yield(" * " .. convert_name(arg.name) .. " = " .. arg.comment[1])
  347. for i, comment in ipairs(arg.comment) do
  348. if (i > 1) then
  349. yield(" * " .. comment)
  350. end
  351. end
  352. end
  353. end
  354. yield(" */")
  355. end
  356. local args = {}
  357. if func.this ~= nil then
  358. args[1] = convert_type(func.this_type) .. " _this"
  359. end
  360. for _, arg in ipairs(func.args) do
  361. table.insert(args, convert_type(arg) .. " " .. convert_name(arg.name))
  362. end
  363. if static then
  364. yield(convert_ret_type(func.ret) .. " bgfx_" .. func.cname .. "(" .. table.concat(args, ", ") .. ");")
  365. else
  366. yield("alias da_bgfx_" .. func.cname .. " = " .. convert_ret_type(func.ret) .. " function(" .. table.concat(args, ", ") .. ");")
  367. yield("da_bgfx_" .. func.cname .. " bgfx_" .. func.cname .. ";")
  368. end
  369. end
  370. -- printtable("idl types", idl.types)
  371. -- printtable("idl funcs", idl.funcs)
  372. function gen.write(codes, outputfile)
  373. local out = assert(io.open(outputfile, "wb"))
  374. out:write(codes)
  375. out:close()
  376. print("Generating: " .. outputfile)
  377. end
  378. if (...) == nil then
  379. -- run `lua bindings-d.lua` in command line
  380. print(gen.gen_types())
  381. print(gen.gen_funcs())
  382. end
  383. return gen