Files
bgfx/scripts/docs-rst.lua
2026-02-28 22:29:20 +00:00

255 lines
6.4 KiB
Lua

local codegen = require "codegen"
local gen = {}
local function to_underscorecase(name)
local tmp = {}
for v in name:gmatch "[_%u][%l%d]*" do
if v:byte() == 95 then -- '_'
v = v:sub(2)
end
tmp[#tmp+1] = v
end
return table.concat(tmp, "_")
end
function gen.gen()
local idl = codegen.idl()
-- Count C++ name occurrences for overload detection
-- Only count non-conly, non-class functions (free functions)
local cpp_name_count = {}
for _, f in ipairs(idl.funcs) do
if not f.conly and not f.class then
cpp_name_count[f.name] = (cpp_name_count[f.name] or 0) + 1
end
end
-- Collect section items by section id from declarations
local section_items = {}
for _, t in ipairs(idl.types) do
if t.section then
if not section_items[t.section] then
section_items[t.section] = {}
end
local kind
if t.flag then
kind = "flag"
elseif t.struct or t.enum then
kind = "struct"
end
if kind then
table.insert(section_items[t.section], {
kind = kind,
item = t,
order = t._order or 0,
})
end
end
end
for _, f in ipairs(idl.funcs) do
if f.section and not f.conly and not f.class then
if not section_items[f.section] then
section_items[f.section] = {}
end
table.insert(section_items[f.section], {
kind = "func",
item = f,
order = f._order or 0,
})
end
end
for _, items in pairs(section_items) do
table.sort(items, function(a, b) return a.order < b.order end)
end
-- Build C++ function signature
local function build_signature(f)
local parts = {}
for _, arg in ipairs(f.args) do
local s = arg.fulltype .. " " .. arg.name
if arg.array then
s = s .. arg.array
end
if arg.default then
s = s .. " = " .. arg.default
end
parts[#parts+1] = s
end
return table.concat(parts, ", ")
end
-- Get BGFX_ define name for a flag item
local function get_define_name(flag_type, flag_item)
local prefix = "BGFX_" .. (flag_type.cname or to_underscorecase(flag_type.name):upper())
local suffix
if flag_item.cname then
suffix = flag_item.cname
else
suffix = to_underscorecase(flag_item.name):upper()
end
return prefix .. "_" .. suffix
end
-- Flag label mapping for "State Flags" section
local state_flag_labels = {
StateWrite = "Write",
StateDepthTest = "Depth Test",
StateBlend = "Blend Mode",
StateBlendEquation = "Blend Equation",
StateCull = "Primitive Culling",
StatePt = "Primitive Type",
State = "Misc",
}
local underlines = {
[1] = "-",
[2] = "~",
[3] = "*",
[4] = '"',
}
local r = {}
local function emit(s)
r[#r+1] = s or ""
end
-- Title
emit("API Reference")
emit("=============")
emit()
emit()
emit(".. note::")
emit()
emit(" If you're just getting started with bgfx, you might get more out of these simple walkthroughs for how to use bgfx's API:")
emit()
emit(" - `Hello, bgfx! (tutorial) <https://dev.to/pperon/hello-bgfx-4dka>`_")
emit(" - `bgfx-minimal-example (repo on GitHub) <https://github.com/jpcy/bgfx-minimal-example#bgfx-minimal-example>`_")
emit(" - `Using the bgfx library with C++ on Ubuntu (tutorial) <https://www.sandeepnambiar.com/getting-started-with-bgfx/>`_")
emit(" - `Getting started with BGFX (playlist on Youtube) <https://www.youtube.com/playlist?list=PLwFtWV3PS6y_oTOfHjbE0Zk8N9_QuQlHy>`_")
emit(" - `Getting started with BGFX (repo on GitHub) <https://github.com/gamecoder-nz/Getting-Started-With-BGFX>`_")
-- Determine leaf sections and build parent paths for item lookup.
-- A leaf section is one not immediately followed by a deeper-level section.
-- The path is "parent_title/title" (used to disambiguate duplicate titles).
local parent_at_level = {}
for i, sec in ipairs(idl.sections) do
parent_at_level[sec.level] = sec.title
local parent = parent_at_level[sec.level - 1]
sec._path = parent and (parent .. "/" .. sec.title) or sec.title
sec._is_leaf = true
if i > 1 then
local prev = idl.sections[i - 1]
if prev.level < sec.level then
prev._is_leaf = false
end
end
end
for _, sec in ipairs(idl.sections) do
emit()
-- Section header
emit(sec.title)
emit(string.rep(underlines[sec.level], #sec.title))
-- Description (skip first line if it matches the section title)
if sec.desc then
local start_idx = 1
if sec.desc[1] == sec.title then
start_idx = 2
end
-- Skip leading empty lines
while start_idx <= #sec.desc and sec.desc[start_idx] == "" do
start_idx = start_idx + 1
end
if start_idx <= #sec.desc then
emit()
local in_note = false
for i = start_idx, #sec.desc do
local line = sec.desc[i]
local remarks_text = line:match "^@remarks%s+(.*)"
if remarks_text then
emit(".. note::")
emit()
emit(" " .. remarks_text)
in_note = true
elseif in_note then
if line == "" then
emit()
else
emit(" " .. line)
end
else
emit(line)
end
end
end
end
-- Items (only for leaf sections)
if sec._is_leaf then
local items = section_items[sec._path] or section_items[sec.title] or {}
local is_state_flags = (sec.title == "State Flags")
local prev_kind = nil
for _, entry in ipairs(items) do
if entry.kind == "func" then
local f = entry.item
local count = cpp_name_count[f.name] or 0
if prev_kind ~= "func" then
emit()
end
if count > 1 then
emit(".. doxygenfunction:: bgfx::" .. f.name .. "(" .. build_signature(f) .. ")")
else
emit(".. doxygenfunction:: bgfx::" .. f.name)
end
prev_kind = "func"
elseif entry.kind == "struct" then
local t = entry.item
emit()
emit(".. doxygenstruct:: bgfx::" .. (t.typename or t.name))
emit(" :members:")
prev_kind = "struct"
elseif entry.kind == "flag" then
local t = entry.item
emit()
if is_state_flags then
local label = state_flag_labels[t.name]
if label then
emit("**" .. label .. "**")
emit()
end
end
for _, fitem in ipairs(t.flag) do
emit(".. doxygendefine:: " .. get_define_name(t, fitem))
end
prev_kind = "flag"
end
end
end
end
emit()
return table.concat(r, "\n") .. "\n"
end
function gen.write(codes, outputfile)
local out = assert(io.open(outputfile, "wb"))
out:write(codes)
out:close()
print("Generating: " .. outputfile)
end
if (...) == nil then
-- run `lua docs-rst.lua` in command line
print(gen.gen())
end
return gen