bindings-d.lua 24 KB

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