2
0

bindings-d.lua 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936
  1. local codegen = require "codegen"
  2. local idl = codegen.idl "bgfx.idl"
  3. local template = [[
  4. /+
  5. + ┌==============================┐
  6. + │ AUTO GENERATED! DO NOT EDIT! │
  7. + └==============================┘
  8. +/
  9. module bgfx;
  10. import bindbc.common.types: c_int64, c_uint64, va_list;
  11. import bindbc.bgfx.config;
  12. static import bgfx.impl;
  13. $version
  14. alias ViewID = ushort;
  15. enum invalidHandle(T) = T(ushort.max);
  16. alias ReleaseFn = extern(C++) void function(void* ptr, void* userData) nothrow;
  17. $types
  18. pragma(inline,true) nothrow @nogc{
  19. /**
  20. Allocate a buffer to pass to bgfx. Data will be freed inside bgfx.
  21. Params:
  22. size = Size to allocate.
  23. */
  24. MemoryRef alloc(uint size){
  25. auto mem = bgfx.impl.alloc(__traits(parameters));
  26. return MemoryRef(cast(ubyte[])mem.data[0..mem.size], mem);
  27. }
  28. /**
  29. Allocate a buffer to pass to bgfx and copy `data` into it. Data will be freed inside bgfx.
  30. Params:
  31. data = Pointer to data to be copied.
  32. size = Size of data to be copied.
  33. */
  34. MemoryRef copy(const(void)* data, uint size){
  35. auto mem = bgfx.impl.copy(__traits(parameters));
  36. return MemoryRef(cast(ubyte[])mem.data[0..mem.size], mem);
  37. }
  38. pure @safe:
  39. StateBlend_ blendFuncSeparate(StateBlend_ srcRGB, StateBlend_ dstRGB, StateBlend_ srcA, StateBlend_ dstA){
  40. return (srcRGB | ((dstRGB) << 4)) | ((srcA | (dstA << 4)) << 8);
  41. }
  42. ///Blend equation separate.
  43. StateBlendEquation_ blendEquationSeparate(StateBlendEquation_ equationRGB, StateBlendEquation_ equationA){
  44. return equationRGB | (equationA << 3);
  45. }
  46. ///Blend function.
  47. StateBlend_ blendFunc(StateBlend_ src, StateBlend_ dst){ return blendFuncSeparate(src, dst, src, dst); }
  48. ///Blend equation.
  49. StateBlendEquation_ blendEquation(StateBlendEquation_ equation){ return blendEquationSeparate(equation, equation); }
  50. ///Utility predefined blend modes.
  51. enum StateBlendFunc: StateBlend_{
  52. ///Additive blending.
  53. add = blendFunc(StateBlend.one, StateBlend.one),
  54. ///Alpha blend.
  55. alpha = blendFunc(StateBlend.srcAlpha, StateBlend.invSrcAlpha),
  56. ///Selects darker color of blend.
  57. darken = blendFunc(StateBlend.one, StateBlend.one) | blendEquation(StateBlendEquation.min),
  58. ///Selects lighter color of blend.
  59. lighten = blendFunc(StateBlend.one, StateBlend.one) | blendEquation(StateBlendEquation.max),
  60. ///Multiplies colors.
  61. multiply = blendFunc(StateBlend.dstColor, StateBlend.zero),
  62. ///Opaque pixels will cover the pixels directly below them without any math or algorithm applied to them.
  63. normal = blendFunc(StateBlend.one, StateBlend.invSrcAlpha),
  64. ///Multiplies the inverse of the blend and base colors.
  65. screen = blendFunc(StateBlend.one, StateBlend.invSrcColor),
  66. ///Decreases the brightness of the base color based on the value of the blend color.
  67. linearBurn = blendFunc(StateBlend.dstColor, StateBlend.invDstColor) | blendEquation(StateBlendEquation.sub),
  68. }
  69. StateBlend_ blendFuncRTx(StateBlend_ src, StateBlend_ dst){
  70. return cast(uint)(src >> StateBlend.shift) | (cast(uint)(dst >> StateBlend.shift) << 4);
  71. }
  72. StateBlend_ blendFuncRTxE(StateBlend_ src, StateBlend_ dst, StateBlendEquation_ equation){
  73. return blendFuncRTx(src, dst) | (cast(uint)(equation >> StateBlendEquation.shift) << 8);
  74. }
  75. StateBlend_ blendFuncRT1(StateBlend_ src, StateBlend_ dst){ return blendFuncRTx(src, dst) << 0; }
  76. StateBlend_ blendFuncRT2(StateBlend_ src, StateBlend_ dst){ return blendFuncRTx(src, dst) << 11; }
  77. StateBlend_ blendFuncRT3(StateBlend_ src, StateBlend_ dst){ return blendFuncRTx(src, dst) << 22; }
  78. StateBlend_ blendFuncRT1E(StateBlend_ src, StateBlend_ dst, StateBlendEquation_ equation){
  79. return blendFuncRTxE(src, dst, equation) << 0;
  80. }
  81. StateBlend_ blendFuncRT2E(StateBlend_ src, StateBlend_ dst, StateBlendEquation_ equation){
  82. return blendFuncRTxE(src, dst, equation) << 11;
  83. }
  84. StateBlend_ blendFuncRT3E(StateBlend_ src, StateBlend_ dst, StateBlendEquation_ equation){
  85. return blendFuncRTxE(src, dst, equation) << 22;
  86. }
  87. }
  88. /**
  89. A wrapper around `Memory` that allows you to mutate its `data`.
  90. Do not create instances of this struct yourself.
  91. */
  92. struct MemoryRef{
  93. ubyte[] data;
  94. const(Memory)* memory;
  95. alias memory this;
  96. }
  97. $structs
  98. mixin(joinFnBinds((){
  99. FnBind[] ret = [
  100. $funcs
  101. ];
  102. return ret;
  103. }(), $membersWithFns));
  104. static if(!staticBinding):
  105. import bindbc.loader;
  106. debug{
  107. mixin(makeDynloadFns("Bgfx", makeLibPaths(["bgfx-shared-libDebug", "bgfxDebug", "bgfx"]), [__MODULE__, "bgfx.impl"]));
  108. }else{
  109. mixin(makeDynloadFns("Bgfx", makeLibPaths(["bgfx-shared-libRelease", "bgfxRelease", "bgfx"]), [__MODULE__, "bgfx.impl"]));
  110. }
  111. ]]
  112. 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"}
  113. local function contains(table, val)
  114. for i=1,#table do
  115. if table[i] == val then
  116. return true
  117. end
  118. end
  119. return false
  120. end
  121. local function hasPrefix(str, prefix)
  122. return prefix == "" or str:sub(1, #prefix) == prefix
  123. end
  124. local function hasSuffix(str, suffix)
  125. return suffix == "" or str:sub(-#suffix) == suffix
  126. end
  127. local enumTypes = {}
  128. local membersWithFns = ""
  129. local capsWords = {"Mip", "Id", "Rw", "Vb", "Ib", "Cb", "Rt", "Pci", "Srgb", "Pt", "Ccw", "2d", "3d", "Msaa"}
  130. local capsRepl = {
  131. hidpi = "hiDPI", lineaa = "lineAA", maxanisotropy = "maxAnisotropy",
  132. notequal = "notEqual", gequal = "gEqual", Lequal = "LEqual", lequal = "lEqual",
  133. decrsat = "decrSat", incrsat = "incrSat", revsub = "revSub",
  134. linestrip = "lineStrip", tristrip = "triStrip",
  135. bstencil = "bStencil", fstencil = "fStencil",
  136. Rmask = "RMask",
  137. }
  138. local function abbrevsToUpper(name)
  139. if name:len() >= 3 then
  140. for _, abbrev in pairs(capsWords) do
  141. name = name:gsub(abbrev, function(s0)
  142. return s0:upper()
  143. end)
  144. end
  145. for from, to in pairs(capsRepl) do
  146. name = name:gsub(from, to)
  147. end
  148. end
  149. return name
  150. end
  151. local function toCamelCase(name)
  152. if name:len() >= 3 then
  153. name = name:sub(0, 1) .. name:sub(2, -2):gsub("_", "") .. name:sub(-1)
  154. end
  155. if name:find("%u%u+%l") then
  156. name = name:gsub("(%u-)(%u%l)", function(s0, s1)
  157. return s0:lower() .. s1
  158. end)
  159. else
  160. name = (name:gsub("^([^%l]*)(%l?)", function(s0, s1)
  161. if s1 ~= nil then
  162. return s0:lower() .. s1
  163. end
  164. return s0:lower()
  165. end))
  166. end
  167. return abbrevsToUpper(name)
  168. end
  169. -- local function toPascalCase(name)
  170. -- return (name:gsub("^%l", string.upper))
  171. -- end
  172. local usEnSubs = {
  173. color = "colour", Color = "Colour",
  174. rasterize = "rasterise", Rasterize = "Rasterise",
  175. initialize = "initialise", Initialize = "Initialise",
  176. normalize = "normalise", Normalize = "Normalise",
  177. normalized = "normalised", Normalized = "Normalised",
  178. ccw = "acw", CCW = "ACW",
  179. }
  180. local function toIntlEn(name)
  181. local change = false
  182. for us, intl in pairs(usEnSubs) do
  183. if name:find(us) then
  184. name = (name:gsub(us, intl))
  185. change = true
  186. end
  187. end
  188. if change then
  189. return name
  190. else
  191. return nil
  192. end
  193. end
  194. -- Unconditionally convert
  195. local function toIntlEnUncond(name)
  196. local newName = toIntlEn(name)
  197. if newName ~= nil then
  198. return newName
  199. end
  200. return name
  201. end
  202. local function hexStr(val, bits)
  203. local digits = bits / 4
  204. local str = string.format(string.format("%%0%iX", digits), val)
  205. local i = 4
  206. while i < str:len() do
  207. str = str:sub(0, i) .. "_" .. str:sub(i+1)
  208. i = i + 5
  209. end
  210. return "0x" .. str
  211. end
  212. local function convArray(array)
  213. if string.find(array, "::") then
  214. return string.gsub(array, "::.*", ".") .. toCamelCase(string.gsub(array, ".-::", ""))
  215. else
  216. return array
  217. end
  218. end
  219. local typeSubs = {
  220. {"uint32_t", "uint"}, {"int32_t", "int"},
  221. {"uint16_t", "ushort"}, {"int16_t", "short"},
  222. {"uint64_t", "c_uint64"}, {"int64_t", "c_int64"},
  223. {"uint8_t", "ubyte"}, {"int8_t", "byte"},
  224. {"uintptr_t", "size_t"}
  225. }
  226. local function convSomeType(arg, isFnArg)
  227. local type = arg.fulltype
  228. if type == "bx::AllocatorI*" or type == "CallbackI*" then
  229. type = "void*"
  230. else
  231. for _, item in ipairs(typeSubs) do
  232. if type:find(item[1]) then
  233. type = type:gsub(item[1], item[2])
  234. break
  235. end
  236. end
  237. type = type:gsub("::Enum", "") --fix enums
  238. type = type:gsub("%s+%*", "*") --remove spacing before `*`
  239. if isFnArg then
  240. for _, enum in pairs(enumTypes) do --fix C++ linkage errors
  241. if type == enum then
  242. type = string.format("bgfx.impl.%s.Enum", enum)
  243. else
  244. type = (type:gsub("(" .. enum .. ")([^A-Za-z0-9_])", function(s0, s1)
  245. return string.format("bgfx.impl.%s.Enum", enum) .. s1
  246. end))
  247. end
  248. end
  249. type = type:gsub("([^&]-)%s?&", "ref %1") --change `&` suffix to `ref` prefix
  250. if arg.array ~= nil then
  251. type = type .. "*" --append *
  252. end
  253. else
  254. type = type:gsub("([^&]-)%s?&", "%1*") --change `&` to `*`
  255. if arg.array ~= nil then
  256. type = type .. convArray(arg.array) --append [n]
  257. end
  258. end
  259. type = type:gsub("const%s+([A-Za-z_][A-Za-z0-9_]*)%s*%*", "const(%1)*") --change `const x*` to `const(x)*`
  260. type = abbrevsToUpper(type)
  261. end
  262. return type
  263. end
  264. local function convType(arg)
  265. return convSomeType(arg, false)
  266. end
  267. local function convFnArgType(arg)
  268. return convSomeType(arg, true)
  269. end
  270. local valSubs = {
  271. NULL = "null",
  272. UINT8_MAX = "ubyte.max",
  273. UINT16_MAX = "ushort.max",
  274. UINT32_MAX = "uint.max",
  275. BGFX_INVALID_HANDLE = "invalidHandle",
  276. BGFX_DISCARD_ALL = "Discard.all",
  277. BGFX_BUFFER_NONE = "Buffer.none",
  278. BGFX_STENCIL_NONE = "Stencil.none",
  279. BGFX_TEXTURE_NONE = "Texture.none",
  280. BGFX_SAMPLER_NONE = "Sampler.none",
  281. BGFX_RESET_NONE = "Reset.none",
  282. BGFX_SAMPLER_U_CLAMP = "SamplerU.clamp",
  283. BGFX_SAMPLER_V_CLAMP = "SamplerV.clamp",
  284. BGFX_RESOLVE_AUTO_GEN_MIPS = "Resolve.autoGenMIPs",
  285. ["ViewMode::Default"] = "ViewMode.default_",
  286. }
  287. local function convVal(arg, type)
  288. local val = string.format("%s", arg)
  289. for from, to in pairs(valSubs) do
  290. if val:find(from) then
  291. if from == "BGFX_INVALID_HANDLE" then
  292. val = val:gsub(from, to .. "!" .. type)
  293. else
  294. val = val:gsub(from, to)
  295. end
  296. end
  297. end
  298. if val:find("INT32_MAX") then
  299. val = val:gsub("INT32_MAX", "int.max")
  300. end
  301. val = convArray(val)
  302. return val
  303. end
  304. local function convStructType(arg)
  305. return convType(arg)
  306. end
  307. local function convName(name)
  308. name = abbrevsToUpper(name)
  309. if contains(dKeywords, name) then
  310. return name .. "_"
  311. end
  312. return name
  313. end
  314. local function convStructMember(member)
  315. return convStructType(member) .. " " .. convName(member.name)
  316. end
  317. local allStructs = {}
  318. local function genVersion()
  319. return "enum uint apiVersion = " .. (idl._version or 0) .. ";"
  320. end
  321. local function genStructMemberFn(func) --NOTE: this does not work on nested structs
  322. if func.class ~= nil and func.conly == nil and func.cppinline == nil then
  323. local st = allStructs[func.class]
  324. local attribs = ""
  325. if func.comments ~= nil then
  326. if #st.fns > 0 then
  327. table.insert(st.fns, "")
  328. end
  329. table.insert(st.fns, "/**")
  330. for _, line in ipairs(func.comments) do
  331. local line = line:gsub("@remarks", "Remarks:")
  332. line = line:gsub("@remark", "Remarks:")
  333. line = line:gsub("@(%l)(%l+)", function(a, b) return a:upper() .. b .. ":" end)
  334. table.insert(st.fns, line)
  335. end
  336. local hasParamsComments = false
  337. for _, arg in ipairs(func.args) do
  338. if arg.comment ~= nil then
  339. hasParamsComments = true
  340. break
  341. end
  342. end
  343. if hasParamsComments then
  344. table.insert(st.fns, "Params:")
  345. end
  346. for _, arg in ipairs(func.args) do
  347. if arg.comment ~= nil then
  348. table.insert(st.fns, "\t" .. toIntlEnUncond(convName(arg.name:sub(2))) .. " = " .. arg.comment[1])
  349. for i, comment in ipairs(arg.comment) do
  350. if i > 1 then
  351. table.insert(st.fns, comment)
  352. end
  353. end
  354. end
  355. end
  356. table.insert(st.fns, "*/")
  357. end
  358. local args = {}
  359. for _, arg in ipairs(func.args) do
  360. local def = ""
  361. if arg.default ~= nil then
  362. def = string.format("=%s", convVal(arg.default, convFnArgType(arg)))
  363. end
  364. if arg.fulltype == "..." then
  365. table.insert(args, "..." .. def)
  366. else
  367. table.insert(args, convFnArgType(arg) .. " " .. toIntlEnUncond(convName(arg.name:sub(2))) .. def)
  368. end
  369. end
  370. if func.const ~= nil then
  371. attribs = "const"
  372. end
  373. if attribs ~= "" then
  374. attribs = ", memAttr: q{" .. attribs .. "}"
  375. end
  376. table.insert(st.fns, string.format("{q{%s}, q{%s}, q{%s}, ext: `C++`%s},", convType(func.ret), func.name, table.concat(args, ", "), attribs))
  377. end
  378. end
  379. local converter = {}
  380. local yield = coroutine.yield
  381. local gen = {}
  382. gen.implFile = [[
  383. /+
  384. + ┌==============================┐
  385. + │ AUTO GENERATED! DO NOT EDIT! │
  386. + └==============================┘
  387. +/
  388. ///Do NOT import this module! Use the symbols with the same names in `bgfx/package.d` instead.
  389. module bgfx.impl;
  390. import bindbc.bgfx.config;
  391. import bgfx;
  392. package:
  393. mixin(joinFnBinds((){
  394. FnBind[] ret = [
  395. {q{const(Memory)*}, q{alloc}, q{uint size}, ext: `C++, "bgfx"`},
  396. {q{const(Memory)*}, q{copy}, q{const(void)* data, uint size}, ext: `C++, "bgfx"`},
  397. ];
  398. return ret;
  399. }()));
  400. ]]
  401. function gen.gen()
  402. local indent = ""
  403. local idx = 1;
  404. local r = template:gsub("$([a-zA-Z_]+)", function(what)
  405. local tmp = {}
  406. local ind_end = template:find("$"..what, idx, true)
  407. local ind_start = ind_end
  408. for j = 1, ind_end-1 do
  409. local i = 1+ind_end-1-j
  410. local c = string.sub(template, i, i)
  411. if c ~= ' ' and c ~= '\t' then
  412. ind_start = i
  413. break
  414. end
  415. end
  416. indent = string.sub(template, ind_start+1, ind_end-1)
  417. if what == "version" then
  418. return genVersion()
  419. elseif what == "structs" then
  420. for _, fn in ipairs(idl.funcs) do
  421. genStructMemberFn(fn)
  422. end
  423. for _, object in ipairs(idl["types"]) do
  424. if object.struct ~= nil and object.namespace == nil then
  425. local co = coroutine.create(converter[what])
  426. local any
  427. while true do
  428. local ok, v = coroutine.resume(co, allStructs[object.name], object.name, object.name, true, indent:len())
  429. assert(ok, debug.traceback(co, v))
  430. if not v then
  431. break
  432. end
  433. table.insert(tmp, v)
  434. any = true
  435. end
  436. if any and tmp[#tmp] ~= "" then
  437. table.insert(tmp, "")
  438. end
  439. end
  440. end
  441. elseif what == "membersWithFns" then
  442. table.insert(tmp, "\"" .. membersWithFns .. "\"")
  443. else
  444. for _, object in ipairs(idl[what]) do
  445. local co = coroutine.create(converter[what])
  446. local any
  447. while true do
  448. local ok, v = coroutine.resume(co, object)
  449. assert(ok, debug.traceback(co, v))
  450. if not v then
  451. break
  452. end
  453. table.insert(tmp, v)
  454. any = true
  455. end
  456. if any and tmp[#tmp] ~= "" then
  457. table.insert(tmp, "")
  458. end
  459. end
  460. end
  461. return table.concat(tmp, "\n" .. indent)
  462. end)
  463. return r
  464. end
  465. function converter.structs(st, name, fullyQualifiedName, topLvl)
  466. for _, line in ipairs(st.comments) do
  467. yield(line)
  468. end
  469. if topLvl then
  470. yield("extern(C++, \"bgfx\") struct " .. name .. "{")
  471. else
  472. yield("extern(C++) struct " .. name .. "{")
  473. end
  474. local subN = 0
  475. for _, subStruct in ipairs(st.subs) do
  476. subN = subN + 1
  477. local co = coroutine.create(converter.structs)
  478. while true do
  479. local ok, v = coroutine.resume(co, subStruct, subStruct.name, name .. "." .. subStruct.name, false)
  480. assert(ok, debug.traceback(co, v))
  481. if not v then
  482. break
  483. end
  484. yield("\t" .. v)
  485. end
  486. end
  487. if subN > 0 then
  488. yield("\t")
  489. end
  490. for _, line in ipairs(st.fields) do
  491. yield(line)
  492. end
  493. if #st.fns > 0 then
  494. membersWithFns = membersWithFns .. fullyQualifiedName .. ", "
  495. yield("\textern(D) mixin(joinFnBinds((){")
  496. yield("\t\tFnBind[] ret = [")
  497. for _, line in ipairs(st.fns) do
  498. yield("\t\t\t" .. line)
  499. end
  500. yield("\t\t];")
  501. yield("\t\treturn ret;")
  502. yield("\t}()));")
  503. end
  504. yield("}")
  505. end
  506. function converter.types(typ)
  507. if typ.comments ~= nil and not typ.struct then
  508. if #typ.comments == 1 then
  509. yield("///" .. typ.comments[1])
  510. else
  511. yield("/**")
  512. for _, comment in ipairs(typ.comments) do
  513. yield(comment)
  514. end
  515. yield("*/")
  516. end
  517. end
  518. if typ.handle then ---hnadle
  519. yield("extern(C++, \"bgfx\") struct " .. typ.name .. "{")
  520. yield("\tushort idx;")
  521. yield("}")
  522. --yield(typ.name .. " invalidHandle(){ return " .. typ.name .. "(ushort.max); }")
  523. -- For some reason, this has never worked, so I'm commenting it out just in case it does start working suddenly. :P
  524. --[[
  525. elseif typ.funcptr then
  526. local args = {}
  527. for _, arg in ipairs(typ.args) do
  528. if arg.fulltype == "..." then
  529. table.insert(args, "..." .. def)
  530. else
  531. table.insert(args, convFnArgType(arg) .. " " .. convName(arg.name:sub(2)) .. def)
  532. end
  533. end
  534. yield(string.format("alias %s = extern(C++) %s function(%s);", typ.name, convType(typ.ret), table.concat(args, ", ")))
  535. --]]
  536. elseif typ.enum then
  537. local typeName = abbrevsToUpper(typ.name:gsub("::Enum", ""))
  538. local otherName = string.format("bgfx.impl.%s.Enum", typ.name:gsub("::Enum", ""))
  539. yield("enum " .. typeName .. ": " .. otherName .. "{")
  540. table.insert(enumTypes, typeName)
  541. local vals = ""
  542. for idx, enum in ipairs(typ.enum) do
  543. local comments = ""
  544. if enum.comment ~= nil then
  545. if #enum.comment == 1 then
  546. comments = " ///" .. enum.comment[1];
  547. else
  548. yield("\t/**")
  549. for _, comment in ipairs(enum.comment) do
  550. yield("\t" .. comment)
  551. end
  552. yield("\t*/")
  553. end
  554. end
  555. local name = convName(toCamelCase(enum.name))
  556. yield("\t" .. name .. " = " .. otherName .. "." .. name .. ",")
  557. vals = vals .. name .. ","
  558. local intlName = toIntlEn(enum.name)
  559. if intlName ~= nil then
  560. yield("\t" .. convName(toCamelCase(intlName)) .. " = " .. otherName .. "." .. name .. ",")
  561. end
  562. end
  563. gen.implFile = gen.implFile .. string.format([[
  564. extern(C++, "bgfx") package final abstract class %s{
  565. enum Enum{
  566. %scount
  567. }
  568. }
  569. ]], typeName, vals)
  570. yield("\t" .. "count = " .. otherName .. ".count,")
  571. yield("}")
  572. elseif typ.bits ~= nil then
  573. local typeName = convName(typ.name)
  574. if typeName == "Caps" then
  575. typeName = "CapFlags"
  576. end
  577. local enumType = "uint"
  578. if typ.bits == 64 then
  579. enumType = "ulong"
  580. elseif typ.bits == 32 then
  581. enumType = "uint"
  582. elseif typ.bits == 16 then
  583. enumType = "ushort"
  584. elseif typ.bits == 8 then
  585. enumType = "ubyte"
  586. end
  587. local maxLen = 0
  588. if typ.shift then
  589. maxLen = string.len("shift")
  590. elseif typ.range then
  591. maxLen = string.len("mask")
  592. end
  593. for _, flag in ipairs(typ.flag) do
  594. maxLen = math.max(maxLen, flag.name:len())
  595. end
  596. yield("alias " .. typeName .. "_ = " .. enumType .. ";")
  597. yield("enum " .. typeName .. ": " .. typeName .. "_{")
  598. local function getValOr(name)
  599. local t = typeName
  600. if typeName == "State" then
  601. if hasPrefix(name, "Write") then
  602. t = t .. name:sub(1, 5)
  603. name = name:sub(6)
  604. elseif hasPrefix(name, "DepthTest") then
  605. t = t .. name:sub(1, 9)
  606. name = name:sub(10)
  607. elseif hasPrefix(name, "Cull") then
  608. t = t .. name:sub(1, 4)
  609. name = name:sub(5)
  610. end
  611. elseif typeName == "Sampler" then
  612. if hasPrefix(name, "Min") then
  613. t = t .. name:sub(1, 3)
  614. name = name:sub(4)
  615. elseif hasPrefix(name, "Mag") then
  616. t = t .. name:sub(1, 3)
  617. name = name:sub(4)
  618. elseif hasPrefix(name, "Mip") then
  619. t = t .. name:sub(1, 3)
  620. name = name:sub(4)
  621. elseif hasPrefix(name, "U") then
  622. t = t .. name:sub(1, 1)
  623. name = name:sub(2)
  624. elseif hasPrefix(name, "V") then
  625. t = t .. name:sub(1, 1)
  626. name = name:sub(2)
  627. elseif hasPrefix(name, "W") then
  628. t = t .. name:sub(1, 1)
  629. name = name:sub(2)
  630. elseif hasPrefix(name, "Compare") then
  631. t = t .. name:sub(1, 7)
  632. name = name:sub(8)
  633. end
  634. end
  635. return abbrevsToUpper(t) .. "." .. convName(toCamelCase(name))
  636. end
  637. for idx, flag in ipairs(typ.flag) do
  638. local value = flag.value
  639. if value ~= nil then
  640. value = hexStr(value, typ.bits)
  641. else
  642. for _, name in ipairs(flag) do
  643. if value ~= nil then
  644. value = value .. " | " .. getValOr(name)
  645. else
  646. value = getValOr(name)
  647. end
  648. end
  649. end
  650. local comments = ""
  651. if flag.comment ~= nil then
  652. if #flag.comment == 1 then
  653. comments = " ///" .. flag.comment[1]
  654. else
  655. yield("\t/**")
  656. for _, comment in ipairs(flag.comment) do
  657. yield("\t" .. comment)
  658. end
  659. yield("\t*/")
  660. end
  661. end
  662. local name = convName(toCamelCase(flag.name))
  663. yield("\t" .. name .. string.rep(" ", maxLen+2 - name:len()) .. "= " .. value .. "," .. comments)
  664. local intlName = toIntlEn(name)
  665. if intlName ~= nil then
  666. intlName = intlName
  667. yield("\t" .. intlName .. string.rep(" ", maxLen+2 - intlName:len()) .. "= " .. name .. ",")
  668. end
  669. end
  670. if typ.shift then
  671. local name = convName("shift")
  672. local value = typ.shift
  673. local comments = ""
  674. if typ.desc then
  675. comments = string.format(" ///%s bit shift", typ.desc)
  676. end
  677. yield("\t" .. name .. string.rep(" ", maxLen+2 - name:len()) .. "= " .. value .. "," .. comments)
  678. end
  679. if typ.range then
  680. local name = convName("mask")
  681. local value = hexStr(typ.mask, typ.bits)
  682. local comments = ""
  683. if typ.desc then
  684. comments = string.format(" ///%s bit mask", typ.desc)
  685. end
  686. yield("\t" .. name .. string.rep(" ", maxLen+2 - name:len()) .. "= " .. value .. "," .. comments)
  687. end
  688. yield("}")
  689. local intlName = toIntlEn(typeName)
  690. if intlName ~= nil then
  691. yield("alias " .. intlName .. " = " .. typeName .. ";")
  692. end
  693. if typ.helper then
  694. yield(string.format(
  695. "%s_ to%s(%s v) nothrow @nogc pure @safe{ return (v << %s) & %s; }",
  696. typeName,
  697. typeName,
  698. enumType,
  699. (typeName .. ".shift"),
  700. (typeName .. ".mask")))
  701. if intlName ~= nil then
  702. yield("alias to" .. intlName .. " = to" .. typeName .. ";")
  703. end
  704. end
  705. elseif typ.struct ~= nil then
  706. local st = {name = typ.name, comments = {}, fields = {}, fns = {}, subs = {}}
  707. if typ.comments ~= nil then
  708. if #typ.comments == 1 then
  709. table.insert(st.comments, "///" .. typ.comments[1])
  710. else
  711. table.insert(st.comments, "/**")
  712. for _, comment in ipairs(typ.comments) do
  713. table.insert(st.comments, comment)
  714. end
  715. table.insert(st.comments, "*/")
  716. end
  717. end
  718. for _, member in ipairs(typ.struct) do
  719. local comments = ""
  720. if member.comment ~= nil then
  721. if #member.comment == 1 then
  722. comments = " ///" .. member.comment[1]
  723. else
  724. if #st.fields > 0 then
  725. table.insert(st.fields, "\t")
  726. end
  727. table.insert(st.fields, "\t/**")
  728. for _, comment in ipairs(member.comment) do
  729. table.insert(st.fields, "\t" .. comment)
  730. end
  731. table.insert(st.fields, "\t*/")
  732. end
  733. end
  734. table.insert(st.fields, "\t" .. convStructMember(member) .. ";" .. comments)
  735. end
  736. if typ.ctor ~= nil and typ.name ~= "PlatformData" then
  737. table.insert(st.fns, "{q{void}, q{this}, q{}, ext: `C++`},")
  738. end
  739. if typ.namespace ~= nil then --if this is a sub-struct
  740. if allStructs[typ.namespace] ~= nil then
  741. table.insert(allStructs[typ.namespace].subs, st)
  742. else
  743. allStructs[typ.namespace] = {subs = {st}}
  744. end
  745. else --otherwise it's top-level
  746. if allStructs[typ.name] ~= nil then
  747. st.subs = allStructs[typ.name].subs
  748. end
  749. allStructs[typ.name] = st
  750. end
  751. end
  752. end
  753. function converter.funcs(func)
  754. if func.class == nil and func.conly == nil and func.cppinline == nil then
  755. local extern = "C++, \"bgfx\""
  756. local attribs = ""
  757. if (func.cfunc ~= nil and func.name ~= "init") or func.name == "alloc" or func.name == "copy" then --what the is "cfunc" even meant to mean?
  758. return
  759. end
  760. if func.comments ~= nil then
  761. yield("/**")
  762. for _, line in ipairs(func.comments) do
  763. local line = line:gsub("@remarks", "Remarks:")
  764. line = line:gsub("@remark", "Remarks:")
  765. line = line:gsub("@(%l)(%l+)", function(a, b) return a:upper() .. b .. ":" end)
  766. yield("* " .. line)
  767. end
  768. local hasParamsComments = false
  769. for _, arg in ipairs(func.args) do
  770. if arg.comment ~= nil then
  771. hasParamsComments = true
  772. break
  773. end
  774. end
  775. if hasParamsComments then
  776. yield("Params:")
  777. end
  778. for _, arg in ipairs(func.args) do
  779. if arg.comment ~= nil then
  780. yield("\t" .. toIntlEnUncond(convName(arg.name:sub(2))) .. " = " .. arg.comment[1])
  781. for i, comment in ipairs(arg.comment) do
  782. if i > 1 then
  783. yield(comment)
  784. end
  785. end
  786. end
  787. end
  788. yield("*/")
  789. end
  790. local args = {}
  791. for _, arg in ipairs(func.args) do
  792. local def = ""
  793. if arg.default ~= nil then
  794. def = string.format("=%s", convVal(arg.default, convFnArgType(arg)))
  795. end
  796. if arg.fulltype == "..." then
  797. table.insert(args, "..." .. def)
  798. else
  799. table.insert(args, convFnArgType(arg) .. " " .. toIntlEnUncond(convName(arg.name:sub(2))) .. def)
  800. end
  801. end
  802. if attribs ~= "" then
  803. attribs = ", memAttr: q{" .. attribs .. "}"
  804. end
  805. yield(string.format("{q{%s}, q{%s}, q{%s}, ext: `%s`%s},", convType(func.ret), func.name, table.concat(args, ", "), extern, attribs))
  806. end
  807. end
  808. -- printtable("idl types", idl.types)
  809. -- printtable("idl funcs", idl.funcs)
  810. function gen.write(codes, outputfile)
  811. local out = assert(io.open(outputfile, "wb"))
  812. out:write(codes)
  813. out:close()
  814. print("Generating: " .. outputfile)
  815. end
  816. if (...) == nil then
  817. -- run `lua bindings-d.lua` in command line
  818. print(gen.gen(dTemplate))
  819. end
  820. return gen