bindings-d.lua 24 KB

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