From 9443662dc168dbeaa7189c8e4a421d71c28998fa Mon Sep 17 00:00:00 2001 From: Hanchin Hsieh Date: Sun, 26 Apr 2026 15:02:46 +0800 Subject: [PATCH 1/5] render: register builtin material from material dir --- Makefile | 5 +- clibs/soluna/compile_lua.lua | 1 + src/data/settingdefault.dl | 1 - src/embedlua.c | 18 ++ src/material/matdefault.lua | 46 +++++ src/material/matmask.lua | 45 +++++ src/material/matpquad.lua | 43 +++++ src/material/matquad.lua | 42 +++++ src/material/mattext.lua | 53 ++++++ src/service/render.lua | 341 +++++++++++++---------------------- 10 files changed, 378 insertions(+), 217 deletions(-) create mode 100644 src/material/matdefault.lua create mode 100644 src/material/matmask.lua create mode 100644 src/material/matpquad.lua create mode 100644 src/material/matquad.lua create mode 100644 src/material/mattext.lua diff --git a/Makefile b/Makefile index b50c8e6..1a3514b 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ LTASK_O=$(patsubst %.c,$(BUILD)/ltask_%.o,$(LTASK_C)) LTASK_LUASRC=\ 3rd/ltask/service/root.lua\ 3rd/ltask/service/timer.lua\ - $(wildcard 3rd/ltask/lualib/*.lua src/lualib/*.lua src/service/*.lua) + $(wildcard 3rd/ltask/lualib/*.lua src/lualib/*.lua src/service/*.lua src/material/*.lua) LTASK_LUACODE=$(patsubst %.lua, $(BUILD)/%.lua.h, $(notdir $(LTASK_LUASRC))) @@ -116,6 +116,9 @@ $(BUILD)/%.lua.h : src/lualib/%.lua $(BUILD)/%.lua.h : src/service/%.lua $(COMPILE_LUA) +$(BUILD)/%.lua.h : src/material/%.lua + $(COMPILE_LUA) + $(BUILD)/%.dl.h : src/data/%.dl $(COMPILE_DATALIST) diff --git a/clibs/soluna/compile_lua.lua b/clibs/soluna/compile_lua.lua index 227f06a..ff6a780 100644 --- a/clibs/soluna/compile_lua.lua +++ b/clibs/soluna/compile_lua.lua @@ -30,6 +30,7 @@ local lua_code_src = { "3rd/ltask/lualib", "src/service", "src/lualib", + "src/material", } return function(objdeps) diff --git a/src/data/settingdefault.dl b/src/data/settingdefault.dl index 69b4903..5fb6b5d 100644 --- a/src/data/settingdefault.dl +++ b/src/data/settingdefault.dl @@ -12,4 +12,3 @@ high_dpi : false window_title : soluna background : 0x4080c0 tmpbuffer_size : 0x20000 - diff --git a/src/embedlua.c b/src/embedlua.c index de9c046..189c1cf 100644 --- a/src/embedlua.c +++ b/src/embedlua.c @@ -22,6 +22,11 @@ #include "coroutine.lua.h" #include "packageloader.lua.h" #include "audio.lua.h" +#include "matdefault.lua.h" +#include "mattext.lua.h" +#include "matquad.lua.h" +#include "matmask.lua.h" +#include "matpquad.lua.h" #include "lua.h" #include "lauxlib.h" @@ -32,6 +37,11 @@ lua_pushcclosure(L, get_string, 2); \ lua_setfield(L, -2, #name); +#define REG_MATERIAL(name) \ + lua_pushstring(L, #name); \ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); \ + REG_SOURCE(name) + #define REG_DATALIST(name) \ lua_pushlightuserdata(L, (void *)dl_##name); \ lua_pushinteger(L, sizeof(dl_##name) - 1); \ @@ -88,6 +98,14 @@ luaopen_embedsource(lua_State *L) { REG_SOURCE(audio) lua_setfield(L, -2, "service"); + lua_newtable(L); // material + REG_MATERIAL(matdefault) + REG_MATERIAL(mattext) + REG_MATERIAL(matquad) + REG_MATERIAL(matmask) + REG_MATERIAL(matpquad) + lua_setfield(L, -2, "material"); + lua_newtable(L); // data list REG_DATALIST(settingdefault) lua_setfield(L, -2, "data"); diff --git a/src/material/matdefault.lua b/src/material/matdefault.lua new file mode 100644 index 0000000..7df0876 --- /dev/null +++ b/src/material/matdefault.lua @@ -0,0 +1,46 @@ +local render = require "soluna.render" +local defmat = require "soluna.material.default" + +return function(register) + register { + name = "default", + create = function(ctx) + local state = ctx.state + local setting = ctx.settings + local inst_buffer = render.buffer { + type = "vertex", + usage = "stream", + label = "texquad-instance", + size = defmat.instance_size * setting.draw_instance, + } + local bindings = render.bindings() + bindings:vbuffer(0, inst_buffer) + bindings:view(0, state.views.storage) + bindings:sampler(0, state.default_sampler) + + state.inst = assert(inst_buffer) + state.bindings = bindings + state.material = defmat.new { + inst_buffer = state.inst, + bindings = state.bindings, + uniform = state.uniform, + sr_buffer = state.srbuffer_mem, + sprite_bank = ctx.arg.bank_ptr, + tmp_buffer = ctx.tmp_buffer, + } + + return { + reset = function() + bindings:base(0) + end, + submit = function(ptr, n) + state.material:submit(ptr, n) + end, + draw = function(ptr, n, tex) + bindings:view(1, state.views[tex + 1]) + state.material:draw(ptr, n, tex) + end, + } + end, + } +end diff --git a/src/material/matmask.lua b/src/material/matmask.lua new file mode 100644 index 0000000..b99d055 --- /dev/null +++ b/src/material/matmask.lua @@ -0,0 +1,45 @@ +local render = require "soluna.render" +local maskmat = require "soluna.material.mask" + +return function(register) + register { + name = "mask", + create = function(ctx) + local state = ctx.state + state.mask_inst = render.buffer { + type = "vertex", + usage = "stream", + label = "mask-instance", + size = maskmat.instance_size * ctx.settings.draw_instance, + } + + local mask_bindings = render.bindings() + mask_bindings:vbuffer(0, state.mask_inst) + mask_bindings:view(0, state.views.storage) + mask_bindings:sampler(0, state.default_sampler) + + state.mask_bindings = mask_bindings + state.material_mask = maskmat.new { + inst_buffer = state.mask_inst, + bindings = state.mask_bindings, + uniform = state.uniform, + sr_buffer = state.srbuffer_mem, + sprite_bank = ctx.arg.bank_ptr, + tmp_buffer = ctx.tmp_buffer, + } + + return { + reset = function() + mask_bindings:base(0) + end, + submit = function(ptr, n) + state.material_mask:submit(ptr, n) + end, + draw = function(ptr, n, tex) + mask_bindings:view(1, state.views[tex + 1]) + state.material_mask:draw(ptr, n, tex) + end, + } + end, + } +end diff --git a/src/material/matpquad.lua b/src/material/matpquad.lua new file mode 100644 index 0000000..d3f4b18 --- /dev/null +++ b/src/material/matpquad.lua @@ -0,0 +1,43 @@ +local render = require "soluna.render" +local pqmat = require "soluna.material.perspective_quad" + +return function(register) + register { + name = "perspective_quad", + create = function(ctx) + local state = ctx.state + state.perspective_quad_inst = render.buffer { + type = "vertex", + usage = "stream", + label = "perspective-quad-instance", + size = pqmat.instance_size * ctx.settings.draw_instance, + } + + local perspective_quad_bindings = render.bindings() + perspective_quad_bindings:vbuffer(0, state.perspective_quad_inst) + perspective_quad_bindings:sampler(0, state.default_sampler) + + state.perspective_quad_bindings = perspective_quad_bindings + state.material_perspective_quad = pqmat.new { + inst_buffer = state.perspective_quad_inst, + bindings = state.perspective_quad_bindings, + uniform = state.uniform, + sprite_bank = ctx.arg.bank_ptr, + tmp_buffer = ctx.tmp_buffer, + } + + return { + reset = function() + perspective_quad_bindings:base(0) + end, + submit = function(ptr, n) + state.material_perspective_quad:submit(ptr, n) + end, + draw = function(ptr, n, tex) + perspective_quad_bindings:view(1, state.views[tex + 1]) + state.material_perspective_quad:draw(ptr, n, tex) + end, + } + end, + } +end diff --git a/src/material/matquad.lua b/src/material/matquad.lua new file mode 100644 index 0000000..47ab4e5 --- /dev/null +++ b/src/material/matquad.lua @@ -0,0 +1,42 @@ +local render = require "soluna.render" +local quadmat = require "soluna.material.quad" + +return function(register) + register { + name = "quad", + create = function(ctx) + local state = ctx.state + state.quad_inst = render.buffer { + type = "vertex", + usage = "stream", + label = "quad-instance", + size = quadmat.instance_size * ctx.settings.draw_instance, + } + + local quad_bindings = render.bindings() + quad_bindings:vbuffer(0, state.quad_inst) + quad_bindings:view(0, state.views.storage) + + state.quad_bindings = quad_bindings + state.material_quad = quadmat.new { + inst_buffer = state.quad_inst, + bindings = state.quad_bindings, + uniform = state.uniform, + sr_buffer = state.srbuffer_mem, + tmp_buffer = ctx.tmp_buffer, + } + + return { + reset = function() + quad_bindings:base(0) + end, + submit = function(ptr, n) + state.material_quad:submit(ptr, n) + end, + draw = function(ptr, n) + state.material_quad:draw(ptr, n) + end, + } + end, + } +end diff --git a/src/material/mattext.lua b/src/material/mattext.lua new file mode 100644 index 0000000..acb0855 --- /dev/null +++ b/src/material/mattext.lua @@ -0,0 +1,53 @@ +local render = require "soluna.render" +local textmat = require "soluna.material.text" + +return function(register) + register { + name = "text", + create = function(ctx) + local state = ctx.state + local setting = ctx.settings + local text_bindings + local text_sampler_desc = setting.text_sampler + if text_sampler_desc then + text_sampler_desc.label = text_sampler_desc.label or "text-sampler" + state.text_sampler = render.sampler(text_sampler_desc) + state.text_inst = render.buffer { + type = "vertex", + usage = "stream", + label = "text-instance", + size = textmat.instance_size * setting.draw_instance, + } + text_bindings = render.bindings() + text_bindings:vbuffer(0, state.text_inst) + text_bindings:view(0, state.views.storage) + text_bindings:sampler(0, state.text_sampler) + else + state.text_inst = state.inst + text_bindings = state.bindings + end + state.text_bindings = text_bindings + state.material_text = textmat.normal { + inst_buffer = state.text_inst, + bindings = state.text_bindings, + uniform = state.uniform, + sr_buffer = state.srbuffer_mem, + font_manager = ctx.font.cobj, + tmp_buffer = ctx.tmp_buffer, + } + + return { + reset = function() + text_bindings:base(0) + end, + submit = function(ptr, n) + state.material_text:submit(ptr, n) + end, + draw = function(ptr, n) + text_bindings:view(1, state.views.font) + state.material_text:draw(ptr, n) + end, + } + end, + } +end diff --git a/src/service/render.lua b/src/service/render.lua index 0ccebc7..267bcaa 100644 --- a/src/service/render.lua +++ b/src/service/render.lua @@ -3,24 +3,104 @@ local render = require "soluna.render" local image = require "soluna.image" local embedsource = require "soluna.embedsource" local drawmgr = require "soluna.drawmgr" -local defmat = require "soluna.material.default" -local textmat = require "soluna.material.text" -local quadmat = require "soluna.material.quad" -local maskmat = require "soluna.material.mask" -local pqmat = require "soluna.material.perspective_quad" -local soluna_app = require "soluna.app" +local file = require "soluna.file" -global require, assert, pairs, pcall, ipairs, print +global require, assert, pairs, pcall, ipairs, print, load, type, table local setting = require "soluna".settings() -local DEFAULT_MAT = 0 -local TEXT_MAT = 1 -local QUAD_MAT = 2 -local MASK_MAT = 3 -local PERSPECTIVE_QUAD_MAT = 4 +local reset_materials -local font = {} ; do +local font = {} + +local function create_materials(ctx) + local function load_materials() + local registry = {} + + function reset_materials(materials) + for _, desc in ipairs(registry) do + local obj = materials[desc.id] + if obj.reset then + obj.reset() + end + end + end + + local function join_path(path, name) + if path:match "/$" then + return path .. name + else + return path .. "/" .. name + end + end + + local function append(desc, id) + assert(type(desc.name) == "string") + assert(type(desc.create) == "function") + desc.id = id + registry[#registry + 1] = desc + return id + end + + local function run_source(source, chunkname, register) + local chunk = assert(load(source, chunkname)) + local callback = assert(chunk()) + assert(type(callback) == "function") + callback(register) + end + local MATERIAL_EXTLUA_BASE = 256 + do + local next_id = 0 + local function register(desc) + local id = next_id + assert(id < MATERIAL_EXTLUA_BASE) + next_id = id + 1 + return append(desc, id) + end + local function load_material(name) + local loader = assert(embedsource.material[name]) + run_source(loader(), "@src/material/" .. name .. ".lua", register) + end + for _, name in ipairs(embedsource.material) do + load_material(name) + end + end + if setting.extlua_material_path and setting.extlua_material_path ~= "" then + local path = setting.extlua_material_path + if file.attributes(path, "mode") ~= "directory" then + return registry + end + local files = {} + for name in file.dir(path) do + if name ~= "." and name ~= ".." and name:match "%.lua$" then + files[#files + 1] = name + end + end + table.sort(files) + local next_id = MATERIAL_EXTLUA_BASE + local function register(desc) + local id = next_id + next_id = id + 1 + return append(desc, id) + end + for _, name in ipairs(files) do + local fullname = join_path(path, name) + run_source(assert(file.load(fullname)), "@" .. fullname, register) + end + end + return registry + end + local materials = {} + for _, desc in ipairs(load_materials()) do + local obj = assert(desc.create(ctx)) + assert(type(obj.submit) == "function") + assert(type(obj.draw) == "function") + materials[desc.id] = obj + end + return materials +end + +do local mgr = require "soluna.font.manager" local fontapi = require "soluna.font" local texture_ptr @@ -31,11 +111,11 @@ local font = {} ; do font.cobj = fontapi.cobj() texture_ptr = fontapi.texture() end - + function font.shutdown() mgr.shutdown() end - + function font.submit(img) if fontapi.submit() then img:update(texture_ptr) @@ -43,7 +123,7 @@ local font = {} ; do end end -local batch = {} ; do +local batch = {}; do local thread local submit_n = 0 function batch.register(addr) @@ -53,6 +133,7 @@ local batch = {} ; do } return n end + function batch.wait() if submit_n ~= #batch then thread = ltask.current_token() @@ -60,10 +141,11 @@ local batch = {} ; do end submit_n = 0 end + function batch.submit(id, ptr, size) local q = batch[id] local token = ltask.current_token() - local function func () + local function func() return ptr, size, token end if q[1] == nil then @@ -74,16 +156,17 @@ local batch = {} ; do end q[1] = func else - q[#q+1] = func + q[#q + 1] = func end ltask.wait() end + function batch.consume(id) local q = batch[id] local r = assert(q[1]) local n = #q for i = 1, n - 1 do - q[i] = q[i+1] + q[i] = q[i + 1] end q[n] = nil return r() @@ -92,54 +175,6 @@ end local STATE -local materials = { - [DEFAULT_MAT] = { - submit = function(ptr, n) - STATE.material:submit(ptr, n) - end, - draw = function(ptr, n, tex) - STATE.bindings:view(1, STATE.views[tex+1]) - STATE.material:draw(ptr, n, tex) - end, - }, - [TEXT_MAT] = { - submit = function(ptr, n) - STATE.material_text:submit(ptr, n) - end, - draw = function(ptr, n) - STATE.text_bindings:view(1, STATE.views.font) - STATE.material_text:draw(ptr, n) - end, - }, - [QUAD_MAT] = { - submit = function(ptr, n) - STATE.material_quad:submit(ptr, n) - end, - draw = function(ptr, n) - STATE.material_quad:draw(ptr, n) - end, - }, - [MASK_MAT] = { - submit = function(ptr, n) - STATE.material_mask:submit(ptr, n) - end, - draw = function(ptr, n, tex) - STATE.mask_bindings:view(1, STATE.views[tex+1]) - STATE.material_mask:draw(ptr, n, tex) - end, - }, - [PERSPECTIVE_QUAD_MAT] = { - submit = function(ptr, n) - STATE.material_perspective_quad:submit(ptr, n) - end, - draw = function(ptr, n, tex) - STATE.perspective_quad_bindings:view(1, STATE.views[tex+1]) - STATE.material_perspective_quad:draw(ptr, n, tex) - end, - }, -} - - local S = {} function S.app(settings) @@ -183,11 +218,7 @@ local function frame(count) local batch_n = #batch if update_image then update_image() end STATE.drawmgr:reset() - STATE.bindings:base(0) - STATE.text_bindings:base(0) - STATE.quad_bindings:base(0) - STATE.mask_bindings:base(0) - STATE.perspective_quad_bindings:base(0) + reset_materials(STATE.materials) for i = 1, batch_n do local ptr, size = batch[i][1]() if ptr then @@ -197,24 +228,24 @@ local function frame(count) local draw_n = #STATE.drawmgr for i = 1, draw_n do local mat, ptr, n, tex = STATE.drawmgr(i) - local obj = materials[mat] + local obj = assert(STATE.materials[mat]) obj.submit(ptr, n) end STATE.srbuffer:update(STATE.srbuffer_mem:ptr()) STATE.pass:begin() - font.submit(STATE.font_texture) - for i = 1, draw_n do - local mat, ptr, n, tex = STATE.drawmgr(i) - local obj = materials[mat] - obj.draw(ptr, n, tex) - end + font.submit(STATE.font_texture) + for i = 1, draw_n do + local mat, ptr, n, tex = STATE.drawmgr(i) + local obj = assert(STATE.materials[mat]) + obj.draw(ptr, n, tex) + end STATE.pass:finish() render.submit() end function S.frame(count) batch.wait() - local ok , err = pcall(ltask.mainthread_run, frame, count) + local ok, err = pcall(ltask.mainthread_run, frame, count) if not ok then print("RENDER ERR", err) end @@ -233,12 +264,12 @@ function S.quit() for _, v in ipairs(batch) do workers[v.source] = true end - - S.submit_batch = function() end -- prevent submit + + S.submit_batch = function() end -- prevent submit for _, v in ipairs(batch) do for _, resp in ipairs(v) do - local _,_, token = resp() + local _, _, token = resp() ltask.wakeup(token) end end @@ -271,13 +302,6 @@ local function render_init(arg) font.init() local texture_size = setting.texture_size - - local inst_buffer = render.buffer { - type = "vertex", - usage = "stream", - label = "texquad-instance", - size = defmat.instance_size * setting.draw_instance, -- textmat.instance_size is the same - } local sr_buffer = render.buffer { type = "storage", usage = "dynamic", @@ -307,91 +331,13 @@ local function render_init(arg) font_texture = font_texture, views = views, } - local bindings = render.bindings() - bindings:vbuffer(0, inst_buffer) - bindings:view(0, views.storage) - bindings:sampler(0, STATE.default_sampler) - - STATE.inst = assert(inst_buffer) STATE.srbuffer = assert(sr_buffer) - STATE.srbuffer_mem = render.srbuffer(setting.srbuffer_size) - STATE.bindings = bindings - - do - local text_sampler_desc = setting.text_sampler - if text_sampler_desc then - text_sampler_desc.label = text_sampler_desc.label or "text-sampler" - STATE.text_sampler = render.sampler(text_sampler_desc) - STATE.text_inst = render.buffer { - type = "vertex", - usage = "stream", - label = "text-instance", - size = textmat.instance_size * setting.draw_instance, - } - local text_bindings = render.bindings() - text_bindings:vbuffer(0, STATE.text_inst) - text_bindings:view(0, views.storage) - text_bindings:sampler(0, STATE.text_sampler) - - STATE.text_bindings = text_bindings - else - STATE.text_inst = STATE.inst - STATE.text_bindings = STATE.bindings - end - end - - do - STATE.quad_inst = render.buffer { - type = "vertex", - usage = "stream", - label = "quad-instance", - size = quadmat.instance_size * setting.draw_instance, - } - - local quadbind = render.bindings() - quadbind:vbuffer(0, STATE.quad_inst) - quadbind:view(0, views.storage) - - STATE.quad_bindings = quadbind - end - - do - STATE.mask_inst = render.buffer { - type = "vertex", - usage = "stream", - label = "mask-instance", - size = maskmat.instance_size * setting.draw_instance, - } - - local maskbind = render.bindings() - - maskbind:vbuffer(0, STATE.mask_inst) - maskbind:view(0, views.storage) - maskbind:sampler(0, STATE.default_sampler) - - STATE.mask_bindings = maskbind - end - - do - STATE.perspective_quad_inst = render.buffer { - type = "vertex", - usage = "stream", - label = "perspective-quad-instance", - size = pqmat.instance_size * setting.draw_instance, - } - - local pqbind = render.bindings() - pqbind:vbuffer(0, STATE.perspective_quad_inst) - pqbind:sampler(0, STATE.default_sampler) - STATE.perspective_quad_bindings = pqbind - end - STATE.drawmgr = drawmgr.new(arg.bank_ptr, setting.draw_instance) - + STATE.uniform = render.uniform { - 12, -- size + 12, -- size framesize = { offset = 0, type = "float", @@ -402,52 +348,17 @@ local function render_init(arg) type = "float", }, } - STATE.uniform.framesize = { 2/arg.width, -2/arg.height } - STATE.uniform.tex_size = 1/texture_size - - local tmp_buffer = render.tmp_buffer(setting.tmpbuffer_size) + STATE.uniform.framesize = { 2 / arg.width, -2 / arg.height } + STATE.uniform.tex_size = 1 / texture_size - STATE.material = defmat.new { - inst_buffer = STATE.inst, - bindings = STATE.bindings, - uniform = STATE.uniform, - sr_buffer = STATE.srbuffer_mem, - sprite_bank = arg.bank_ptr, - tmp_buffer = tmp_buffer, - } - - STATE.material_mask = maskmat.new { - inst_buffer = STATE.mask_inst, - bindings = STATE.mask_bindings, - uniform = STATE.uniform, - sr_buffer = STATE.srbuffer_mem, - sprite_bank = arg.bank_ptr, - tmp_buffer = tmp_buffer, - } - - STATE.material_text = textmat.normal { - inst_buffer = STATE.text_inst, - bindings = STATE.text_bindings, - uniform = STATE.uniform, - sr_buffer = STATE.srbuffer_mem, - font_manager = font.cobj, - tmp_buffer = tmp_buffer, - } - - STATE.material_quad = quadmat.new { - inst_buffer = STATE.quad_inst, - bindings = STATE.quad_bindings, - uniform = STATE.uniform, - sr_buffer = STATE.srbuffer_mem, - tmp_buffer = tmp_buffer, - } - - STATE.material_perspective_quad = pqmat.new { - inst_buffer = STATE.perspective_quad_inst, - bindings = STATE.perspective_quad_bindings, - uniform = STATE.uniform, - sprite_bank = arg.bank_ptr, + local tmp_buffer = render.tmp_buffer(setting.tmpbuffer_size) + STATE.materials = create_materials { + state = STATE, + arg = arg, tmp_buffer = tmp_buffer, + settings = setting, + font = font, + render = render, } end @@ -456,7 +367,7 @@ function S.init(arg) end function S.resize(w, h) - STATE.uniform.framesize = { 2/w, -2/h } + STATE.uniform.framesize = { 2 / w, -2 / h } end return S From 713491348b1956a17ac8163edbf588e08aa65c8f Mon Sep 17 00:00:00 2001 From: Hanchin Hsieh Date: Mon, 27 Apr 2026 12:44:45 +0800 Subject: [PATCH 2/5] render: support register external material --- Makefile | 19 +- clibs/sample/make.lua | 82 + clibs/soluna/make.lua | 2 + docs/material_perspective_quad.lua | 27 - extlua/extlua.c | 1939 +++++++++++---------- extlua/extlua.temp.c | 13 +- extlua/extlua_impl.c | 646 +++---- extlua/extlua_sample.c | 482 +++++ extlua/gen.lua | 1 + extlua/gen_sokol.lua | 134 ++ extlua/gen_soluna.lua | 202 +++ {src => extlua}/perspective_quad.glsl | 0 extlua/sokolapi.c | 131 ++ extlua/sokolapi.temp.c | 28 + extlua/sokolapi_impl.c | 51 + extlua/sokolapi_impl.temp.c | 17 + extlua/solunaapi.c | 63 + extlua/solunaapi.h | 48 + extlua/solunaapi.h.temp | 14 + extlua/solunaapi.temp.c | 32 + extlua/solunaapi_impl.c | 66 + extlua/solunaapi_impl.temp.c | 19 + make.lua | 13 +- src/embedlua.c | 2 - src/extapi.c | 231 +++ src/extapi_types.h | 41 + src/extapi_types.temp.h | 6 + src/external.c | 31 +- src/luamods.c | 2 - src/material/matdefault.lua | 78 +- src/material/matmask.lua | 82 +- src/material/matpquad.lua | 43 - src/material/matquad.lua | 76 +- src/material/mattext.lua | 94 +- src/material_mask.c | 20 +- src/material_perspective_quad.c | 462 ----- src/material_quad.c | 20 +- src/material_text.c | 32 +- src/material_util.h | 5 - src/service/render.lua | 126 +- test/extlua.game | 2 + test/extlua.lua | 126 ++ test/extlua/material/perspective_quad.lua | 43 + test/perspective_quad.lua | 226 --- 44 files changed, 3440 insertions(+), 2337 deletions(-) create mode 100644 clibs/sample/make.lua delete mode 100644 docs/material_perspective_quad.lua create mode 100644 extlua/gen_sokol.lua create mode 100644 extlua/gen_soluna.lua rename {src => extlua}/perspective_quad.glsl (100%) create mode 100644 extlua/sokolapi.c create mode 100644 extlua/sokolapi.temp.c create mode 100644 extlua/sokolapi_impl.c create mode 100644 extlua/sokolapi_impl.temp.c create mode 100644 extlua/solunaapi.c create mode 100644 extlua/solunaapi.h create mode 100644 extlua/solunaapi.h.temp create mode 100644 extlua/solunaapi.temp.c create mode 100644 extlua/solunaapi_impl.c create mode 100644 extlua/solunaapi_impl.temp.c create mode 100644 src/extapi.c create mode 100644 src/extapi_types.h create mode 100644 src/extapi_types.temp.h delete mode 100644 src/material/matpquad.lua delete mode 100644 src/material_perspective_quad.c create mode 100644 test/extlua/material/perspective_quad.lua delete mode 100644 test/perspective_quad.lua diff --git a/Makefile b/Makefile index 1a3514b..6848300 100644 --- a/Makefile +++ b/Makefile @@ -58,12 +58,17 @@ $(LUA_O) : $(LUASRC) SHADER_SRC=$(wildcard src/*.glsl) SHADER_O=$(patsubst src/%.glsl,$(BUILD)/%.glsl.h,$(SHADER_SRC)) +EXTLUA_SHADER_SRC=$(wildcard extlua/*.glsl) +EXTLUA_SHADER_O=$(patsubst extlua/%.glsl,$(BUILD)/%.glsl.h,$(EXTLUA_SHADER_SRC)) SHADERINC=-I$(BUILD) $(BUILD)/%.glsl.h : src/%.glsl $(SHDC) --input $< --output $@ --slang hlsl4 --format sokol -shader : $(SHADER_O) +$(BUILD)/%.glsl.h : extlua/%.glsl + $(SHDC) --input $< --output $@ --slang hlsl4 --format sokol + +shader : $(SHADER_O) $(EXTLUA_SHADER_O) MAIN_FULL=$(wildcard src/*.c) PLATFORM_FULL=$(wildcard src/platform/windows/*.c) @@ -71,7 +76,7 @@ MAIN_C=$(notdir $(MAIN_FULL)) MAIN_O=$(patsubst %.c,$(BUILD)/soluna_%.o,$(MAIN_C)) PLATFORM_C=$(notdir $(PLATFORM_FULL)) PLATFORM_O=$(patsubst %.c,$(BUILD)/platform_%.o,$(PLATFORM_C)) -EXTLUA_O=$(BUILD)/extlua_impl.o +EXTLUA_O=$(BUILD)/extlua_impl.o $(BUILD)/sokolapi_impl.o $(BUILD)/solunaapi_impl.o $(MAIN_O) : $(SHADER_O) @@ -156,11 +161,17 @@ $(BUILD)/minizip_%.o : 3rd/zlib/contrib/minizip/%.c $(BUILD)/extlua_impl.o : extlua/extlua_impl.c $(COMPILE_C) $(LUAINC) +$(BUILD)/sokolapi_impl.o : extlua/sokolapi_impl.c + $(COMPILE_C) $(3RDINC) + +$(BUILD)/solunaapi_impl.o : extlua/solunaapi_impl.c + $(COMPILE_C) $(LUAINC) $(3RDINC) + $(BIN)/$(APPNAME): $(MAIN_O) $(PLATFORM_O) $(EXTLUA_O) $(LTASK_O) $(LUA_O) $(DATALIST_O) $(BUILD)/yoga.o $(ZLIB_O) $(MINIZIP_O) $(LD) $(OUTPUT_EXE) $@ $^ $(LDFLAGS) -$(BIN)/sample.dll : extlua/extlua.c extlua/extlua_sample.c - $(CC) $(CFLAGS) $(SHARED) $(OUTPUT_EXE) $@ $^ $(LUAINC) +$(BIN)/sample.dll : extlua/extlua.c extlua/sokolapi.c extlua/solunaapi.c extlua/extlua_sample.c | $(EXTLUA_SHADER_O) + $(CC) $(CFLAGS) $(SHARED) $(OUTPUT_EXE) $@ $^ $(LUAINC) $(3RDINC) $(SHADERINC) -Iextlua extlua_sample: $(BIN)/sample.dll diff --git a/clibs/sample/make.lua b/clibs/sample/make.lua new file mode 100644 index 0000000..5fde2ee --- /dev/null +++ b/clibs/sample/make.lua @@ -0,0 +1,82 @@ +local lm = require "luamake" +local platform = require "bee.platform" + +lm.rootdir = lm.basedir + +local function shdc_plat() + if lm.os == "windows" then + return "win32" + end + if lm.os == "linux" then + return "linux" + end + if lm.os == "macos" then + return platform.Arch == "arm64" and "osx_arm64" or "osx" + end + return "unknown" +end + +local paths = { + windows = "$PATH/$NAME.exe", + macos = "$PATH/$NAME", + linux = "$PATH/$NAME", +} + +local shdc = assert(paths[lm.os]):gsub("%$(%u+)", { + PATH = tostring(lm.basedir / "bin/sokol-tools-bin/bin" / shdc_plat()), + NAME = "sokol-shdc", +}) + +local function shader_lang() + local plat = lm.platform + if plat == "msvc" or plat == "clang-cl" or plat == "mingw" then + return "hlsl4" + end + if plat == "macos" then + return "metal_macos" + end + if plat == "emcc" then + return "wgsl" + end + if plat == "linux" then + return "glsl430" + end + return "unknown" +end + +local function compile_shader(src, name) + local dep = name .. "_shader" + local target = lm.builddir .. "/" .. name + lm:runlua(dep) { + script = lm.basedir .. "/clibs/soluna/shader2c.lua", + inputs = lm.basedir .. "/" .. src, + outputs = lm.basedir .. "/" .. target, + args = { + shdc, + "$in", + "$out", + shader_lang(), + }, + } + return dep +end + +local sample_shader = compile_shader("extlua/perspective_quad.glsl", "perspective_quad.glsl.h") + +lm:dll "sample" { + sources = { + "extlua/extlua.c", + "extlua/sokolapi.c", + "extlua/solunaapi.c", + "extlua/extlua_sample.c", + }, + objdeps = { + sample_shader, + }, + includes = { + "3rd/lua", + "3rd", + "build", + "extlua", + }, +} diff --git a/clibs/soluna/make.lua b/clibs/soluna/make.lua index bef6293..3256387 100644 --- a/clibs/soluna/make.lua +++ b/clibs/soluna/make.lua @@ -31,6 +31,8 @@ lm:source_set "soluna_src" { sources = { "src/*.c", "extlua/extlua_impl.c", + "extlua/sokolapi_impl.c", + "extlua/solunaapi_impl.c", }, objdeps = objdeps, defines = { diff --git a/docs/material_perspective_quad.lua b/docs/material_perspective_quad.lua deleted file mode 100644 index 9b08151..0000000 --- a/docs/material_perspective_quad.lua +++ /dev/null @@ -1,27 +0,0 @@ ----@meta soluna.material.perspective_quad - ----perspective quad 选项 ----Perspective quad options. ----@class soluna.material.perspective_quad.Options ----@field quad? number[] 自定义四角坐标 `{x0,y0,x1,y1,x2,y2,x3,y3}` / Custom corner coordinates ----@field scale_x? number X 缩放,默认 1 / X scale, default 1 ----@field scale_y? number Y 缩放,默认 1 / Y scale, default 1 ----@field shear_x? number X shear,默认 0 / X shear, default 0 ----@field shear_y? number Y shear,默认 0 / Y shear, default 0 ----@field q? number[] 四角 perspective q,默认全 1 / Per-corner perspective q, default all 1 ----@field color? integer ARGB 颜色,默认 `0xffffffff` / ARGB color, default `0xffffffff` - ----perspective quad material 模块 ----Perspective quad material module. ----@class soluna.material.perspective_quad -local matproj = {} - ----创建 perspective sprite command stream ----Creates a perspective sprite command stream. ----@param sprite integer 1-based sprite id / 1-based sprite id ----@param options soluna.material.perspective_quad.Options 绘制选项 / Draw options ----@return string stream 可传给 `batch:add` 的 packed stream / Packed stream for `batch:add` -function matproj.sprite(sprite, options) -end - -return matproj diff --git a/extlua/extlua.c b/extlua/extlua.c index 60fd6a4..fe2d09d 100644 --- a/extlua/extlua.c +++ b/extlua/extlua.c @@ -1,967 +1,972 @@ -// AUTO GENERATED by extlua.temp.c, DONT EDIT - -#include -#include -#include -#include -#include - -struct lua_api { - int version; - - lua_State * (*lua_newstate) (lua_Alloc f, void *ud, unsigned seed); - void (*lua_close) (lua_State *L); - lua_State * (*lua_newthread) (lua_State *L); - int (*lua_closethread) (lua_State *L, lua_State *from); - lua_CFunction (*lua_atpanic) (lua_State *L, lua_CFunction panicf); - lua_Number (*lua_version) (lua_State *L); - int (*lua_absindex) (lua_State *L, int idx); - int (*lua_gettop) (lua_State *L); - void (*lua_settop) (lua_State *L, int idx); - void (*lua_pushvalue) (lua_State *L, int idx); - void (*lua_rotate) (lua_State *L, int idx, int n); - void (*lua_copy) (lua_State *L, int fromidx, int toidx); - int (*lua_checkstack) (lua_State *L, int n); - void (*lua_xmove) (lua_State *from, lua_State *to, int n); - int (*lua_isnumber) (lua_State *L, int idx); - int (*lua_isstring) (lua_State *L, int idx); - int (*lua_iscfunction) (lua_State *L, int idx); - int (*lua_isinteger) (lua_State *L, int idx); - int (*lua_isuserdata) (lua_State *L, int idx); - int (*lua_type) (lua_State *L, int idx); - const char * (*lua_typename) (lua_State *L, int tp); - lua_Number (*lua_tonumberx) (lua_State *L, int idx, int *isnum); - lua_Integer (*lua_tointegerx) (lua_State *L, int idx, int *isnum); - int (*lua_toboolean) (lua_State *L, int idx); - const char * (*lua_tolstring) (lua_State *L, int idx, size_t *len); - lua_Unsigned (*lua_rawlen) (lua_State *L, int idx); - lua_CFunction (*lua_tocfunction) (lua_State *L, int idx); - void * (*lua_touserdata) (lua_State *L, int idx); - lua_State * (*lua_tothread) (lua_State *L, int idx); - const void * (*lua_topointer) (lua_State *L, int idx); - void (*lua_arith) (lua_State *L, int op); - int (*lua_rawequal) (lua_State *L, int idx1, int idx2); - int (*lua_compare) (lua_State *L, int idx1, int idx2, int op); - void (*lua_pushnil) (lua_State *L); - void (*lua_pushnumber) (lua_State *L, lua_Number n); - void (*lua_pushinteger) (lua_State *L, lua_Integer n); - const char * (*lua_pushlstring) (lua_State *L, const char *s, size_t len); - const char * (*lua_pushexternalstring) (lua_State *L, - const char *s, size_t len, lua_Alloc falloc, void *ud); - const char * (*lua_pushstring) (lua_State *L, const char *s); - const char * (*lua_pushvfstring) (lua_State *L, const char *fmt, - va_list argp); - void (*lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); - void (*lua_pushboolean) (lua_State *L, int b); - void (*lua_pushlightuserdata) (lua_State *L, void *p); - int (*lua_pushthread) (lua_State *L); - int (*lua_getglobal) (lua_State *L, const char *name); - int (*lua_gettable) (lua_State *L, int idx); - int (*lua_getfield) (lua_State *L, int idx, const char *k); - int (*lua_geti) (lua_State *L, int idx, lua_Integer n); - int (*lua_rawget) (lua_State *L, int idx); - int (*lua_rawgeti) (lua_State *L, int idx, lua_Integer n); - int (*lua_rawgetp) (lua_State *L, int idx, const void *p); - void (*lua_createtable) (lua_State *L, int narr, int nrec); - void * (*lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); - int (*lua_getmetatable) (lua_State *L, int objindex); - int (*lua_getiuservalue) (lua_State *L, int idx, int n); - void (*lua_setglobal) (lua_State *L, const char *name); - void (*lua_settable) (lua_State *L, int idx); - void (*lua_setfield) (lua_State *L, int idx, const char *k); - void (*lua_seti) (lua_State *L, int idx, lua_Integer n); - void (*lua_rawset) (lua_State *L, int idx); - void (*lua_rawseti) (lua_State *L, int idx, lua_Integer n); - void (*lua_rawsetp) (lua_State *L, int idx, const void *p); - int (*lua_setmetatable) (lua_State *L, int objindex); - int (*lua_setiuservalue) (lua_State *L, int idx, int n); - void (*lua_callk) (lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k); - int (*lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction k); - int (*lua_load) (lua_State *L, lua_Reader reader, void *dt, - const char *chunkname, const char *mode); - int (*lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); - int (*lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k); - int (*lua_resume) (lua_State *L, lua_State *from, int narg, - int *nres); - int (*lua_status) (lua_State *L); - int (*lua_isyieldable) (lua_State *L); - void (*lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud); - void (*lua_warning) (lua_State *L, const char *msg, int tocont); - int (*lua_error) (lua_State *L); - int (*lua_next) (lua_State *L, int idx); - void (*lua_concat) (lua_State *L, int n); - void (*lua_len) (lua_State *L, int idx); - unsigned (*lua_numbertocstring) (lua_State *L, int idx, char *buff); - size_t (*lua_stringtonumber) (lua_State *L, const char *s); - lua_Alloc (*lua_getallocf) (lua_State *L, void **ud); - void (*lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); - void (*lua_toclose) (lua_State *L, int idx); - void (*lua_closeslot) (lua_State *L, int idx); - int (*lua_getstack) (lua_State *L, int level, lua_Debug *ar); - int (*lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); - const char * (*lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); - const char * (*lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); - const char * (*lua_getupvalue) (lua_State *L, int funcindex, int n); - const char * (*lua_setupvalue) (lua_State *L, int funcindex, int n); - void * (*lua_upvalueid) (lua_State *L, int fidx, int n); - void (*lua_upvaluejoin) (lua_State *L, int fidx1, int n1, - int fidx2, int n2); - void (*lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); - lua_Hook (*lua_gethook) (lua_State *L); - int (*lua_gethookmask) (lua_State *L); - int (*lua_gethookcount) (lua_State *L); - void (*luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); - int (*luaL_getmetafield) (lua_State *L, int obj, const char *e); - int (*luaL_callmeta) (lua_State *L, int obj, const char *e); - const char * (*luaL_tolstring) (lua_State *L, int idx, size_t *len); - int (*luaL_argerror) (lua_State *L, int arg, const char *extramsg); - int (*luaL_typeerror) (lua_State *L, int arg, const char *tname); - const char * (*luaL_checklstring) (lua_State *L, int arg, - size_t *l); - const char * (*luaL_optlstring) (lua_State *L, int arg, - const char *def, size_t *l); - lua_Number (*luaL_checknumber) (lua_State *L, int arg); - lua_Number (*luaL_optnumber) (lua_State *L, int arg, lua_Number def); - lua_Integer (*luaL_checkinteger) (lua_State *L, int arg); - lua_Integer (*luaL_optinteger) (lua_State *L, int arg, - lua_Integer def); - void (*luaL_checkstack) (lua_State *L, int sz, const char *msg); - void (*luaL_checktype) (lua_State *L, int arg, int t); - void (*luaL_checkany) (lua_State *L, int arg); - int (*luaL_newmetatable) (lua_State *L, const char *tname); - void (*luaL_setmetatable) (lua_State *L, const char *tname); - void * (*luaL_testudata) (lua_State *L, int ud, const char *tname); - void * (*luaL_checkudata) (lua_State *L, int ud, const char *tname); - void (*luaL_where) (lua_State *L, int lvl); - int (*luaL_checkoption) (lua_State *L, int arg, const char *def, - const char *const lst[]); - int (*luaL_fileresult) (lua_State *L, int stat, const char *fname); - int (*luaL_execresult) (lua_State *L, int stat); - void * (*luaL_alloc) (void *ud, void *ptr, size_t osize, - size_t nsize); - int (*luaL_ref) (lua_State *L, int t); - void (*luaL_unref) (lua_State *L, int t, int ref); - int (*luaL_loadfilex) (lua_State *L, const char *filename, - const char *mode); - int (*luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, - const char *name, const char *mode); - int (*luaL_loadstring) (lua_State *L, const char *s); - lua_State * (*luaL_newstate) (void); - unsigned (*luaL_makeseed) (lua_State *L); - lua_Integer (*luaL_len) (lua_State *L, int idx); - void (*luaL_addgsub) (luaL_Buffer *b, const char *s, - const char *p, const char *r); - const char * (*luaL_gsub) (lua_State *L, const char *s, - const char *p, const char *r); - void (*luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); - int (*luaL_getsubtable) (lua_State *L, int idx, const char *fname); - void (*luaL_traceback) (lua_State *L, lua_State *L1, - const char *msg, int level); - void (*luaL_requiref) (lua_State *L, const char *modname, - lua_CFunction openf, int glb); - void (*luaL_buffinit) (lua_State *L, luaL_Buffer *B); - char * (*luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); - void (*luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); - void (*luaL_addstring) (luaL_Buffer *B, const char *s); - void (*luaL_addvalue) (luaL_Buffer *B); - void (*luaL_pushresult) (luaL_Buffer *B); - void (*luaL_pushresultsize) (luaL_Buffer *B, size_t sz); - char * (*luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); - int (*lua_gc) (lua_State *L, int what, ...); -}; - -static struct lua_api API; - -LUA_API lua_State * -lua_newstate(lua_Alloc f, void *ud, unsigned seed) { - return API.lua_newstate(f,ud,seed); -} - -LUA_API void -lua_close(lua_State *L) { - API.lua_close(L); -} - -LUA_API lua_State * -lua_newthread(lua_State *L) { - return API.lua_newthread(L); -} - -LUA_API int -lua_closethread(lua_State *L, lua_State *from) { - return API.lua_closethread(L,from); -} - -LUA_API lua_CFunction -lua_atpanic(lua_State *L, lua_CFunction panicf) { - return API.lua_atpanic(L,panicf); -} - -LUA_API lua_Number -lua_version(lua_State *L) { - return API.lua_version(L); -} - -LUA_API int -lua_absindex(lua_State *L, int idx) { - return API.lua_absindex(L,idx); -} - -LUA_API int -lua_gettop(lua_State *L) { - return API.lua_gettop(L); -} - -LUA_API void -lua_settop(lua_State *L, int idx) { - API.lua_settop(L,idx); -} - -LUA_API void -lua_pushvalue(lua_State *L, int idx) { - API.lua_pushvalue(L,idx); -} - -LUA_API void -lua_rotate(lua_State *L, int idx, int n) { - API.lua_rotate(L,idx,n); -} - -LUA_API void -lua_copy(lua_State *L, int fromidx, int toidx) { - API.lua_copy(L,fromidx,toidx); -} - -LUA_API int -lua_checkstack(lua_State *L, int n) { - return API.lua_checkstack(L,n); -} - -LUA_API void -lua_xmove(lua_State *from, lua_State *to, int n) { - API.lua_xmove(from,to,n); -} - -LUA_API int -lua_isnumber(lua_State *L, int idx) { - return API.lua_isnumber(L,idx); -} - -LUA_API int -lua_isstring(lua_State *L, int idx) { - return API.lua_isstring(L,idx); -} - -LUA_API int -lua_iscfunction(lua_State *L, int idx) { - return API.lua_iscfunction(L,idx); -} - -LUA_API int -lua_isinteger(lua_State *L, int idx) { - return API.lua_isinteger(L,idx); -} - -LUA_API int -lua_isuserdata(lua_State *L, int idx) { - return API.lua_isuserdata(L,idx); -} - -LUA_API int -lua_type(lua_State *L, int idx) { - return API.lua_type(L,idx); -} - -LUA_API const char * -lua_typename(lua_State *L, int tp) { - return API.lua_typename(L,tp); -} - -LUA_API lua_Number -lua_tonumberx(lua_State *L, int idx, int *isnum) { - return API.lua_tonumberx(L,idx,isnum); -} - -LUA_API lua_Integer -lua_tointegerx(lua_State *L, int idx, int *isnum) { - return API.lua_tointegerx(L,idx,isnum); -} - -LUA_API int -lua_toboolean(lua_State *L, int idx) { - return API.lua_toboolean(L,idx); -} - -LUA_API const char * -lua_tolstring(lua_State *L, int idx, size_t *len) { - return API.lua_tolstring(L,idx,len); -} - -LUA_API lua_Unsigned -lua_rawlen(lua_State *L, int idx) { - return API.lua_rawlen(L,idx); -} - -LUA_API lua_CFunction -lua_tocfunction(lua_State *L, int idx) { - return API.lua_tocfunction(L,idx); -} - -LUA_API void * -lua_touserdata(lua_State *L, int idx) { - return API.lua_touserdata(L,idx); -} - -LUA_API lua_State * -lua_tothread(lua_State *L, int idx) { - return API.lua_tothread(L,idx); -} - -LUA_API const void * -lua_topointer(lua_State *L, int idx) { - return API.lua_topointer(L,idx); -} - -LUA_API void -lua_arith(lua_State *L, int op) { - API.lua_arith(L,op); -} - -LUA_API int -lua_rawequal(lua_State *L, int idx1, int idx2) { - return API.lua_rawequal(L,idx1,idx2); -} - -LUA_API int -lua_compare(lua_State *L, int idx1, int idx2, int op) { - return API.lua_compare(L,idx1,idx2,op); -} - -LUA_API void -lua_pushnil(lua_State *L) { - API.lua_pushnil(L); -} - -LUA_API void -lua_pushnumber(lua_State *L, lua_Number n) { - API.lua_pushnumber(L,n); -} - -LUA_API void -lua_pushinteger(lua_State *L, lua_Integer n) { - API.lua_pushinteger(L,n); -} - -LUA_API const char * -lua_pushlstring(lua_State *L, const char *s, size_t len) { - return API.lua_pushlstring(L,s,len); -} - -LUA_API const char * -lua_pushexternalstring(lua_State *L, - const char *s, size_t len, lua_Alloc falloc, void *ud) { - return API.lua_pushexternalstring(L,s,len,falloc,ud); -} - -LUA_API const char * -lua_pushstring(lua_State *L, const char *s) { - return API.lua_pushstring(L,s); -} - -LUA_API const char * -lua_pushvfstring(lua_State *L, const char *fmt, - va_list argp) { - return API.lua_pushvfstring(L,fmt,argp); -} - -LUA_API void -lua_pushcclosure(lua_State *L, lua_CFunction fn, int n) { - API.lua_pushcclosure(L,fn,n); -} - -LUA_API void -lua_pushboolean(lua_State *L, int b) { - API.lua_pushboolean(L,b); -} - -LUA_API void -lua_pushlightuserdata(lua_State *L, void *p) { - API.lua_pushlightuserdata(L,p); -} - -LUA_API int -lua_pushthread(lua_State *L) { - return API.lua_pushthread(L); -} - -LUA_API int -lua_getglobal(lua_State *L, const char *name) { - return API.lua_getglobal(L,name); -} - -LUA_API int -lua_gettable(lua_State *L, int idx) { - return API.lua_gettable(L,idx); -} - -LUA_API int -lua_getfield(lua_State *L, int idx, const char *k) { - return API.lua_getfield(L,idx,k); -} - -LUA_API int -lua_geti(lua_State *L, int idx, lua_Integer n) { - return API.lua_geti(L,idx,n); -} - -LUA_API int -lua_rawget(lua_State *L, int idx) { - return API.lua_rawget(L,idx); -} - -LUA_API int -lua_rawgeti(lua_State *L, int idx, lua_Integer n) { - return API.lua_rawgeti(L,idx,n); -} - -LUA_API int -lua_rawgetp(lua_State *L, int idx, const void *p) { - return API.lua_rawgetp(L,idx,p); -} - -LUA_API void -lua_createtable(lua_State *L, int narr, int nrec) { - API.lua_createtable(L,narr,nrec); -} - -LUA_API void * -lua_newuserdatauv(lua_State *L, size_t sz, int nuvalue) { - return API.lua_newuserdatauv(L,sz,nuvalue); -} - -LUA_API int -lua_getmetatable(lua_State *L, int objindex) { - return API.lua_getmetatable(L,objindex); -} - -LUA_API int -lua_getiuservalue(lua_State *L, int idx, int n) { - return API.lua_getiuservalue(L,idx,n); -} - -LUA_API void -lua_setglobal(lua_State *L, const char *name) { - API.lua_setglobal(L,name); -} - -LUA_API void -lua_settable(lua_State *L, int idx) { - API.lua_settable(L,idx); -} - -LUA_API void -lua_setfield(lua_State *L, int idx, const char *k) { - API.lua_setfield(L,idx,k); -} - -LUA_API void -lua_seti(lua_State *L, int idx, lua_Integer n) { - API.lua_seti(L,idx,n); -} - -LUA_API void -lua_rawset(lua_State *L, int idx) { - API.lua_rawset(L,idx); -} - -LUA_API void -lua_rawseti(lua_State *L, int idx, lua_Integer n) { - API.lua_rawseti(L,idx,n); -} - -LUA_API void -lua_rawsetp(lua_State *L, int idx, const void *p) { - API.lua_rawsetp(L,idx,p); -} - -LUA_API int -lua_setmetatable(lua_State *L, int objindex) { - return API.lua_setmetatable(L,objindex); -} - -LUA_API int -lua_setiuservalue(lua_State *L, int idx, int n) { - return API.lua_setiuservalue(L,idx,n); -} - -LUA_API void -lua_callk(lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k) { - API.lua_callk(L,nargs,nresults,ctx,k); -} - -LUA_API int -lua_pcallk(lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction k) { - return API.lua_pcallk(L,nargs,nresults,errfunc,ctx,k); -} - -LUA_API int -lua_load(lua_State *L, lua_Reader reader, void *dt, - const char *chunkname, const char *mode) { - return API.lua_load(L,reader,dt,chunkname,mode); -} - -LUA_API int -lua_dump(lua_State *L, lua_Writer writer, void *data, int strip) { - return API.lua_dump(L,writer,data,strip); -} - -LUA_API int -lua_yieldk(lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k) { - return API.lua_yieldk(L,nresults,ctx,k); -} - -LUA_API int -lua_resume(lua_State *L, lua_State *from, int narg, - int *nres) { - return API.lua_resume(L,from,narg,nres); -} - -LUA_API int -lua_status(lua_State *L) { - return API.lua_status(L); -} - -LUA_API int -lua_isyieldable(lua_State *L) { - return API.lua_isyieldable(L); -} - -LUA_API void -lua_setwarnf(lua_State *L, lua_WarnFunction f, void *ud) { - API.lua_setwarnf(L,f,ud); -} - -LUA_API void -lua_warning(lua_State *L, const char *msg, int tocont) { - API.lua_warning(L,msg,tocont); -} - -LUA_API int -lua_error(lua_State *L) { - return API.lua_error(L); -} - -LUA_API int -lua_next(lua_State *L, int idx) { - return API.lua_next(L,idx); -} - -LUA_API void -lua_concat(lua_State *L, int n) { - API.lua_concat(L,n); -} - -LUA_API void -lua_len(lua_State *L, int idx) { - API.lua_len(L,idx); -} - -LUA_API unsigned -lua_numbertocstring(lua_State *L, int idx, char *buff) { - return API.lua_numbertocstring(L,idx,buff); -} - -LUA_API size_t -lua_stringtonumber(lua_State *L, const char *s) { - return API.lua_stringtonumber(L,s); -} - -LUA_API lua_Alloc -lua_getallocf(lua_State *L, void **ud) { - return API.lua_getallocf(L,ud); -} - -LUA_API void -lua_setallocf(lua_State *L, lua_Alloc f, void *ud) { - API.lua_setallocf(L,f,ud); -} - -LUA_API void -lua_toclose(lua_State *L, int idx) { - API.lua_toclose(L,idx); -} - -LUA_API void -lua_closeslot(lua_State *L, int idx) { - API.lua_closeslot(L,idx); -} - -LUA_API int -lua_getstack(lua_State *L, int level, lua_Debug *ar) { - return API.lua_getstack(L,level,ar); -} - -LUA_API int -lua_getinfo(lua_State *L, const char *what, lua_Debug *ar) { - return API.lua_getinfo(L,what,ar); -} - -LUA_API const char * -lua_getlocal(lua_State *L, const lua_Debug *ar, int n) { - return API.lua_getlocal(L,ar,n); -} - -LUA_API const char * -lua_setlocal(lua_State *L, const lua_Debug *ar, int n) { - return API.lua_setlocal(L,ar,n); -} - -LUA_API const char * -lua_getupvalue(lua_State *L, int funcindex, int n) { - return API.lua_getupvalue(L,funcindex,n); -} - -LUA_API const char * -lua_setupvalue(lua_State *L, int funcindex, int n) { - return API.lua_setupvalue(L,funcindex,n); -} - -LUA_API void * -lua_upvalueid(lua_State *L, int fidx, int n) { - return API.lua_upvalueid(L,fidx,n); -} - -LUA_API void -lua_upvaluejoin(lua_State *L, int fidx1, int n1, - int fidx2, int n2) { - API.lua_upvaluejoin(L,fidx1,n1,fidx2,n2); -} - -LUA_API void -lua_sethook(lua_State *L, lua_Hook func, int mask, int count) { - API.lua_sethook(L,func,mask,count); -} - -LUA_API lua_Hook -lua_gethook(lua_State *L) { - return API.lua_gethook(L); -} - -LUA_API int -lua_gethookmask(lua_State *L) { - return API.lua_gethookmask(L); -} - -LUA_API int -lua_gethookcount(lua_State *L) { - return API.lua_gethookcount(L); -} - -LUA_API void -luaL_checkversion_(lua_State *L, lua_Number ver, size_t sz) { - API.luaL_checkversion_(L,ver,sz); -} - -LUA_API int -luaL_getmetafield(lua_State *L, int obj, const char *e) { - return API.luaL_getmetafield(L,obj,e); -} - -LUA_API int -luaL_callmeta(lua_State *L, int obj, const char *e) { - return API.luaL_callmeta(L,obj,e); -} - -LUA_API const char * -luaL_tolstring(lua_State *L, int idx, size_t *len) { - return API.luaL_tolstring(L,idx,len); -} - -LUA_API int -luaL_argerror(lua_State *L, int arg, const char *extramsg) { - return API.luaL_argerror(L,arg,extramsg); -} - -LUA_API int -luaL_typeerror(lua_State *L, int arg, const char *tname) { - return API.luaL_typeerror(L,arg,tname); -} - -LUA_API const char * -luaL_checklstring(lua_State *L, int arg, - size_t *l) { - return API.luaL_checklstring(L,arg,l); -} - -LUA_API const char * -luaL_optlstring(lua_State *L, int arg, - const char *def, size_t *l) { - return API.luaL_optlstring(L,arg,def,l); -} - -LUA_API lua_Number -luaL_checknumber(lua_State *L, int arg) { - return API.luaL_checknumber(L,arg); -} - -LUA_API lua_Number -luaL_optnumber(lua_State *L, int arg, lua_Number def) { - return API.luaL_optnumber(L,arg,def); -} - -LUA_API lua_Integer -luaL_checkinteger(lua_State *L, int arg) { - return API.luaL_checkinteger(L,arg); -} - -LUA_API lua_Integer -luaL_optinteger(lua_State *L, int arg, - lua_Integer def) { - return API.luaL_optinteger(L,arg,def); -} - -LUA_API void -luaL_checkstack(lua_State *L, int sz, const char *msg) { - API.luaL_checkstack(L,sz,msg); -} - -LUA_API void -luaL_checktype(lua_State *L, int arg, int t) { - API.luaL_checktype(L,arg,t); -} - -LUA_API void -luaL_checkany(lua_State *L, int arg) { - API.luaL_checkany(L,arg); -} - -LUA_API int -luaL_newmetatable(lua_State *L, const char *tname) { - return API.luaL_newmetatable(L,tname); -} - -LUA_API void -luaL_setmetatable(lua_State *L, const char *tname) { - API.luaL_setmetatable(L,tname); -} - -LUA_API void * -luaL_testudata(lua_State *L, int ud, const char *tname) { - return API.luaL_testudata(L,ud,tname); -} - -LUA_API void * -luaL_checkudata(lua_State *L, int ud, const char *tname) { - return API.luaL_checkudata(L,ud,tname); -} - -LUA_API void -luaL_where(lua_State *L, int lvl) { - API.luaL_where(L,lvl); -} - -LUA_API int -luaL_checkoption(lua_State *L, int arg, const char *def, - const char *const lst[]) { - return API.luaL_checkoption(L,arg,def,lst); -} - -LUA_API int -luaL_fileresult(lua_State *L, int stat, const char *fname) { - return API.luaL_fileresult(L,stat,fname); -} - -LUA_API int -luaL_execresult(lua_State *L, int stat) { - return API.luaL_execresult(L,stat); -} - -LUA_API void * -luaL_alloc(void *ud, void *ptr, size_t osize, - size_t nsize) { - return API.luaL_alloc(ud,ptr,osize,nsize); -} - -LUA_API int -luaL_ref(lua_State *L, int t) { - return API.luaL_ref(L,t); -} - -LUA_API void -luaL_unref(lua_State *L, int t, int ref) { - API.luaL_unref(L,t,ref); -} - -LUA_API int -luaL_loadfilex(lua_State *L, const char *filename, - const char *mode) { - return API.luaL_loadfilex(L,filename,mode); -} - -LUA_API int -luaL_loadbufferx(lua_State *L, const char *buff, size_t sz, - const char *name, const char *mode) { - return API.luaL_loadbufferx(L,buff,sz,name,mode); -} - -LUA_API int -luaL_loadstring(lua_State *L, const char *s) { - return API.luaL_loadstring(L,s); -} - -LUA_API lua_State * -luaL_newstate(void) { - return API.luaL_newstate(); -} - -LUA_API unsigned -luaL_makeseed(lua_State *L) { - return API.luaL_makeseed(L); -} - -LUA_API lua_Integer -luaL_len(lua_State *L, int idx) { - return API.luaL_len(L,idx); -} - -LUA_API void -luaL_addgsub(luaL_Buffer *b, const char *s, - const char *p, const char *r) { - API.luaL_addgsub(b,s,p,r); -} - -LUA_API const char * -luaL_gsub(lua_State *L, const char *s, - const char *p, const char *r) { - return API.luaL_gsub(L,s,p,r); -} - -LUA_API void -luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { - API.luaL_setfuncs(L,l,nup); -} - -LUA_API int -luaL_getsubtable(lua_State *L, int idx, const char *fname) { - return API.luaL_getsubtable(L,idx,fname); -} - -LUA_API void -luaL_traceback(lua_State *L, lua_State *L1, - const char *msg, int level) { - API.luaL_traceback(L,L1,msg,level); -} - -LUA_API void -luaL_requiref(lua_State *L, const char *modname, - lua_CFunction openf, int glb) { - API.luaL_requiref(L,modname,openf,glb); -} - -LUA_API void -luaL_buffinit(lua_State *L, luaL_Buffer *B) { - API.luaL_buffinit(L,B); -} - -LUA_API char * -luaL_prepbuffsize(luaL_Buffer *B, size_t sz) { - return API.luaL_prepbuffsize(B,sz); -} - -LUA_API void -luaL_addlstring(luaL_Buffer *B, const char *s, size_t l) { - API.luaL_addlstring(B,s,l); -} - -LUA_API void -luaL_addstring(luaL_Buffer *B, const char *s) { - API.luaL_addstring(B,s); -} - -LUA_API void -luaL_addvalue(luaL_Buffer *B) { - API.luaL_addvalue(B); -} - -LUA_API void -luaL_pushresult(luaL_Buffer *B) { - API.luaL_pushresult(B); -} - -LUA_API void -luaL_pushresultsize(luaL_Buffer *B, size_t sz) { - API.luaL_pushresultsize(B,sz); -} - -LUA_API char * -luaL_buffinitsize(lua_State *L, luaL_Buffer *B, size_t sz) { - return API.luaL_buffinitsize(L,B,sz); -} - - - -LUA_API -const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { - const char *ret; - va_list argp; - va_start(argp, fmt); - ret = API.lua_pushvfstring(L, fmt, argp); - va_end(argp); - return ret; -} - -LUA_API int -lua_gc (lua_State *L, int what, ...) { - va_list argp; - va_start(argp, what); - int p1 = va_arg(argp, int); - int p2 = va_arg(argp, int); - int p3 = va_arg(argp, int); - va_end(argp); - return API.lua_gc(L, what, p1, p2, p3); -} - -LUA_API int -luaL_error(lua_State *L, const char *fmt, ...) { - va_list argp; - va_start(argp, fmt); - luaL_where(L, 1); - lua_pushvfstring(L, fmt, argp); - va_end(argp); - lua_concat(L, 2); - return lua_error(L); -} - -static void -stub_luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { -} - -static void stub_lua_createtable (lua_State *L, int narr, int nrec) { -} - -static void stub_luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { -} - -struct extraspace { - struct lua_api * api; -}; - -LUA_API void -luaapi_init(lua_State *L) { - struct extraspace * ex = (struct extraspace *)lua_getextraspace(L); - struct lua_api * api = ex->api; - if (api->version == LUA_VERSION_NUM) { - API = *api; - return; - } - // stub for luaL_newlib - API.luaL_checkversion_ = stub_luaL_checkversion_; - API.lua_createtable = stub_lua_createtable; - API.luaL_setfuncs = stub_luaL_setfuncs; -} +// AUTO GENERATED by extlua.temp.c, DONT EDIT + +#include +#include +#include +#include +#include + +struct lua_api { + int version; + + lua_State * (*lua_newstate) (lua_Alloc f, void *ud, unsigned seed); + void (*lua_close) (lua_State *L); + lua_State * (*lua_newthread) (lua_State *L); + int (*lua_closethread) (lua_State *L, lua_State *from); + lua_CFunction (*lua_atpanic) (lua_State *L, lua_CFunction panicf); + lua_Number (*lua_version) (lua_State *L); + int (*lua_absindex) (lua_State *L, int idx); + int (*lua_gettop) (lua_State *L); + void (*lua_settop) (lua_State *L, int idx); + void (*lua_pushvalue) (lua_State *L, int idx); + void (*lua_rotate) (lua_State *L, int idx, int n); + void (*lua_copy) (lua_State *L, int fromidx, int toidx); + int (*lua_checkstack) (lua_State *L, int n); + void (*lua_xmove) (lua_State *from, lua_State *to, int n); + int (*lua_isnumber) (lua_State *L, int idx); + int (*lua_isstring) (lua_State *L, int idx); + int (*lua_iscfunction) (lua_State *L, int idx); + int (*lua_isinteger) (lua_State *L, int idx); + int (*lua_isuserdata) (lua_State *L, int idx); + int (*lua_type) (lua_State *L, int idx); + const char * (*lua_typename) (lua_State *L, int tp); + lua_Number (*lua_tonumberx) (lua_State *L, int idx, int *isnum); + lua_Integer (*lua_tointegerx) (lua_State *L, int idx, int *isnum); + int (*lua_toboolean) (lua_State *L, int idx); + const char * (*lua_tolstring) (lua_State *L, int idx, size_t *len); + lua_Unsigned (*lua_rawlen) (lua_State *L, int idx); + lua_CFunction (*lua_tocfunction) (lua_State *L, int idx); + void * (*lua_touserdata) (lua_State *L, int idx); + lua_State * (*lua_tothread) (lua_State *L, int idx); + const void * (*lua_topointer) (lua_State *L, int idx); + void (*lua_arith) (lua_State *L, int op); + int (*lua_rawequal) (lua_State *L, int idx1, int idx2); + int (*lua_compare) (lua_State *L, int idx1, int idx2, int op); + void (*lua_pushnil) (lua_State *L); + void (*lua_pushnumber) (lua_State *L, lua_Number n); + void (*lua_pushinteger) (lua_State *L, lua_Integer n); + const char * (*lua_pushlstring) (lua_State *L, const char *s, size_t len); + const char * (*lua_pushexternalstring) (lua_State *L, + const char *s, size_t len, lua_Alloc falloc, void *ud); + const char * (*lua_pushstring) (lua_State *L, const char *s); + const char * (*lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); + void (*lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); + void (*lua_pushboolean) (lua_State *L, int b); + void (*lua_pushlightuserdata) (lua_State *L, void *p); + int (*lua_pushthread) (lua_State *L); + int (*lua_getglobal) (lua_State *L, const char *name); + int (*lua_gettable) (lua_State *L, int idx); + int (*lua_getfield) (lua_State *L, int idx, const char *k); + int (*lua_geti) (lua_State *L, int idx, lua_Integer n); + int (*lua_rawget) (lua_State *L, int idx); + int (*lua_rawgeti) (lua_State *L, int idx, lua_Integer n); + int (*lua_rawgetp) (lua_State *L, int idx, const void *p); + void (*lua_createtable) (lua_State *L, int narr, int nrec); + void * (*lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); + int (*lua_getmetatable) (lua_State *L, int objindex); + int (*lua_getiuservalue) (lua_State *L, int idx, int n); + void (*lua_setglobal) (lua_State *L, const char *name); + void (*lua_settable) (lua_State *L, int idx); + void (*lua_setfield) (lua_State *L, int idx, const char *k); + void (*lua_seti) (lua_State *L, int idx, lua_Integer n); + void (*lua_rawset) (lua_State *L, int idx); + void (*lua_rawseti) (lua_State *L, int idx, lua_Integer n); + void (*lua_rawsetp) (lua_State *L, int idx, const void *p); + int (*lua_setmetatable) (lua_State *L, int objindex); + int (*lua_setiuservalue) (lua_State *L, int idx, int n); + void (*lua_callk) (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k); + int (*lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k); + int (*lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname, const char *mode); + int (*lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); + int (*lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k); + int (*lua_resume) (lua_State *L, lua_State *from, int narg, + int *nres); + int (*lua_status) (lua_State *L); + int (*lua_isyieldable) (lua_State *L); + void (*lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud); + void (*lua_warning) (lua_State *L, const char *msg, int tocont); + int (*lua_error) (lua_State *L); + int (*lua_next) (lua_State *L, int idx); + void (*lua_concat) (lua_State *L, int n); + void (*lua_len) (lua_State *L, int idx); + unsigned (*lua_numbertocstring) (lua_State *L, int idx, char *buff); + size_t (*lua_stringtonumber) (lua_State *L, const char *s); + lua_Alloc (*lua_getallocf) (lua_State *L, void **ud); + void (*lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); + void (*lua_toclose) (lua_State *L, int idx); + void (*lua_closeslot) (lua_State *L, int idx); + int (*lua_getstack) (lua_State *L, int level, lua_Debug *ar); + int (*lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); + const char * (*lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); + const char * (*lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); + const char * (*lua_getupvalue) (lua_State *L, int funcindex, int n); + const char * (*lua_setupvalue) (lua_State *L, int funcindex, int n); + void * (*lua_upvalueid) (lua_State *L, int fidx, int n); + void (*lua_upvaluejoin) (lua_State *L, int fidx1, int n1, + int fidx2, int n2); + void (*lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); + lua_Hook (*lua_gethook) (lua_State *L); + int (*lua_gethookmask) (lua_State *L); + int (*lua_gethookcount) (lua_State *L); + void (*luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); + int (*luaL_getmetafield) (lua_State *L, int obj, const char *e); + int (*luaL_callmeta) (lua_State *L, int obj, const char *e); + const char * (*luaL_tolstring) (lua_State *L, int idx, size_t *len); + int (*luaL_argerror) (lua_State *L, int arg, const char *extramsg); + int (*luaL_typeerror) (lua_State *L, int arg, const char *tname); + const char * (*luaL_checklstring) (lua_State *L, int arg, + size_t *l); + const char * (*luaL_optlstring) (lua_State *L, int arg, + const char *def, size_t *l); + lua_Number (*luaL_checknumber) (lua_State *L, int arg); + lua_Number (*luaL_optnumber) (lua_State *L, int arg, lua_Number def); + lua_Integer (*luaL_checkinteger) (lua_State *L, int arg); + lua_Integer (*luaL_optinteger) (lua_State *L, int arg, + lua_Integer def); + void (*luaL_checkstack) (lua_State *L, int sz, const char *msg); + void (*luaL_checktype) (lua_State *L, int arg, int t); + void (*luaL_checkany) (lua_State *L, int arg); + int (*luaL_newmetatable) (lua_State *L, const char *tname); + void (*luaL_setmetatable) (lua_State *L, const char *tname); + void * (*luaL_testudata) (lua_State *L, int ud, const char *tname); + void * (*luaL_checkudata) (lua_State *L, int ud, const char *tname); + void (*luaL_where) (lua_State *L, int lvl); + int (*luaL_checkoption) (lua_State *L, int arg, const char *def, + const char *const lst[]); + int (*luaL_fileresult) (lua_State *L, int stat, const char *fname); + int (*luaL_execresult) (lua_State *L, int stat); + void * (*luaL_alloc) (void *ud, void *ptr, size_t osize, + size_t nsize); + int (*luaL_ref) (lua_State *L, int t); + void (*luaL_unref) (lua_State *L, int t, int ref); + int (*luaL_loadfilex) (lua_State *L, const char *filename, + const char *mode); + int (*luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode); + int (*luaL_loadstring) (lua_State *L, const char *s); + lua_State * (*luaL_newstate) (void); + unsigned (*luaL_makeseed) (lua_State *L); + lua_Integer (*luaL_len) (lua_State *L, int idx); + void (*luaL_addgsub) (luaL_Buffer *b, const char *s, + const char *p, const char *r); + const char * (*luaL_gsub) (lua_State *L, const char *s, + const char *p, const char *r); + void (*luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); + int (*luaL_getsubtable) (lua_State *L, int idx, const char *fname); + void (*luaL_traceback) (lua_State *L, lua_State *L1, + const char *msg, int level); + void (*luaL_requiref) (lua_State *L, const char *modname, + lua_CFunction openf, int glb); + void (*luaL_buffinit) (lua_State *L, luaL_Buffer *B); + char * (*luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); + void (*luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); + void (*luaL_addstring) (luaL_Buffer *B, const char *s); + void (*luaL_addvalue) (luaL_Buffer *B); + void (*luaL_pushresult) (luaL_Buffer *B); + void (*luaL_pushresultsize) (luaL_Buffer *B, size_t sz); + char * (*luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); + int (*lua_gc) (lua_State *L, int what, ...); +}; + +static struct lua_api API; + +LUA_API lua_State * +lua_newstate(lua_Alloc f, void *ud, unsigned seed) { + return API.lua_newstate(f,ud,seed); +} + +LUA_API void +lua_close(lua_State *L) { + API.lua_close(L); +} + +LUA_API lua_State * +lua_newthread(lua_State *L) { + return API.lua_newthread(L); +} + +LUA_API int +lua_closethread(lua_State *L, lua_State *from) { + return API.lua_closethread(L,from); +} + +LUA_API lua_CFunction +lua_atpanic(lua_State *L, lua_CFunction panicf) { + return API.lua_atpanic(L,panicf); +} + +LUA_API lua_Number +lua_version(lua_State *L) { + return API.lua_version(L); +} + +LUA_API int +lua_absindex(lua_State *L, int idx) { + return API.lua_absindex(L,idx); +} + +LUA_API int +lua_gettop(lua_State *L) { + return API.lua_gettop(L); +} + +LUA_API void +lua_settop(lua_State *L, int idx) { + API.lua_settop(L,idx); +} + +LUA_API void +lua_pushvalue(lua_State *L, int idx) { + API.lua_pushvalue(L,idx); +} + +LUA_API void +lua_rotate(lua_State *L, int idx, int n) { + API.lua_rotate(L,idx,n); +} + +LUA_API void +lua_copy(lua_State *L, int fromidx, int toidx) { + API.lua_copy(L,fromidx,toidx); +} + +LUA_API int +lua_checkstack(lua_State *L, int n) { + return API.lua_checkstack(L,n); +} + +LUA_API void +lua_xmove(lua_State *from, lua_State *to, int n) { + API.lua_xmove(from,to,n); +} + +LUA_API int +lua_isnumber(lua_State *L, int idx) { + return API.lua_isnumber(L,idx); +} + +LUA_API int +lua_isstring(lua_State *L, int idx) { + return API.lua_isstring(L,idx); +} + +LUA_API int +lua_iscfunction(lua_State *L, int idx) { + return API.lua_iscfunction(L,idx); +} + +LUA_API int +lua_isinteger(lua_State *L, int idx) { + return API.lua_isinteger(L,idx); +} + +LUA_API int +lua_isuserdata(lua_State *L, int idx) { + return API.lua_isuserdata(L,idx); +} + +LUA_API int +lua_type(lua_State *L, int idx) { + return API.lua_type(L,idx); +} + +LUA_API const char * +lua_typename(lua_State *L, int tp) { + return API.lua_typename(L,tp); +} + +LUA_API lua_Number +lua_tonumberx(lua_State *L, int idx, int *isnum) { + return API.lua_tonumberx(L,idx,isnum); +} + +LUA_API lua_Integer +lua_tointegerx(lua_State *L, int idx, int *isnum) { + return API.lua_tointegerx(L,idx,isnum); +} + +LUA_API int +lua_toboolean(lua_State *L, int idx) { + return API.lua_toboolean(L,idx); +} + +LUA_API const char * +lua_tolstring(lua_State *L, int idx, size_t *len) { + return API.lua_tolstring(L,idx,len); +} + +LUA_API lua_Unsigned +lua_rawlen(lua_State *L, int idx) { + return API.lua_rawlen(L,idx); +} + +LUA_API lua_CFunction +lua_tocfunction(lua_State *L, int idx) { + return API.lua_tocfunction(L,idx); +} + +LUA_API void * +lua_touserdata(lua_State *L, int idx) { + return API.lua_touserdata(L,idx); +} + +LUA_API lua_State * +lua_tothread(lua_State *L, int idx) { + return API.lua_tothread(L,idx); +} + +LUA_API const void * +lua_topointer(lua_State *L, int idx) { + return API.lua_topointer(L,idx); +} + +LUA_API void +lua_arith(lua_State *L, int op) { + API.lua_arith(L,op); +} + +LUA_API int +lua_rawequal(lua_State *L, int idx1, int idx2) { + return API.lua_rawequal(L,idx1,idx2); +} + +LUA_API int +lua_compare(lua_State *L, int idx1, int idx2, int op) { + return API.lua_compare(L,idx1,idx2,op); +} + +LUA_API void +lua_pushnil(lua_State *L) { + API.lua_pushnil(L); +} + +LUA_API void +lua_pushnumber(lua_State *L, lua_Number n) { + API.lua_pushnumber(L,n); +} + +LUA_API void +lua_pushinteger(lua_State *L, lua_Integer n) { + API.lua_pushinteger(L,n); +} + +LUA_API const char * +lua_pushlstring(lua_State *L, const char *s, size_t len) { + return API.lua_pushlstring(L,s,len); +} + +LUA_API const char * +lua_pushexternalstring(lua_State *L, + const char *s, size_t len, lua_Alloc falloc, void *ud) { + return API.lua_pushexternalstring(L,s,len,falloc,ud); +} + +LUA_API const char * +lua_pushstring(lua_State *L, const char *s) { + return API.lua_pushstring(L,s); +} + +LUA_API const char * +lua_pushvfstring(lua_State *L, const char *fmt, + va_list argp) { + return API.lua_pushvfstring(L,fmt,argp); +} + +LUA_API void +lua_pushcclosure(lua_State *L, lua_CFunction fn, int n) { + API.lua_pushcclosure(L,fn,n); +} + +LUA_API void +lua_pushboolean(lua_State *L, int b) { + API.lua_pushboolean(L,b); +} + +LUA_API void +lua_pushlightuserdata(lua_State *L, void *p) { + API.lua_pushlightuserdata(L,p); +} + +LUA_API int +lua_pushthread(lua_State *L) { + return API.lua_pushthread(L); +} + +LUA_API int +lua_getglobal(lua_State *L, const char *name) { + return API.lua_getglobal(L,name); +} + +LUA_API int +lua_gettable(lua_State *L, int idx) { + return API.lua_gettable(L,idx); +} + +LUA_API int +lua_getfield(lua_State *L, int idx, const char *k) { + return API.lua_getfield(L,idx,k); +} + +LUA_API int +lua_geti(lua_State *L, int idx, lua_Integer n) { + return API.lua_geti(L,idx,n); +} + +LUA_API int +lua_rawget(lua_State *L, int idx) { + return API.lua_rawget(L,idx); +} + +LUA_API int +lua_rawgeti(lua_State *L, int idx, lua_Integer n) { + return API.lua_rawgeti(L,idx,n); +} + +LUA_API int +lua_rawgetp(lua_State *L, int idx, const void *p) { + return API.lua_rawgetp(L,idx,p); +} + +LUA_API void +lua_createtable(lua_State *L, int narr, int nrec) { + API.lua_createtable(L,narr,nrec); +} + +LUA_API void * +lua_newuserdatauv(lua_State *L, size_t sz, int nuvalue) { + return API.lua_newuserdatauv(L,sz,nuvalue); +} + +LUA_API int +lua_getmetatable(lua_State *L, int objindex) { + return API.lua_getmetatable(L,objindex); +} + +LUA_API int +lua_getiuservalue(lua_State *L, int idx, int n) { + return API.lua_getiuservalue(L,idx,n); +} + +LUA_API void +lua_setglobal(lua_State *L, const char *name) { + API.lua_setglobal(L,name); +} + +LUA_API void +lua_settable(lua_State *L, int idx) { + API.lua_settable(L,idx); +} + +LUA_API void +lua_setfield(lua_State *L, int idx, const char *k) { + API.lua_setfield(L,idx,k); +} + +LUA_API void +lua_seti(lua_State *L, int idx, lua_Integer n) { + API.lua_seti(L,idx,n); +} + +LUA_API void +lua_rawset(lua_State *L, int idx) { + API.lua_rawset(L,idx); +} + +LUA_API void +lua_rawseti(lua_State *L, int idx, lua_Integer n) { + API.lua_rawseti(L,idx,n); +} + +LUA_API void +lua_rawsetp(lua_State *L, int idx, const void *p) { + API.lua_rawsetp(L,idx,p); +} + +LUA_API int +lua_setmetatable(lua_State *L, int objindex) { + return API.lua_setmetatable(L,objindex); +} + +LUA_API int +lua_setiuservalue(lua_State *L, int idx, int n) { + return API.lua_setiuservalue(L,idx,n); +} + +LUA_API void +lua_callk(lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k) { + API.lua_callk(L,nargs,nresults,ctx,k); +} + +LUA_API int +lua_pcallk(lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k) { + return API.lua_pcallk(L,nargs,nresults,errfunc,ctx,k); +} + +LUA_API int +lua_load(lua_State *L, lua_Reader reader, void *dt, + const char *chunkname, const char *mode) { + return API.lua_load(L,reader,dt,chunkname,mode); +} + +LUA_API int +lua_dump(lua_State *L, lua_Writer writer, void *data, int strip) { + return API.lua_dump(L,writer,data,strip); +} + +LUA_API int +lua_yieldk(lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k) { + return API.lua_yieldk(L,nresults,ctx,k); +} + +LUA_API int +lua_resume(lua_State *L, lua_State *from, int narg, + int *nres) { + return API.lua_resume(L,from,narg,nres); +} + +LUA_API int +lua_status(lua_State *L) { + return API.lua_status(L); +} + +LUA_API int +lua_isyieldable(lua_State *L) { + return API.lua_isyieldable(L); +} + +LUA_API void +lua_setwarnf(lua_State *L, lua_WarnFunction f, void *ud) { + API.lua_setwarnf(L,f,ud); +} + +LUA_API void +lua_warning(lua_State *L, const char *msg, int tocont) { + API.lua_warning(L,msg,tocont); +} + +LUA_API int +lua_error(lua_State *L) { + return API.lua_error(L); +} + +LUA_API int +lua_next(lua_State *L, int idx) { + return API.lua_next(L,idx); +} + +LUA_API void +lua_concat(lua_State *L, int n) { + API.lua_concat(L,n); +} + +LUA_API void +lua_len(lua_State *L, int idx) { + API.lua_len(L,idx); +} + +LUA_API unsigned +lua_numbertocstring(lua_State *L, int idx, char *buff) { + return API.lua_numbertocstring(L,idx,buff); +} + +LUA_API size_t +lua_stringtonumber(lua_State *L, const char *s) { + return API.lua_stringtonumber(L,s); +} + +LUA_API lua_Alloc +lua_getallocf(lua_State *L, void **ud) { + return API.lua_getallocf(L,ud); +} + +LUA_API void +lua_setallocf(lua_State *L, lua_Alloc f, void *ud) { + API.lua_setallocf(L,f,ud); +} + +LUA_API void +lua_toclose(lua_State *L, int idx) { + API.lua_toclose(L,idx); +} + +LUA_API void +lua_closeslot(lua_State *L, int idx) { + API.lua_closeslot(L,idx); +} + +LUA_API int +lua_getstack(lua_State *L, int level, lua_Debug *ar) { + return API.lua_getstack(L,level,ar); +} + +LUA_API int +lua_getinfo(lua_State *L, const char *what, lua_Debug *ar) { + return API.lua_getinfo(L,what,ar); +} + +LUA_API const char * +lua_getlocal(lua_State *L, const lua_Debug *ar, int n) { + return API.lua_getlocal(L,ar,n); +} + +LUA_API const char * +lua_setlocal(lua_State *L, const lua_Debug *ar, int n) { + return API.lua_setlocal(L,ar,n); +} + +LUA_API const char * +lua_getupvalue(lua_State *L, int funcindex, int n) { + return API.lua_getupvalue(L,funcindex,n); +} + +LUA_API const char * +lua_setupvalue(lua_State *L, int funcindex, int n) { + return API.lua_setupvalue(L,funcindex,n); +} + +LUA_API void * +lua_upvalueid(lua_State *L, int fidx, int n) { + return API.lua_upvalueid(L,fidx,n); +} + +LUA_API void +lua_upvaluejoin(lua_State *L, int fidx1, int n1, + int fidx2, int n2) { + API.lua_upvaluejoin(L,fidx1,n1,fidx2,n2); +} + +LUA_API void +lua_sethook(lua_State *L, lua_Hook func, int mask, int count) { + API.lua_sethook(L,func,mask,count); +} + +LUA_API lua_Hook +lua_gethook(lua_State *L) { + return API.lua_gethook(L); +} + +LUA_API int +lua_gethookmask(lua_State *L) { + return API.lua_gethookmask(L); +} + +LUA_API int +lua_gethookcount(lua_State *L) { + return API.lua_gethookcount(L); +} + +LUA_API void +luaL_checkversion_(lua_State *L, lua_Number ver, size_t sz) { + API.luaL_checkversion_(L,ver,sz); +} + +LUA_API int +luaL_getmetafield(lua_State *L, int obj, const char *e) { + return API.luaL_getmetafield(L,obj,e); +} + +LUA_API int +luaL_callmeta(lua_State *L, int obj, const char *e) { + return API.luaL_callmeta(L,obj,e); +} + +LUA_API const char * +luaL_tolstring(lua_State *L, int idx, size_t *len) { + return API.luaL_tolstring(L,idx,len); +} + +LUA_API int +luaL_argerror(lua_State *L, int arg, const char *extramsg) { + return API.luaL_argerror(L,arg,extramsg); +} + +LUA_API int +luaL_typeerror(lua_State *L, int arg, const char *tname) { + return API.luaL_typeerror(L,arg,tname); +} + +LUA_API const char * +luaL_checklstring(lua_State *L, int arg, + size_t *l) { + return API.luaL_checklstring(L,arg,l); +} + +LUA_API const char * +luaL_optlstring(lua_State *L, int arg, + const char *def, size_t *l) { + return API.luaL_optlstring(L,arg,def,l); +} + +LUA_API lua_Number +luaL_checknumber(lua_State *L, int arg) { + return API.luaL_checknumber(L,arg); +} + +LUA_API lua_Number +luaL_optnumber(lua_State *L, int arg, lua_Number def) { + return API.luaL_optnumber(L,arg,def); +} + +LUA_API lua_Integer +luaL_checkinteger(lua_State *L, int arg) { + return API.luaL_checkinteger(L,arg); +} + +LUA_API lua_Integer +luaL_optinteger(lua_State *L, int arg, + lua_Integer def) { + return API.luaL_optinteger(L,arg,def); +} + +LUA_API void +luaL_checkstack(lua_State *L, int sz, const char *msg) { + API.luaL_checkstack(L,sz,msg); +} + +LUA_API void +luaL_checktype(lua_State *L, int arg, int t) { + API.luaL_checktype(L,arg,t); +} + +LUA_API void +luaL_checkany(lua_State *L, int arg) { + API.luaL_checkany(L,arg); +} + +LUA_API int +luaL_newmetatable(lua_State *L, const char *tname) { + return API.luaL_newmetatable(L,tname); +} + +LUA_API void +luaL_setmetatable(lua_State *L, const char *tname) { + API.luaL_setmetatable(L,tname); +} + +LUA_API void * +luaL_testudata(lua_State *L, int ud, const char *tname) { + return API.luaL_testudata(L,ud,tname); +} + +LUA_API void * +luaL_checkudata(lua_State *L, int ud, const char *tname) { + return API.luaL_checkudata(L,ud,tname); +} + +LUA_API void +luaL_where(lua_State *L, int lvl) { + API.luaL_where(L,lvl); +} + +LUA_API int +luaL_checkoption(lua_State *L, int arg, const char *def, + const char *const lst[]) { + return API.luaL_checkoption(L,arg,def,lst); +} + +LUA_API int +luaL_fileresult(lua_State *L, int stat, const char *fname) { + return API.luaL_fileresult(L,stat,fname); +} + +LUA_API int +luaL_execresult(lua_State *L, int stat) { + return API.luaL_execresult(L,stat); +} + +LUA_API void * +luaL_alloc(void *ud, void *ptr, size_t osize, + size_t nsize) { + return API.luaL_alloc(ud,ptr,osize,nsize); +} + +LUA_API int +luaL_ref(lua_State *L, int t) { + return API.luaL_ref(L,t); +} + +LUA_API void +luaL_unref(lua_State *L, int t, int ref) { + API.luaL_unref(L,t,ref); +} + +LUA_API int +luaL_loadfilex(lua_State *L, const char *filename, + const char *mode) { + return API.luaL_loadfilex(L,filename,mode); +} + +LUA_API int +luaL_loadbufferx(lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode) { + return API.luaL_loadbufferx(L,buff,sz,name,mode); +} + +LUA_API int +luaL_loadstring(lua_State *L, const char *s) { + return API.luaL_loadstring(L,s); +} + +LUA_API lua_State * +luaL_newstate(void) { + return API.luaL_newstate(); +} + +LUA_API unsigned +luaL_makeseed(lua_State *L) { + return API.luaL_makeseed(L); +} + +LUA_API lua_Integer +luaL_len(lua_State *L, int idx) { + return API.luaL_len(L,idx); +} + +LUA_API void +luaL_addgsub(luaL_Buffer *b, const char *s, + const char *p, const char *r) { + API.luaL_addgsub(b,s,p,r); +} + +LUA_API const char * +luaL_gsub(lua_State *L, const char *s, + const char *p, const char *r) { + return API.luaL_gsub(L,s,p,r); +} + +LUA_API void +luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) { + API.luaL_setfuncs(L,l,nup); +} + +LUA_API int +luaL_getsubtable(lua_State *L, int idx, const char *fname) { + return API.luaL_getsubtable(L,idx,fname); +} + +LUA_API void +luaL_traceback(lua_State *L, lua_State *L1, + const char *msg, int level) { + API.luaL_traceback(L,L1,msg,level); +} + +LUA_API void +luaL_requiref(lua_State *L, const char *modname, + lua_CFunction openf, int glb) { + API.luaL_requiref(L,modname,openf,glb); +} + +LUA_API void +luaL_buffinit(lua_State *L, luaL_Buffer *B) { + API.luaL_buffinit(L,B); +} + +LUA_API char * +luaL_prepbuffsize(luaL_Buffer *B, size_t sz) { + return API.luaL_prepbuffsize(B,sz); +} + +LUA_API void +luaL_addlstring(luaL_Buffer *B, const char *s, size_t l) { + API.luaL_addlstring(B,s,l); +} + +LUA_API void +luaL_addstring(luaL_Buffer *B, const char *s) { + API.luaL_addstring(B,s); +} + +LUA_API void +luaL_addvalue(luaL_Buffer *B) { + API.luaL_addvalue(B); +} + +LUA_API void +luaL_pushresult(luaL_Buffer *B) { + API.luaL_pushresult(B); +} + +LUA_API void +luaL_pushresultsize(luaL_Buffer *B, size_t sz) { + API.luaL_pushresultsize(B,sz); +} + +LUA_API char * +luaL_buffinitsize(lua_State *L, luaL_Buffer *B, size_t sz) { + return API.luaL_buffinitsize(L,B,sz); +} + + + +LUA_API +const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { + const char *ret; + va_list argp; + va_start(argp, fmt); + ret = API.lua_pushvfstring(L, fmt, argp); + va_end(argp); + return ret; +} + +LUA_API int +lua_gc (lua_State *L, int what, ...) { + va_list argp; + va_start(argp, what); + int p1 = va_arg(argp, int); + int p2 = va_arg(argp, int); + int p3 = va_arg(argp, int); + va_end(argp); + return API.lua_gc(L, what, p1, p2, p3); +} + +LUA_API int +luaL_error(lua_State *L, const char *fmt, ...) { + va_list argp; + va_start(argp, fmt); + luaL_where(L, 1); + lua_pushvfstring(L, fmt, argp); + va_end(argp); + lua_concat(L, 2); + return lua_error(L); +} + +static void +stub_luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { +} + +static void stub_lua_createtable (lua_State *L, int narr, int nrec) { +} + +static void stub_luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { +} + +struct sokol_api; +struct soluna_api; + +struct extlua_apis { + struct lua_api * lua; + struct sokol_api * sokol; + struct soluna_api * soluna; +}; + +LUA_API void +luaapi_init(lua_State *L) { + struct extlua_apis *apis = *(struct extlua_apis **)lua_getextraspace(L); + struct lua_api * api = apis->lua; + if (api->version == LUA_VERSION_NUM) { + API = *api; + return; + } + // stub for luaL_newlib + API.luaL_checkversion_ = stub_luaL_checkversion_; + API.lua_createtable = stub_lua_createtable; + API.luaL_setfuncs = stub_luaL_setfuncs; +} diff --git a/extlua/extlua.temp.c b/extlua/extlua.temp.c index 873da60..4562d88 100644 --- a/extlua/extlua.temp.c +++ b/extlua/extlua.temp.c @@ -56,14 +56,19 @@ static void stub_lua_createtable (lua_State *L, int narr, int nrec) { static void stub_luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { } -struct extraspace { - struct lua_api * api; +struct sokol_api; +struct soluna_api; + +struct extlua_apis { + struct lua_api * lua; + struct sokol_api * sokol; + struct soluna_api * soluna; }; LUA_API void luaapi_init(lua_State *L) { - struct extraspace * ex = (struct extraspace *)lua_getextraspace(L); - struct lua_api * api = ex->api; + struct extlua_apis *apis = *(struct extlua_apis **)lua_getextraspace(L); + struct lua_api * api = apis->lua; if (api->version == LUA_VERSION_NUM) { API = *api; return; diff --git a/extlua/extlua_impl.c b/extlua/extlua_impl.c index 6200940..53342f1 100644 --- a/extlua/extlua_impl.c +++ b/extlua/extlua_impl.c @@ -1,323 +1,323 @@ -// AUTO GENERATED by extlua_impl.temp.c, DONT EDIT - -#include -#include - -struct lua_api { - int version; - - lua_State * (*lua_newstate) (lua_Alloc f, void *ud, unsigned seed); - void (*lua_close) (lua_State *L); - lua_State * (*lua_newthread) (lua_State *L); - int (*lua_closethread) (lua_State *L, lua_State *from); - lua_CFunction (*lua_atpanic) (lua_State *L, lua_CFunction panicf); - lua_Number (*lua_version) (lua_State *L); - int (*lua_absindex) (lua_State *L, int idx); - int (*lua_gettop) (lua_State *L); - void (*lua_settop) (lua_State *L, int idx); - void (*lua_pushvalue) (lua_State *L, int idx); - void (*lua_rotate) (lua_State *L, int idx, int n); - void (*lua_copy) (lua_State *L, int fromidx, int toidx); - int (*lua_checkstack) (lua_State *L, int n); - void (*lua_xmove) (lua_State *from, lua_State *to, int n); - int (*lua_isnumber) (lua_State *L, int idx); - int (*lua_isstring) (lua_State *L, int idx); - int (*lua_iscfunction) (lua_State *L, int idx); - int (*lua_isinteger) (lua_State *L, int idx); - int (*lua_isuserdata) (lua_State *L, int idx); - int (*lua_type) (lua_State *L, int idx); - const char * (*lua_typename) (lua_State *L, int tp); - lua_Number (*lua_tonumberx) (lua_State *L, int idx, int *isnum); - lua_Integer (*lua_tointegerx) (lua_State *L, int idx, int *isnum); - int (*lua_toboolean) (lua_State *L, int idx); - const char * (*lua_tolstring) (lua_State *L, int idx, size_t *len); - lua_Unsigned (*lua_rawlen) (lua_State *L, int idx); - lua_CFunction (*lua_tocfunction) (lua_State *L, int idx); - void * (*lua_touserdata) (lua_State *L, int idx); - lua_State * (*lua_tothread) (lua_State *L, int idx); - const void * (*lua_topointer) (lua_State *L, int idx); - void (*lua_arith) (lua_State *L, int op); - int (*lua_rawequal) (lua_State *L, int idx1, int idx2); - int (*lua_compare) (lua_State *L, int idx1, int idx2, int op); - void (*lua_pushnil) (lua_State *L); - void (*lua_pushnumber) (lua_State *L, lua_Number n); - void (*lua_pushinteger) (lua_State *L, lua_Integer n); - const char * (*lua_pushlstring) (lua_State *L, const char *s, size_t len); - const char * (*lua_pushexternalstring) (lua_State *L, - const char *s, size_t len, lua_Alloc falloc, void *ud); - const char * (*lua_pushstring) (lua_State *L, const char *s); - const char * (*lua_pushvfstring) (lua_State *L, const char *fmt, - va_list argp); - void (*lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); - void (*lua_pushboolean) (lua_State *L, int b); - void (*lua_pushlightuserdata) (lua_State *L, void *p); - int (*lua_pushthread) (lua_State *L); - int (*lua_getglobal) (lua_State *L, const char *name); - int (*lua_gettable) (lua_State *L, int idx); - int (*lua_getfield) (lua_State *L, int idx, const char *k); - int (*lua_geti) (lua_State *L, int idx, lua_Integer n); - int (*lua_rawget) (lua_State *L, int idx); - int (*lua_rawgeti) (lua_State *L, int idx, lua_Integer n); - int (*lua_rawgetp) (lua_State *L, int idx, const void *p); - void (*lua_createtable) (lua_State *L, int narr, int nrec); - void * (*lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); - int (*lua_getmetatable) (lua_State *L, int objindex); - int (*lua_getiuservalue) (lua_State *L, int idx, int n); - void (*lua_setglobal) (lua_State *L, const char *name); - void (*lua_settable) (lua_State *L, int idx); - void (*lua_setfield) (lua_State *L, int idx, const char *k); - void (*lua_seti) (lua_State *L, int idx, lua_Integer n); - void (*lua_rawset) (lua_State *L, int idx); - void (*lua_rawseti) (lua_State *L, int idx, lua_Integer n); - void (*lua_rawsetp) (lua_State *L, int idx, const void *p); - int (*lua_setmetatable) (lua_State *L, int objindex); - int (*lua_setiuservalue) (lua_State *L, int idx, int n); - void (*lua_callk) (lua_State *L, int nargs, int nresults, - lua_KContext ctx, lua_KFunction k); - int (*lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, - lua_KContext ctx, lua_KFunction k); - int (*lua_load) (lua_State *L, lua_Reader reader, void *dt, - const char *chunkname, const char *mode); - int (*lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); - int (*lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, - lua_KFunction k); - int (*lua_resume) (lua_State *L, lua_State *from, int narg, - int *nres); - int (*lua_status) (lua_State *L); - int (*lua_isyieldable) (lua_State *L); - void (*lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud); - void (*lua_warning) (lua_State *L, const char *msg, int tocont); - int (*lua_error) (lua_State *L); - int (*lua_next) (lua_State *L, int idx); - void (*lua_concat) (lua_State *L, int n); - void (*lua_len) (lua_State *L, int idx); - unsigned (*lua_numbertocstring) (lua_State *L, int idx, char *buff); - size_t (*lua_stringtonumber) (lua_State *L, const char *s); - lua_Alloc (*lua_getallocf) (lua_State *L, void **ud); - void (*lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); - void (*lua_toclose) (lua_State *L, int idx); - void (*lua_closeslot) (lua_State *L, int idx); - int (*lua_getstack) (lua_State *L, int level, lua_Debug *ar); - int (*lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); - const char * (*lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); - const char * (*lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); - const char * (*lua_getupvalue) (lua_State *L, int funcindex, int n); - const char * (*lua_setupvalue) (lua_State *L, int funcindex, int n); - void * (*lua_upvalueid) (lua_State *L, int fidx, int n); - void (*lua_upvaluejoin) (lua_State *L, int fidx1, int n1, - int fidx2, int n2); - void (*lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); - lua_Hook (*lua_gethook) (lua_State *L); - int (*lua_gethookmask) (lua_State *L); - int (*lua_gethookcount) (lua_State *L); - void (*luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); - int (*luaL_getmetafield) (lua_State *L, int obj, const char *e); - int (*luaL_callmeta) (lua_State *L, int obj, const char *e); - const char * (*luaL_tolstring) (lua_State *L, int idx, size_t *len); - int (*luaL_argerror) (lua_State *L, int arg, const char *extramsg); - int (*luaL_typeerror) (lua_State *L, int arg, const char *tname); - const char * (*luaL_checklstring) (lua_State *L, int arg, - size_t *l); - const char * (*luaL_optlstring) (lua_State *L, int arg, - const char *def, size_t *l); - lua_Number (*luaL_checknumber) (lua_State *L, int arg); - lua_Number (*luaL_optnumber) (lua_State *L, int arg, lua_Number def); - lua_Integer (*luaL_checkinteger) (lua_State *L, int arg); - lua_Integer (*luaL_optinteger) (lua_State *L, int arg, - lua_Integer def); - void (*luaL_checkstack) (lua_State *L, int sz, const char *msg); - void (*luaL_checktype) (lua_State *L, int arg, int t); - void (*luaL_checkany) (lua_State *L, int arg); - int (*luaL_newmetatable) (lua_State *L, const char *tname); - void (*luaL_setmetatable) (lua_State *L, const char *tname); - void * (*luaL_testudata) (lua_State *L, int ud, const char *tname); - void * (*luaL_checkudata) (lua_State *L, int ud, const char *tname); - void (*luaL_where) (lua_State *L, int lvl); - int (*luaL_checkoption) (lua_State *L, int arg, const char *def, - const char *const lst[]); - int (*luaL_fileresult) (lua_State *L, int stat, const char *fname); - int (*luaL_execresult) (lua_State *L, int stat); - void * (*luaL_alloc) (void *ud, void *ptr, size_t osize, - size_t nsize); - int (*luaL_ref) (lua_State *L, int t); - void (*luaL_unref) (lua_State *L, int t, int ref); - int (*luaL_loadfilex) (lua_State *L, const char *filename, - const char *mode); - int (*luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, - const char *name, const char *mode); - int (*luaL_loadstring) (lua_State *L, const char *s); - lua_State * (*luaL_newstate) (void); - unsigned (*luaL_makeseed) (lua_State *L); - lua_Integer (*luaL_len) (lua_State *L, int idx); - void (*luaL_addgsub) (luaL_Buffer *b, const char *s, - const char *p, const char *r); - const char * (*luaL_gsub) (lua_State *L, const char *s, - const char *p, const char *r); - void (*luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); - int (*luaL_getsubtable) (lua_State *L, int idx, const char *fname); - void (*luaL_traceback) (lua_State *L, lua_State *L1, - const char *msg, int level); - void (*luaL_requiref) (lua_State *L, const char *modname, - lua_CFunction openf, int glb); - void (*luaL_buffinit) (lua_State *L, luaL_Buffer *B); - char * (*luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); - void (*luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); - void (*luaL_addstring) (luaL_Buffer *B, const char *s); - void (*luaL_addvalue) (luaL_Buffer *B); - void (*luaL_pushresult) (luaL_Buffer *B); - void (*luaL_pushresultsize) (luaL_Buffer *B, size_t sz); - char * (*luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); - int (*lua_gc) (lua_State *L, int what, ...); -}; - -struct lua_api * -extlua_api() { - static struct lua_api api = { - LUA_VERSION_NUM, - - lua_newstate, - lua_close, - lua_newthread, - lua_closethread, - lua_atpanic, - lua_version, - lua_absindex, - lua_gettop, - lua_settop, - lua_pushvalue, - lua_rotate, - lua_copy, - lua_checkstack, - lua_xmove, - lua_isnumber, - lua_isstring, - lua_iscfunction, - lua_isinteger, - lua_isuserdata, - lua_type, - lua_typename, - lua_tonumberx, - lua_tointegerx, - lua_toboolean, - lua_tolstring, - lua_rawlen, - lua_tocfunction, - lua_touserdata, - lua_tothread, - lua_topointer, - lua_arith, - lua_rawequal, - lua_compare, - lua_pushnil, - lua_pushnumber, - lua_pushinteger, - lua_pushlstring, - lua_pushexternalstring, - lua_pushstring, - lua_pushvfstring, - lua_pushcclosure, - lua_pushboolean, - lua_pushlightuserdata, - lua_pushthread, - lua_getglobal, - lua_gettable, - lua_getfield, - lua_geti, - lua_rawget, - lua_rawgeti, - lua_rawgetp, - lua_createtable, - lua_newuserdatauv, - lua_getmetatable, - lua_getiuservalue, - lua_setglobal, - lua_settable, - lua_setfield, - lua_seti, - lua_rawset, - lua_rawseti, - lua_rawsetp, - lua_setmetatable, - lua_setiuservalue, - lua_callk, - lua_pcallk, - lua_load, - lua_dump, - lua_yieldk, - lua_resume, - lua_status, - lua_isyieldable, - lua_setwarnf, - lua_warning, - lua_error, - lua_next, - lua_concat, - lua_len, - lua_numbertocstring, - lua_stringtonumber, - lua_getallocf, - lua_setallocf, - lua_toclose, - lua_closeslot, - lua_getstack, - lua_getinfo, - lua_getlocal, - lua_setlocal, - lua_getupvalue, - lua_setupvalue, - lua_upvalueid, - lua_upvaluejoin, - lua_sethook, - lua_gethook, - lua_gethookmask, - lua_gethookcount, - luaL_checkversion_, - luaL_getmetafield, - luaL_callmeta, - luaL_tolstring, - luaL_argerror, - luaL_typeerror, - luaL_checklstring, - luaL_optlstring, - luaL_checknumber, - luaL_optnumber, - luaL_checkinteger, - luaL_optinteger, - luaL_checkstack, - luaL_checktype, - luaL_checkany, - luaL_newmetatable, - luaL_setmetatable, - luaL_testudata, - luaL_checkudata, - luaL_where, - luaL_checkoption, - luaL_fileresult, - luaL_execresult, - luaL_alloc, - luaL_ref, - luaL_unref, - luaL_loadfilex, - luaL_loadbufferx, - luaL_loadstring, - luaL_newstate, - luaL_makeseed, - luaL_len, - luaL_addgsub, - luaL_gsub, - luaL_setfuncs, - luaL_getsubtable, - luaL_traceback, - luaL_requiref, - luaL_buffinit, - luaL_prepbuffsize, - luaL_addlstring, - luaL_addstring, - luaL_addvalue, - luaL_pushresult, - luaL_pushresultsize, - luaL_buffinitsize, - lua_gc, - }; - return &api; -} +// AUTO GENERATED by extlua_impl.temp.c, DONT EDIT + +#include +#include + +struct lua_api { + int version; + + lua_State * (*lua_newstate) (lua_Alloc f, void *ud, unsigned seed); + void (*lua_close) (lua_State *L); + lua_State * (*lua_newthread) (lua_State *L); + int (*lua_closethread) (lua_State *L, lua_State *from); + lua_CFunction (*lua_atpanic) (lua_State *L, lua_CFunction panicf); + lua_Number (*lua_version) (lua_State *L); + int (*lua_absindex) (lua_State *L, int idx); + int (*lua_gettop) (lua_State *L); + void (*lua_settop) (lua_State *L, int idx); + void (*lua_pushvalue) (lua_State *L, int idx); + void (*lua_rotate) (lua_State *L, int idx, int n); + void (*lua_copy) (lua_State *L, int fromidx, int toidx); + int (*lua_checkstack) (lua_State *L, int n); + void (*lua_xmove) (lua_State *from, lua_State *to, int n); + int (*lua_isnumber) (lua_State *L, int idx); + int (*lua_isstring) (lua_State *L, int idx); + int (*lua_iscfunction) (lua_State *L, int idx); + int (*lua_isinteger) (lua_State *L, int idx); + int (*lua_isuserdata) (lua_State *L, int idx); + int (*lua_type) (lua_State *L, int idx); + const char * (*lua_typename) (lua_State *L, int tp); + lua_Number (*lua_tonumberx) (lua_State *L, int idx, int *isnum); + lua_Integer (*lua_tointegerx) (lua_State *L, int idx, int *isnum); + int (*lua_toboolean) (lua_State *L, int idx); + const char * (*lua_tolstring) (lua_State *L, int idx, size_t *len); + lua_Unsigned (*lua_rawlen) (lua_State *L, int idx); + lua_CFunction (*lua_tocfunction) (lua_State *L, int idx); + void * (*lua_touserdata) (lua_State *L, int idx); + lua_State * (*lua_tothread) (lua_State *L, int idx); + const void * (*lua_topointer) (lua_State *L, int idx); + void (*lua_arith) (lua_State *L, int op); + int (*lua_rawequal) (lua_State *L, int idx1, int idx2); + int (*lua_compare) (lua_State *L, int idx1, int idx2, int op); + void (*lua_pushnil) (lua_State *L); + void (*lua_pushnumber) (lua_State *L, lua_Number n); + void (*lua_pushinteger) (lua_State *L, lua_Integer n); + const char * (*lua_pushlstring) (lua_State *L, const char *s, size_t len); + const char * (*lua_pushexternalstring) (lua_State *L, + const char *s, size_t len, lua_Alloc falloc, void *ud); + const char * (*lua_pushstring) (lua_State *L, const char *s); + const char * (*lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); + void (*lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); + void (*lua_pushboolean) (lua_State *L, int b); + void (*lua_pushlightuserdata) (lua_State *L, void *p); + int (*lua_pushthread) (lua_State *L); + int (*lua_getglobal) (lua_State *L, const char *name); + int (*lua_gettable) (lua_State *L, int idx); + int (*lua_getfield) (lua_State *L, int idx, const char *k); + int (*lua_geti) (lua_State *L, int idx, lua_Integer n); + int (*lua_rawget) (lua_State *L, int idx); + int (*lua_rawgeti) (lua_State *L, int idx, lua_Integer n); + int (*lua_rawgetp) (lua_State *L, int idx, const void *p); + void (*lua_createtable) (lua_State *L, int narr, int nrec); + void * (*lua_newuserdatauv) (lua_State *L, size_t sz, int nuvalue); + int (*lua_getmetatable) (lua_State *L, int objindex); + int (*lua_getiuservalue) (lua_State *L, int idx, int n); + void (*lua_setglobal) (lua_State *L, const char *name); + void (*lua_settable) (lua_State *L, int idx); + void (*lua_setfield) (lua_State *L, int idx, const char *k); + void (*lua_seti) (lua_State *L, int idx, lua_Integer n); + void (*lua_rawset) (lua_State *L, int idx); + void (*lua_rawseti) (lua_State *L, int idx, lua_Integer n); + void (*lua_rawsetp) (lua_State *L, int idx, const void *p); + int (*lua_setmetatable) (lua_State *L, int objindex); + int (*lua_setiuservalue) (lua_State *L, int idx, int n); + void (*lua_callk) (lua_State *L, int nargs, int nresults, + lua_KContext ctx, lua_KFunction k); + int (*lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, + lua_KContext ctx, lua_KFunction k); + int (*lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname, const char *mode); + int (*lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); + int (*lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, + lua_KFunction k); + int (*lua_resume) (lua_State *L, lua_State *from, int narg, + int *nres); + int (*lua_status) (lua_State *L); + int (*lua_isyieldable) (lua_State *L); + void (*lua_setwarnf) (lua_State *L, lua_WarnFunction f, void *ud); + void (*lua_warning) (lua_State *L, const char *msg, int tocont); + int (*lua_error) (lua_State *L); + int (*lua_next) (lua_State *L, int idx); + void (*lua_concat) (lua_State *L, int n); + void (*lua_len) (lua_State *L, int idx); + unsigned (*lua_numbertocstring) (lua_State *L, int idx, char *buff); + size_t (*lua_stringtonumber) (lua_State *L, const char *s); + lua_Alloc (*lua_getallocf) (lua_State *L, void **ud); + void (*lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); + void (*lua_toclose) (lua_State *L, int idx); + void (*lua_closeslot) (lua_State *L, int idx); + int (*lua_getstack) (lua_State *L, int level, lua_Debug *ar); + int (*lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); + const char * (*lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); + const char * (*lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); + const char * (*lua_getupvalue) (lua_State *L, int funcindex, int n); + const char * (*lua_setupvalue) (lua_State *L, int funcindex, int n); + void * (*lua_upvalueid) (lua_State *L, int fidx, int n); + void (*lua_upvaluejoin) (lua_State *L, int fidx1, int n1, + int fidx2, int n2); + void (*lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); + lua_Hook (*lua_gethook) (lua_State *L); + int (*lua_gethookmask) (lua_State *L); + int (*lua_gethookcount) (lua_State *L); + void (*luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); + int (*luaL_getmetafield) (lua_State *L, int obj, const char *e); + int (*luaL_callmeta) (lua_State *L, int obj, const char *e); + const char * (*luaL_tolstring) (lua_State *L, int idx, size_t *len); + int (*luaL_argerror) (lua_State *L, int arg, const char *extramsg); + int (*luaL_typeerror) (lua_State *L, int arg, const char *tname); + const char * (*luaL_checklstring) (lua_State *L, int arg, + size_t *l); + const char * (*luaL_optlstring) (lua_State *L, int arg, + const char *def, size_t *l); + lua_Number (*luaL_checknumber) (lua_State *L, int arg); + lua_Number (*luaL_optnumber) (lua_State *L, int arg, lua_Number def); + lua_Integer (*luaL_checkinteger) (lua_State *L, int arg); + lua_Integer (*luaL_optinteger) (lua_State *L, int arg, + lua_Integer def); + void (*luaL_checkstack) (lua_State *L, int sz, const char *msg); + void (*luaL_checktype) (lua_State *L, int arg, int t); + void (*luaL_checkany) (lua_State *L, int arg); + int (*luaL_newmetatable) (lua_State *L, const char *tname); + void (*luaL_setmetatable) (lua_State *L, const char *tname); + void * (*luaL_testudata) (lua_State *L, int ud, const char *tname); + void * (*luaL_checkudata) (lua_State *L, int ud, const char *tname); + void (*luaL_where) (lua_State *L, int lvl); + int (*luaL_checkoption) (lua_State *L, int arg, const char *def, + const char *const lst[]); + int (*luaL_fileresult) (lua_State *L, int stat, const char *fname); + int (*luaL_execresult) (lua_State *L, int stat); + void * (*luaL_alloc) (void *ud, void *ptr, size_t osize, + size_t nsize); + int (*luaL_ref) (lua_State *L, int t); + void (*luaL_unref) (lua_State *L, int t, int ref); + int (*luaL_loadfilex) (lua_State *L, const char *filename, + const char *mode); + int (*luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode); + int (*luaL_loadstring) (lua_State *L, const char *s); + lua_State * (*luaL_newstate) (void); + unsigned (*luaL_makeseed) (lua_State *L); + lua_Integer (*luaL_len) (lua_State *L, int idx); + void (*luaL_addgsub) (luaL_Buffer *b, const char *s, + const char *p, const char *r); + const char * (*luaL_gsub) (lua_State *L, const char *s, + const char *p, const char *r); + void (*luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); + int (*luaL_getsubtable) (lua_State *L, int idx, const char *fname); + void (*luaL_traceback) (lua_State *L, lua_State *L1, + const char *msg, int level); + void (*luaL_requiref) (lua_State *L, const char *modname, + lua_CFunction openf, int glb); + void (*luaL_buffinit) (lua_State *L, luaL_Buffer *B); + char * (*luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); + void (*luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); + void (*luaL_addstring) (luaL_Buffer *B, const char *s); + void (*luaL_addvalue) (luaL_Buffer *B); + void (*luaL_pushresult) (luaL_Buffer *B); + void (*luaL_pushresultsize) (luaL_Buffer *B, size_t sz); + char * (*luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); + int (*lua_gc) (lua_State *L, int what, ...); +}; + +struct lua_api * +extlua_api() { + static struct lua_api api = { + LUA_VERSION_NUM, + + lua_newstate, + lua_close, + lua_newthread, + lua_closethread, + lua_atpanic, + lua_version, + lua_absindex, + lua_gettop, + lua_settop, + lua_pushvalue, + lua_rotate, + lua_copy, + lua_checkstack, + lua_xmove, + lua_isnumber, + lua_isstring, + lua_iscfunction, + lua_isinteger, + lua_isuserdata, + lua_type, + lua_typename, + lua_tonumberx, + lua_tointegerx, + lua_toboolean, + lua_tolstring, + lua_rawlen, + lua_tocfunction, + lua_touserdata, + lua_tothread, + lua_topointer, + lua_arith, + lua_rawequal, + lua_compare, + lua_pushnil, + lua_pushnumber, + lua_pushinteger, + lua_pushlstring, + lua_pushexternalstring, + lua_pushstring, + lua_pushvfstring, + lua_pushcclosure, + lua_pushboolean, + lua_pushlightuserdata, + lua_pushthread, + lua_getglobal, + lua_gettable, + lua_getfield, + lua_geti, + lua_rawget, + lua_rawgeti, + lua_rawgetp, + lua_createtable, + lua_newuserdatauv, + lua_getmetatable, + lua_getiuservalue, + lua_setglobal, + lua_settable, + lua_setfield, + lua_seti, + lua_rawset, + lua_rawseti, + lua_rawsetp, + lua_setmetatable, + lua_setiuservalue, + lua_callk, + lua_pcallk, + lua_load, + lua_dump, + lua_yieldk, + lua_resume, + lua_status, + lua_isyieldable, + lua_setwarnf, + lua_warning, + lua_error, + lua_next, + lua_concat, + lua_len, + lua_numbertocstring, + lua_stringtonumber, + lua_getallocf, + lua_setallocf, + lua_toclose, + lua_closeslot, + lua_getstack, + lua_getinfo, + lua_getlocal, + lua_setlocal, + lua_getupvalue, + lua_setupvalue, + lua_upvalueid, + lua_upvaluejoin, + lua_sethook, + lua_gethook, + lua_gethookmask, + lua_gethookcount, + luaL_checkversion_, + luaL_getmetafield, + luaL_callmeta, + luaL_tolstring, + luaL_argerror, + luaL_typeerror, + luaL_checklstring, + luaL_optlstring, + luaL_checknumber, + luaL_optnumber, + luaL_checkinteger, + luaL_optinteger, + luaL_checkstack, + luaL_checktype, + luaL_checkany, + luaL_newmetatable, + luaL_setmetatable, + luaL_testudata, + luaL_checkudata, + luaL_where, + luaL_checkoption, + luaL_fileresult, + luaL_execresult, + luaL_alloc, + luaL_ref, + luaL_unref, + luaL_loadfilex, + luaL_loadbufferx, + luaL_loadstring, + luaL_newstate, + luaL_makeseed, + luaL_len, + luaL_addgsub, + luaL_gsub, + luaL_setfuncs, + luaL_getsubtable, + luaL_traceback, + luaL_requiref, + luaL_buffinit, + luaL_prepbuffsize, + luaL_addlstring, + luaL_addstring, + luaL_addvalue, + luaL_pushresult, + luaL_pushresultsize, + luaL_buffinitsize, + lua_gc, + }; + return &api; +} diff --git a/extlua/extlua_sample.c b/extlua/extlua_sample.c index d9f1e35..c110c88 100644 --- a/extlua/extlua_sample.c +++ b/extlua/extlua_sample.c @@ -1,7 +1,14 @@ #include #include +#include +#include + +#include "sokol/sokol_gfx.h" +#include "perspective_quad.glsl.h" +#include "solunaapi.h" LUA_API void luaapi_init(lua_State *L); +void sokolapi_init(lua_State *L); #if defined(_WIN32) #define EXTLUA_EXPORT __declspec(dllexport) @@ -9,6 +16,478 @@ LUA_API void luaapi_init(lua_State *L); #define EXTLUA_EXPORT __attribute__((visibility("default"))) #endif +#define PQUAD_CORNER_N 4 +#define PQUAD_INFO_CORNER_MASK 0x3u +#define PQUAD_INFO_USE_SPRITE_RECT 0x4u +#define PQUAD_EPSILON 0.000001f + +struct color { + unsigned char channel[4]; +}; + +struct pquad_payload { + uint32_t info; + float q; + struct color color; +}; + +struct pquad_inst { + float pos_h0[3]; + float pos_h1[3]; + float pos_h2[3]; + float uv_rect[4]; + float q[4]; + struct color color; +}; + +struct material_perspective_quad { + sg_pipeline pip; + sg_buffer inst; + void *bind; + int base; + vs_params_t *uniform; + void *bank; + void *tmp_ptr; + size_t tmp_size; +}; + +struct sprite_rect_basis { + float scale_x; + float scale_y; + float shear_x; + float shear_y; + float tx; + float ty; +}; + +static int material_id = 0; + +static sg_pipeline +make_pipeline(sg_pipeline_desc *desc) { + sg_shader shd = sg_make_shader(perspective_quad_shader_desc(sg_query_backend())); + desc->shader = shd; + desc->primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP; + desc->label = "extlua-perspective-quad-pipeline"; + desc->layout.buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE; + desc->colors[0].blend = (sg_blend_state) { + .enabled = true, + .src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA, + .dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + .src_factor_alpha = SG_BLENDFACTOR_ONE, + .dst_factor_alpha = SG_BLENDFACTOR_ZERO, + }; + return sg_make_pipeline(desc); +} + +static void +set_position_homography(const float pos[PQUAD_CORNER_N][2], struct pquad_inst *inst) { + const float x0 = pos[0][0], y0 = pos[0][1]; + const float x1 = pos[1][0], y1 = pos[1][1]; + const float x2 = pos[2][0], y2 = pos[2][1]; + const float x3 = pos[3][0], y3 = pos[3][1]; + const float sx = x0 - x1 + x3 - x2; + const float sy = y0 - y1 + y3 - y2; + const float dx1 = x1 - x3; + const float dx2 = x2 - x3; + const float dy1 = y1 - y3; + const float dy2 = y2 - y3; + const float det = dx1 * dy2 - dx2 * dy1; + float m31 = 0.0f; + float m32 = 0.0f; + float abs_det = det < 0.0f ? -det : det; + if (abs_det > PQUAD_EPSILON) { + m31 = (sx * dy2 - sy * dx2) / det; + m32 = (sy * dx1 - sx * dy1) / det; + } + const float m11 = x1 - x0 + m31 * x1; + const float m12 = x2 - x0 + m32 * x2; + const float m13 = x0; + const float m21 = y1 - y0 + m31 * y1; + const float m22 = y2 - y0 + m32 * y2; + const float m23 = y0; + inst->pos_h0[0] = m11; + inst->pos_h0[1] = m21; + inst->pos_h0[2] = m31; + inst->pos_h1[0] = m12; + inst->pos_h1[1] = m22; + inst->pos_h1[2] = m32; + inst->pos_h2[0] = m13; + inst->pos_h2[1] = m23; + inst->pos_h2[2] = 1.0f; +} + +static inline int +perspective_quad_count(lua_State *L, int prim_n) { + if (prim_n % PQUAD_CORNER_N != 0) { + luaL_error(L, "Invalid perspective quad primitive count %d", prim_n); + return 0; + } + return prim_n / PQUAD_CORNER_N; +} + +static inline void +decode_sprite_rect_basis(struct sprite_rect_basis *basis, uint32_t corner, const struct soluna_material_stream_data *item) { + float x = item->x; + float y = item->y; + switch (corner) { + case 0: + basis->scale_x = x; + basis->scale_y = y; + break; + case 1: + basis->shear_x = x; + basis->shear_y = y; + break; + case 2: + basis->tx = x; + basis->ty = y; + break; + } +} + +static inline void +build_quad_from_rect(const struct sprite_rect_basis *basis, const struct soluna_sprite_rect *rect, float pos[PQUAD_CORNER_N][2]) { + float scale_x = basis->scale_x - basis->tx; + float scale_y = basis->scale_y - basis->ty; + float shear_x = basis->shear_x - basis->tx; + float shear_y = basis->shear_y - basis->ty; + int corner; + for (corner=0; cornerw - rect->ox) : -rect->ox; + float y = (corner >> 1) ? (rect->h - rect->oy) : -rect->oy; + pos[corner][0] = x * scale_x + y * shear_x + basis->tx; + pos[corner][1] = x * shear_y + y * scale_y + basis->ty; + } +} + +static void +submit(lua_State *L, void *m_, const void *stream, int n) { + struct material_perspective_quad *m = (struct material_perspective_quad *)m_; + struct pquad_inst *tmp = (struct pquad_inst *)m->tmp_ptr; + int out_n = perspective_quad_count(L, n); + int i; + for (i=0; icolor = payload.color; + } else if (item.sprite != sprite || flags != stream_flags) { + luaL_error(L, "Invalid perspective quad stream"); + } + uint32_t corner = payload.info & PQUAD_INFO_CORNER_MASK; + if (corner >= PQUAD_CORNER_N) { + luaL_error(L, "Invalid perspective quad corner %u", corner); + } + if (stream_flags & PQUAD_INFO_USE_SPRITE_RECT) { + decode_sprite_rect_basis(&sprite_rect_basis, corner, &item); + } else { + pos[corner][0] = item.x; + pos[corner][1] = item.y; + } + float q = payload.q; + if (q <= PQUAD_EPSILON) { + q = PQUAD_EPSILON; + } + inst->q[corner] = q; + } + struct soluna_sprite_rect sprite_rect; + if (!soluna_material_sprite_rect(L, m->bank, sprite, &sprite_rect)) { + luaL_error(L, "Invalid perspective quad sprite %d", sprite); + } + if (stream_flags & PQUAD_INFO_USE_SPRITE_RECT) { + build_quad_from_rect(&sprite_rect_basis, &sprite_rect, pos); + } + set_position_homography(pos, inst); + inst->uv_rect[0] = sprite_rect.u; + inst->uv_rect[1] = sprite_rect.v; + inst->uv_rect[2] = sprite_rect.w; + inst->uv_rect[3] = sprite_rect.h; + } + sg_append_buffer(m->inst, &(sg_range) { tmp, out_n * sizeof(tmp[0]) }); +} + +static int +lmaterial_perspective_quad_submit(lua_State *L) { + struct material_perspective_quad *m = (struct material_perspective_quad *)luaL_checkudata(L, 1, "EXTLUA_MATERIAL_PERSPECTIVE_QUAD"); + int inst_batch_n = (int)(m->tmp_size / sizeof(struct pquad_inst)); + if (inst_batch_n < 1) { + return luaL_error(L, "Perspective quad tmp buffer is too small"); + } + soluna_material_submit(L, inst_batch_n * PQUAD_CORNER_N, m, submit); + return 0; +} + +static int +lmaterial_perspective_quad_draw(lua_State *L) { + struct material_perspective_quad *m = (struct material_perspective_quad *)luaL_checkudata(L, 1, "EXTLUA_MATERIAL_PERSPECTIVE_QUAD"); + int prim_n = luaL_checkinteger(L, 3); + if (prim_n <= 0) { + return 0; + } + int quad_n = perspective_quad_count(L, prim_n); + sg_apply_pipeline(m->pip); + sg_apply_uniforms(UB_vs_params, &(sg_range) { m->uniform, sizeof(vs_params_t) }); + sg_bindings bindings = soluna_material_bindings(L, m->bind); + bindings.vertex_buffer_offsets[0] += (size_t)m->base * sizeof(struct pquad_inst); + sg_apply_bindings(&bindings); + sg_draw(0, 4, quad_n); + m->base += quad_n; + return 0; +} + +static int +lmaterial_perspective_quad_reset(lua_State *L) { + struct material_perspective_quad *m = (struct material_perspective_quad *)luaL_checkudata(L, 1, "EXTLUA_MATERIAL_PERSPECTIVE_QUAD"); + m->base = 0; + return 0; +} + +static int +lset_material_id(lua_State *L) { + int id = luaL_checkinteger(L, 1); + if (id <= 0) { + return luaL_error(L, "Invalid perspective quad material id %d", id); + } + material_id = id; + return 0; +} + +static void +init_pipeline(struct material_perspective_quad *p) { + sg_pipeline_desc desc = { + .layout.attrs = { + [ATTR_perspective_quad_pos_h0].format = SG_VERTEXFORMAT_FLOAT3, + [ATTR_perspective_quad_pos_h1].format = SG_VERTEXFORMAT_FLOAT3, + [ATTR_perspective_quad_pos_h2].format = SG_VERTEXFORMAT_FLOAT3, + [ATTR_perspective_quad_uv_rect].format = SG_VERTEXFORMAT_FLOAT4, + [ATTR_perspective_quad_q].format = SG_VERTEXFORMAT_FLOAT4, + [ATTR_perspective_quad_color].format = SG_VERTEXFORMAT_UBYTE4N, + }, + }; + p->pip = make_pipeline(&desc); +} + +static int +lnew_material_perspective_quad(lua_State *L) { + luaL_checktype(L, 1, LUA_TTABLE); + struct material_perspective_quad *m = (struct material_perspective_quad *)lua_newuserdatauv(L, sizeof(*m), 4); + int material_index = lua_gettop(L); + init_pipeline(m); + m->base = 0; + + if (lua_getfield(L, 1, "inst_buffer") != LUA_TUSERDATA) { + return luaL_error(L, "Invalid key .inst_buffer"); + } + luaL_checkudata(L, -1, "SOKOL_BUFFER"); + lua_pushvalue(L, -1); + lua_setiuservalue(L, material_index, 1); + lua_pushlightuserdata(L, &m->inst); + lua_call(L, 1, 0); + + if (lua_getfield(L, 1, "bindings") != LUA_TUSERDATA) { + return luaL_error(L, "Invalid key .bindings"); + } + m->bind = luaL_checkudata(L, -1, "SOKOL_BINDINGS"); + lua_pushvalue(L, -1); + lua_setiuservalue(L, material_index, 2); + lua_pop(L, 1); + + if (lua_getfield(L, 1, "uniform") != LUA_TUSERDATA) { + return luaL_error(L, "Invalid key .uniform"); + } + m->uniform = (vs_params_t *)luaL_checkudata(L, -1, "SOKOL_UNIFORM"); + lua_pushvalue(L, -1); + lua_setiuservalue(L, material_index, 3); + lua_pop(L, 1); + + if (lua_getfield(L, 1, "sprite_bank") != LUA_TLIGHTUSERDATA) { + return luaL_error(L, "Invalid key .sprite_bank"); + } + m->bank = lua_touserdata(L, -1); + lua_pop(L, 1); + + if (lua_getfield(L, 1, "tmp_buffer") != LUA_TUSERDATA) { + return luaL_error(L, "Invalid key .tmp_buffer"); + } + if (lua_getmetatable(L, -1)) { + return luaL_error(L, "Not an userdata without metatable"); + } + m->tmp_ptr = lua_touserdata(L, -1); + m->tmp_size = lua_rawlen(L, -1); + lua_setiuservalue(L, material_index, 4); + + if (luaL_newmetatable(L, "EXTLUA_MATERIAL_PERSPECTIVE_QUAD")) { + luaL_Reg l[] = { + { "__index", NULL }, + { "reset", lmaterial_perspective_quad_reset }, + { "submit", lmaterial_perspective_quad_submit }, + { "draw", lmaterial_perspective_quad_draw }, + { NULL, NULL }, + }; + luaL_setfuncs(L, l, 0); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + } + lua_setmetatable(L, -2); + return 1; +} + +static inline float +get_number_field(lua_State *L, int index, const char *field, float defv) { + float v; + lua_getfield(L, index, field); + v = luaL_optnumber(L, -1, defv); + lua_pop(L, 1); + return v; +} + +static int +get_quad(lua_State *L, int index, float quad[8]) { + if (lua_getfield(L, index, "quad") == LUA_TTABLE) { + int i; + for (i=0; i<8; i++) { + lua_geti(L, -1, i + 1); + quad[i] = luaL_checknumber(L, -1); + lua_pop(L, 1); + } + lua_pop(L, 1); + return 0; + } + lua_pop(L, 1); + return 1; +} + +static void +get_q(lua_State *L, int index, float q[4]) { + int i; + if (lua_getfield(L, index, "q") != LUA_TTABLE) { + for (i=0; i<4; i++) { + q[i] = 1.0f; + } + lua_pop(L, 1); + return; + } + for (i=0; i<4; i++) { + lua_geti(L, -1, i + 1); + q[i] = luaL_optnumber(L, -1, 1.0f); + lua_pop(L, 1); + } + lua_pop(L, 1); +} + +static struct color +get_color(lua_State *L, int index) { + uint32_t color; + struct color c; + lua_getfield(L, index, "color"); + color = (uint32_t)luaL_optinteger(L, -1, 0xffffffff); + if (!(color & 0xff000000)) { + color |= 0xff000000; + } + c.channel[0] = (color >> 16) & 0xff; + c.channel[1] = (color >> 8) & 0xff; + c.channel[2] = color & 0xff; + c.channel[3] = (color >> 24) & 0xff; + lua_pop(L, 1); + return c; +} + +struct pquad_stream_context { + int sprite; + int use_sprite_rect; + float scale_x; + float scale_y; + float shear_x; + float shear_y; + float quad[8]; + float q[4]; + struct color color; + struct pquad_payload payload[PQUAD_CORNER_N]; +}; + +static void +write_perspective_quad_stream(void *ud, int index, struct soluna_material_stream_item *item) { + struct pquad_stream_context *ctx = (struct pquad_stream_context *)ud; + item->sprite = ctx->sprite; + if (ctx->use_sprite_rect) { + switch (index) { + case 0: + item->x = ctx->scale_x; + item->y = ctx->scale_y; + break; + case 1: + item->x = ctx->shear_x; + item->y = ctx->shear_y; + break; + default: + item->x = 0.0f; + item->y = 0.0f; + break; + } + } else { + float x = ctx->quad[index * 2]; + float y = ctx->quad[index * 2 + 1]; + item->x = x * ctx->scale_x + y * ctx->shear_x; + item->y = x * ctx->shear_y + y * ctx->scale_y; + } + struct pquad_payload *payload = &ctx->payload[index]; + uint32_t info = (uint32_t)index; + if (ctx->use_sprite_rect) { + info |= PQUAD_INFO_USE_SPRITE_RECT; + } + payload->info = info; + payload->q = ctx->q[index]; + payload->color = ctx->color; + item->payload = payload; +} + +static int +lperspective_quad_sprite(lua_State *L) { + if (material_id <= 0) { + return luaL_error(L, "Perspective quad material is not registered"); + } + luaL_checktype(L, 2, LUA_TTABLE); + struct pquad_stream_context ctx; + ctx.sprite = luaL_checkinteger(L, 1) - 1; + ctx.use_sprite_rect = get_quad(L, 2, ctx.quad); + ctx.scale_x = get_number_field(L, 2, "scale_x", 1.0f); + ctx.scale_y = get_number_field(L, 2, "scale_y", 1.0f); + ctx.shear_x = get_number_field(L, 2, "shear_x", 0.0f); + ctx.shear_y = get_number_field(L, 2, "shear_y", 0.0f); + get_q(L, 2, ctx.q); + ctx.color = get_color(L, 2); + soluna_material_push_stream(L, material_id, PQUAD_CORNER_N, sizeof(struct pquad_payload), write_perspective_quad_stream, &ctx); + return 1; +} + +static int +luaopen_ext_material_perspective_quad(lua_State *L) { + luaL_checkversion(L); + luaL_Reg l[] = { + { "set_material_id", lset_material_id }, + { "new", lnew_material_perspective_quad }, + { "sprite", lperspective_quad_sprite }, + { "instance_size", NULL }, + { NULL, NULL }, + }; + luaL_newlib(L, l); + lua_pushinteger(L, sizeof(struct pquad_inst)); + lua_setfield(L, -2, "instance_size"); + return 1; +} + static int lhello(lua_State *L) { lua_pushstring(L, "Hello World From Sample"); @@ -28,8 +507,11 @@ luaopen_foobar(lua_State *L) { EXTLUA_EXPORT int extlua_init(lua_State *L) { luaapi_init(L); + sokolapi_init(L); + solunaapi_init(L); luaL_Reg l[] = { { "ext.foobar", luaopen_foobar }, + { "ext.material.perspective_quad", luaopen_ext_material_perspective_quad }, { NULL, NULL }, }; luaL_newlib(L, l); diff --git a/extlua/gen.lua b/extlua/gen.lua index f785130..8c57a34 100644 --- a/extlua/gen.lua +++ b/extlua/gen.lua @@ -33,6 +33,7 @@ local function get_apis(result, filename, prefix) error("Invalid function " .. line) end end + retv = retv:gsub("%s+$", "") if retv:match "%s*void%s*$" then retv = "void" end diff --git a/extlua/gen_sokol.lua b/extlua/gen_sokol.lua new file mode 100644 index 0000000..64b8974 --- /dev/null +++ b/extlua/gen_sokol.lua @@ -0,0 +1,134 @@ +-- sokolapi.c generator + +local header = "../3rd/sokol/sokol_gfx.h" + +local allowlist = { + sg_make_buffer = true, + sg_destroy_buffer = true, + sg_update_buffer = true, + sg_append_buffer = true, + sg_make_shader = true, + sg_destroy_shader = true, + sg_make_pipeline = true, + sg_destroy_pipeline = true, + sg_apply_pipeline = true, + sg_apply_bindings = true, + sg_apply_uniforms = true, + sg_draw = true, + sg_draw_ex = true, + sg_query_backend = true, + sg_query_buffer_state = true, + sg_query_shader_state = true, + sg_query_pipeline_state = true, +} + +local function parse_params(params) + local p = {} + if params == "(void)" then + return p + end + local body = params:sub(2, -2) + local n = 1 + for decl in body:gmatch "[^,]+" do + local t, name = decl:match "^(.-)([%w_]+)%s*$" + if not t then + error("Invalid param " .. decl) + end + p[n] = { type = t, name = name } + n = n + 1 + end + return p +end + +local function readfile(filename) + local f = assert(io.open(filename)) + local content = f:read "a" + f:close() + return content +end + +local function get_apis() + local src = readfile(header) + local apis = {} + for line in src:gmatch "SOKOL_GFX_API_DECL%s*(.-;)%s*\n" do + local retv, name, params = line:match "([%s%w_*]+)%s+(sg_[%w_]+)%s*(%b());$" + if name and allowlist[name] then + apis[#apis + 1] = { + ret = retv:gsub("%s+$", ""), + name = name, + params = parse_params(params), + } + end + end + return apis +end + +local function decls(params) + if #params == 0 then + return "void" + end + local r = {} + for i, p in ipairs(params) do + r[i] = p.type .. p.name + end + return table.concat(r, ", ") +end + +local function args(params) + local r = {} + for i, p in ipairs(params) do + r[i] = p.name + end + return table.concat(r, ", ") +end + +local function gen_decl(apis) + local r = {} + for i, api in ipairs(apis) do + r[i] = ("\t%s (*%s) (%s);"):format(api.ret, api.name, decls(api.params)) + end + return table.concat(r, "\n") +end + +local function gen_struct(apis) + local r = {} + for i, api in ipairs(apis) do + r[i] = ("\t\t%s,"):format(api.name) + end + return table.concat(r, "\n") +end + +local function gen_impl(apis) + local r = {} + for i, api in ipairs(apis) do + local ret = api.ret == "void" and "" or "return " + r[i] = ("SOKOL_GFX_API_DECL %s\n%s(%s) {\n\t%sAPI.%s(%s);\n}\n\n"):format( + api.ret, + api.name, + decls(api.params), + ret, + api.name, + args(api.params) + ) + end + return table.concat(r) +end + +local function genfile(filename, temp) + local t = readfile(filename) + local output = filename:gsub("%.temp", "") + local f = assert(io.open(output, "w")) + f:write("// AUTO GENERATED by " .. filename .. ", DONT EDIT\n\n") + f:write((t:gsub("%$([%w_]+)%$", temp))) + f:close() +end + +local apis = get_apis() +local convert = { + API_DECL = gen_decl(apis), + API_STRUCT = gen_struct(apis), + API_IMPL = gen_impl(apis), +} + +genfile("sokolapi.temp.c", convert) +genfile("sokolapi_impl.temp.c", convert) diff --git a/extlua/gen_soluna.lua b/extlua/gen_soluna.lua new file mode 100644 index 0000000..6d19e92 --- /dev/null +++ b/extlua/gen_soluna.lua @@ -0,0 +1,202 @@ +-- solunaapi.c generator + +local apis = { + { + ret = "void", + name = "soluna_material_submit", + params = { + { type = "lua_State *", name = "L" }, + { type = "int ", name = "batch_n" }, + { type = "void *", name = "ud" }, + { type = "soluna_material_submit_func ", name = "submit" }, + }, + }, + { + ret = "int", + name = "soluna_material_sprite_rect", + params = { + { type = "lua_State *", name = "L" }, + { type = "void *", name = "bank" }, + { type = "int ", name = "sprite" }, + { type = "struct soluna_sprite_rect *", name = "out" }, + }, + }, + { + ret = "sg_bindings", + name = "soluna_material_bindings", + params = { + { type = "lua_State *", name = "L" }, + { type = "void *", name = "bindings" }, + }, + }, + { + ret = "void", + name = "soluna_material_push_stream", + params = { + { type = "lua_State *", name = "L" }, + { type = "int ", name = "material_id" }, + { type = "int ", name = "count" }, + { type = "size_t ", name = "payload_size" }, + { type = "soluna_material_stream_write_func ", name = "write" }, + { type = "void *", name = "ud" }, + }, + }, + { + ret = "void", + name = "soluna_material_stream_read", + params = { + { type = "lua_State *", name = "L" }, + { type = "const void *", name = "stream" }, + { type = "int ", name = "index" }, + { type = "int ", name = "material_id" }, + { type = "size_t ", name = "payload_size" }, + { type = "void *", name = "payload" }, + { type = "struct soluna_material_stream_data *", name = "out" }, + }, + }, +} + +local type_decl = [[ +#define SOLUNA_EXT_API_VERSION 1 + +struct soluna_sprite_rect { + int texture; + float u; + float v; + float w; + float h; + float ox; + float oy; +}; + +struct soluna_material_stream_item { + float x; + float y; + int sprite; + const void *payload; +}; + +struct soluna_material_stream_data { + float x; + float y; + int sprite; +}; + +typedef void (*soluna_material_submit_func)(lua_State *L, void *ud, const void *stream, int n); +typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); +]] + +local host_type_decl = [[ +#include + +#include + +#include "sokol/sokol_gfx.h" + +]] .. type_decl + +local function readfile(filename) + local f = assert(io.open(filename)) + local content = f:read "a" + f:close() + return content +end + +local function genfile(filename, temp) + local t = readfile(filename) + local output = filename:gsub("%.temp", "") + local f = assert(io.open(output, "w")) + f:write("// AUTO GENERATED by " .. filename .. ", DONT EDIT\n\n") + f:write((t:gsub("%$([%w_]+)%$", temp))) + f:close() +end + +local function decls(params) + if #params == 0 then + return "void" + end + local r = {} + for i, p in ipairs(params) do + r[i] = p.type .. p.name + end + return table.concat(r, ", ") +end + +local function args(params) + local r = {} + for i, p in ipairs(params) do + r[i] = p.name + end + return table.concat(r, ", ") +end + +local function field_name(api) + return api.field or api.name:gsub("^soluna_", "") +end + +local function impl_name(api) + return api.impl or field_name(api) +end + +local function gen_header_decl() + local r = { "void solunaapi_init(lua_State *L);" } + for _, api in ipairs(apis) do + r[#r + 1] = ("%s %s(%s);"):format(api.ret, api.name, decls(api.params)) + end + return table.concat(r, "\n") +end + +local function gen_api_decl() + local r = {} + for i, api in ipairs(apis) do + r[i] = ("\t%s (*%s) (%s);"):format(api.ret, field_name(api), decls(api.params)) + end + return table.concat(r, "\n") +end + +local function gen_api_struct() + local r = {} + for i, api in ipairs(apis) do + r[i] = ("\t\t%s,"):format(impl_name(api)) + end + return table.concat(r, "\n") +end + +local function gen_api_extern() + local r = {} + for i, api in ipairs(apis) do + r[i] = ("extern %s %s(%s);"):format(api.ret, impl_name(api), decls(api.params)) + end + return table.concat(r, "\n") +end + +local function gen_api_impl() + local r = {} + for i, api in ipairs(apis) do + local ret = api.ret == "void" and "" or "return " + r[i] = ("%s\n%s(%s) {\n\t%sAPI.%s(%s);\n}\n\n"):format( + api.ret, + api.name, + decls(api.params), + ret, + field_name(api), + args(api.params) + ) + end + return table.concat(r) +end + +local convert = { + TYPE_DECL = type_decl, + HEADER_DECL = gen_header_decl(), + API_DECL = gen_api_decl(), + API_STRUCT = gen_api_struct(), + API_EXTERN = gen_api_extern(), + API_IMPL = gen_api_impl(), + HOST_TYPE_DECL = host_type_decl, +} + +genfile("solunaapi.h.temp", convert) +genfile("solunaapi.temp.c", convert) +genfile("solunaapi_impl.temp.c", convert) +genfile("../src/extapi_types.temp.h", convert) diff --git a/src/perspective_quad.glsl b/extlua/perspective_quad.glsl similarity index 100% rename from src/perspective_quad.glsl rename to extlua/perspective_quad.glsl diff --git a/extlua/sokolapi.c b/extlua/sokolapi.c new file mode 100644 index 0000000..5e4159f --- /dev/null +++ b/extlua/sokolapi.c @@ -0,0 +1,131 @@ +// AUTO GENERATED by sokolapi.temp.c, DONT EDIT + +#include + +#include "sokol/sokol_gfx.h" + +struct sokol_api { + int version; + + sg_buffer (*sg_make_buffer) (const sg_buffer_desc* desc); + sg_shader (*sg_make_shader) (const sg_shader_desc* desc); + sg_pipeline (*sg_make_pipeline) (const sg_pipeline_desc* desc); + void (*sg_destroy_buffer) (sg_buffer buf); + void (*sg_destroy_shader) (sg_shader shd); + void (*sg_destroy_pipeline) (sg_pipeline pip); + void (*sg_update_buffer) (sg_buffer buf, const sg_range* data); + int (*sg_append_buffer) (sg_buffer buf, const sg_range* data); + void (*sg_apply_pipeline) (sg_pipeline pip); + void (*sg_apply_bindings) (const sg_bindings* bindings); + void (*sg_apply_uniforms) (int ub_slot, const sg_range* data); + void (*sg_draw) (int base_element, int num_elements, int num_instances); + void (*sg_draw_ex) (int base_element, int num_elements, int num_instances, int base_vertex, int base_instance); + sg_backend (*sg_query_backend) (void); + sg_resource_state (*sg_query_buffer_state) (sg_buffer buf); + sg_resource_state (*sg_query_shader_state) (sg_shader shd); + sg_resource_state (*sg_query_pipeline_state) (sg_pipeline pip); +}; + +static struct sokol_api API; + +SOKOL_GFX_API_DECL sg_buffer +sg_make_buffer(const sg_buffer_desc* desc) { + return API.sg_make_buffer(desc); +} + +SOKOL_GFX_API_DECL sg_shader +sg_make_shader(const sg_shader_desc* desc) { + return API.sg_make_shader(desc); +} + +SOKOL_GFX_API_DECL sg_pipeline +sg_make_pipeline(const sg_pipeline_desc* desc) { + return API.sg_make_pipeline(desc); +} + +SOKOL_GFX_API_DECL void +sg_destroy_buffer(sg_buffer buf) { + API.sg_destroy_buffer(buf); +} + +SOKOL_GFX_API_DECL void +sg_destroy_shader(sg_shader shd) { + API.sg_destroy_shader(shd); +} + +SOKOL_GFX_API_DECL void +sg_destroy_pipeline(sg_pipeline pip) { + API.sg_destroy_pipeline(pip); +} + +SOKOL_GFX_API_DECL void +sg_update_buffer(sg_buffer buf, const sg_range* data) { + API.sg_update_buffer(buf, data); +} + +SOKOL_GFX_API_DECL int +sg_append_buffer(sg_buffer buf, const sg_range* data) { + return API.sg_append_buffer(buf, data); +} + +SOKOL_GFX_API_DECL void +sg_apply_pipeline(sg_pipeline pip) { + API.sg_apply_pipeline(pip); +} + +SOKOL_GFX_API_DECL void +sg_apply_bindings(const sg_bindings* bindings) { + API.sg_apply_bindings(bindings); +} + +SOKOL_GFX_API_DECL void +sg_apply_uniforms(int ub_slot, const sg_range* data) { + API.sg_apply_uniforms(ub_slot, data); +} + +SOKOL_GFX_API_DECL void +sg_draw(int base_element, int num_elements, int num_instances) { + API.sg_draw(base_element, num_elements, num_instances); +} + +SOKOL_GFX_API_DECL void +sg_draw_ex(int base_element, int num_elements, int num_instances, int base_vertex, int base_instance) { + API.sg_draw_ex(base_element, num_elements, num_instances, base_vertex, base_instance); +} + +SOKOL_GFX_API_DECL sg_backend +sg_query_backend(void) { + return API.sg_query_backend(); +} + +SOKOL_GFX_API_DECL sg_resource_state +sg_query_buffer_state(sg_buffer buf) { + return API.sg_query_buffer_state(buf); +} + +SOKOL_GFX_API_DECL sg_resource_state +sg_query_shader_state(sg_shader shd) { + return API.sg_query_shader_state(shd); +} + +SOKOL_GFX_API_DECL sg_resource_state +sg_query_pipeline_state(sg_pipeline pip) { + return API.sg_query_pipeline_state(pip); +} + + + +struct lua_api; +struct soluna_api; + +struct extlua_apis { + struct lua_api * lua; + struct sokol_api * sokol; + struct soluna_api * soluna; +}; + +void +sokolapi_init(lua_State *L) { + struct extlua_apis *apis = *(struct extlua_apis **)lua_getextraspace(L); + API = *apis->sokol; +} diff --git a/extlua/sokolapi.temp.c b/extlua/sokolapi.temp.c new file mode 100644 index 0000000..d85ba68 --- /dev/null +++ b/extlua/sokolapi.temp.c @@ -0,0 +1,28 @@ +#include + +#include "sokol/sokol_gfx.h" + +struct sokol_api { + int version; + +$API_DECL$ +}; + +static struct sokol_api API; + +$API_IMPL$ + +struct lua_api; +struct soluna_api; + +struct extlua_apis { + struct lua_api * lua; + struct sokol_api * sokol; + struct soluna_api * soluna; +}; + +void +sokolapi_init(lua_State *L) { + struct extlua_apis *apis = *(struct extlua_apis **)lua_getextraspace(L); + API = *apis->sokol; +} diff --git a/extlua/sokolapi_impl.c b/extlua/sokolapi_impl.c new file mode 100644 index 0000000..b6c685f --- /dev/null +++ b/extlua/sokolapi_impl.c @@ -0,0 +1,51 @@ +// AUTO GENERATED by sokolapi_impl.temp.c, DONT EDIT + +#include "sokol/sokol_gfx.h" + +struct sokol_api { + int version; + + sg_buffer (*sg_make_buffer) (const sg_buffer_desc* desc); + sg_shader (*sg_make_shader) (const sg_shader_desc* desc); + sg_pipeline (*sg_make_pipeline) (const sg_pipeline_desc* desc); + void (*sg_destroy_buffer) (sg_buffer buf); + void (*sg_destroy_shader) (sg_shader shd); + void (*sg_destroy_pipeline) (sg_pipeline pip); + void (*sg_update_buffer) (sg_buffer buf, const sg_range* data); + int (*sg_append_buffer) (sg_buffer buf, const sg_range* data); + void (*sg_apply_pipeline) (sg_pipeline pip); + void (*sg_apply_bindings) (const sg_bindings* bindings); + void (*sg_apply_uniforms) (int ub_slot, const sg_range* data); + void (*sg_draw) (int base_element, int num_elements, int num_instances); + void (*sg_draw_ex) (int base_element, int num_elements, int num_instances, int base_vertex, int base_instance); + sg_backend (*sg_query_backend) (void); + sg_resource_state (*sg_query_buffer_state) (sg_buffer buf); + sg_resource_state (*sg_query_shader_state) (sg_shader shd); + sg_resource_state (*sg_query_pipeline_state) (sg_pipeline pip); +}; + +struct sokol_api * +extlua_sokol_api() { + static struct sokol_api api = { + SOKOL_GFX_INCLUDED, + + sg_make_buffer, + sg_make_shader, + sg_make_pipeline, + sg_destroy_buffer, + sg_destroy_shader, + sg_destroy_pipeline, + sg_update_buffer, + sg_append_buffer, + sg_apply_pipeline, + sg_apply_bindings, + sg_apply_uniforms, + sg_draw, + sg_draw_ex, + sg_query_backend, + sg_query_buffer_state, + sg_query_shader_state, + sg_query_pipeline_state, + }; + return &api; +} diff --git a/extlua/sokolapi_impl.temp.c b/extlua/sokolapi_impl.temp.c new file mode 100644 index 0000000..eed6161 --- /dev/null +++ b/extlua/sokolapi_impl.temp.c @@ -0,0 +1,17 @@ +#include "sokol/sokol_gfx.h" + +struct sokol_api { + int version; + +$API_DECL$ +}; + +struct sokol_api * +extlua_sokol_api() { + static struct sokol_api api = { + SOKOL_GFX_INCLUDED, + +$API_STRUCT$ + }; + return &api; +} diff --git a/extlua/solunaapi.c b/extlua/solunaapi.c new file mode 100644 index 0000000..5ff7176 --- /dev/null +++ b/extlua/solunaapi.c @@ -0,0 +1,63 @@ +// AUTO GENERATED by solunaapi.temp.c, DONT EDIT + +#include "solunaapi.h" + +#include + +struct soluna_api { + int version; + + void (*material_submit) (lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit); + int (*material_sprite_rect) (lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out); + sg_bindings (*material_bindings) (lua_State *L, void *bindings); + void (*material_push_stream) (lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud); + void (*material_stream_read) (lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out); +}; + +static struct soluna_api API; + +void +soluna_material_submit(lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit) { + API.material_submit(L, batch_n, ud, submit); +} + +int +soluna_material_sprite_rect(lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out) { + return API.material_sprite_rect(L, bank, sprite, out); +} + +sg_bindings +soluna_material_bindings(lua_State *L, void *bindings) { + return API.material_bindings(L, bindings); +} + +void +soluna_material_push_stream(lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud) { + API.material_push_stream(L, material_id, count, payload_size, write, ud); +} + +void +soluna_material_stream_read(lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { + API.material_stream_read(L, stream, index, material_id, payload_size, payload, out); +} + + + +struct lua_api; +struct sokol_api; + +struct extlua_apis { + struct lua_api * lua; + struct sokol_api * sokol; + struct soluna_api * soluna; +}; + +void +solunaapi_init(lua_State *L) { + struct extlua_apis *apis = *(struct extlua_apis **)lua_getextraspace(L); + if (apis == NULL || apis->soluna == NULL || apis->soluna->version != SOLUNA_EXT_API_VERSION) { + int version = (apis != NULL && apis->soluna != NULL) ? apis->soluna->version : 0; + luaL_error(L, "soluna ext api version mismatch, expected %d got %d", SOLUNA_EXT_API_VERSION, version); + } + API = *apis->soluna; +} diff --git a/extlua/solunaapi.h b/extlua/solunaapi.h new file mode 100644 index 0000000..26b1da0 --- /dev/null +++ b/extlua/solunaapi.h @@ -0,0 +1,48 @@ +// AUTO GENERATED by solunaapi.h.temp, DONT EDIT + +#ifndef SOLUNAAPI_H +#define SOLUNAAPI_H + +#include + +#include + +#include "sokol/sokol_gfx.h" + +#define SOLUNA_EXT_API_VERSION 1 + +struct soluna_sprite_rect { + int texture; + float u; + float v; + float w; + float h; + float ox; + float oy; +}; + +struct soluna_material_stream_item { + float x; + float y; + int sprite; + const void *payload; +}; + +struct soluna_material_stream_data { + float x; + float y; + int sprite; +}; + +typedef void (*soluna_material_submit_func)(lua_State *L, void *ud, const void *stream, int n); +typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); + + +void solunaapi_init(lua_State *L); +void soluna_material_submit(lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit); +int soluna_material_sprite_rect(lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out); +sg_bindings soluna_material_bindings(lua_State *L, void *bindings); +void soluna_material_push_stream(lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud); +void soluna_material_stream_read(lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out); + +#endif diff --git a/extlua/solunaapi.h.temp b/extlua/solunaapi.h.temp new file mode 100644 index 0000000..f47b61d --- /dev/null +++ b/extlua/solunaapi.h.temp @@ -0,0 +1,14 @@ +#ifndef SOLUNAAPI_H +#define SOLUNAAPI_H + +#include + +#include + +#include "sokol/sokol_gfx.h" + +$TYPE_DECL$ + +$HEADER_DECL$ + +#endif diff --git a/extlua/solunaapi.temp.c b/extlua/solunaapi.temp.c new file mode 100644 index 0000000..66efa6e --- /dev/null +++ b/extlua/solunaapi.temp.c @@ -0,0 +1,32 @@ +#include "solunaapi.h" + +#include + +struct soluna_api { + int version; + +$API_DECL$ +}; + +static struct soluna_api API; + +$API_IMPL$ + +struct lua_api; +struct sokol_api; + +struct extlua_apis { + struct lua_api * lua; + struct sokol_api * sokol; + struct soluna_api * soluna; +}; + +void +solunaapi_init(lua_State *L) { + struct extlua_apis *apis = *(struct extlua_apis **)lua_getextraspace(L); + if (apis == NULL || apis->soluna == NULL || apis->soluna->version != SOLUNA_EXT_API_VERSION) { + int version = (apis != NULL && apis->soluna != NULL) ? apis->soluna->version : 0; + luaL_error(L, "soluna ext api version mismatch, expected %d got %d", SOLUNA_EXT_API_VERSION, version); + } + API = *apis->soluna; +} diff --git a/extlua/solunaapi_impl.c b/extlua/solunaapi_impl.c new file mode 100644 index 0000000..5295b34 --- /dev/null +++ b/extlua/solunaapi_impl.c @@ -0,0 +1,66 @@ +// AUTO GENERATED by solunaapi_impl.temp.c, DONT EDIT + +#include + +#include + +#include "sokol/sokol_gfx.h" + +#define SOLUNA_EXT_API_VERSION 1 + +struct soluna_sprite_rect { + int texture; + float u; + float v; + float w; + float h; + float ox; + float oy; +}; + +struct soluna_material_stream_item { + float x; + float y; + int sprite; + const void *payload; +}; + +struct soluna_material_stream_data { + float x; + float y; + int sprite; +}; + +typedef void (*soluna_material_submit_func)(lua_State *L, void *ud, const void *stream, int n); +typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); + + +extern void material_submit(lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit); +extern int material_sprite_rect(lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out); +extern sg_bindings material_bindings(lua_State *L, void *bindings); +extern void material_push_stream(lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud); +extern void material_stream_read(lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out); + +struct soluna_api { + int version; + + void (*material_submit) (lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit); + int (*material_sprite_rect) (lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out); + sg_bindings (*material_bindings) (lua_State *L, void *bindings); + void (*material_push_stream) (lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud); + void (*material_stream_read) (lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out); +}; + +struct soluna_api * +extlua_soluna_api() { + static struct soluna_api api = { + SOLUNA_EXT_API_VERSION, + + material_submit, + material_sprite_rect, + material_bindings, + material_push_stream, + material_stream_read, + }; + return &api; +} diff --git a/extlua/solunaapi_impl.temp.c b/extlua/solunaapi_impl.temp.c new file mode 100644 index 0000000..e8b6648 --- /dev/null +++ b/extlua/solunaapi_impl.temp.c @@ -0,0 +1,19 @@ +$HOST_TYPE_DECL$ + +$API_EXTERN$ + +struct soluna_api { + int version; + +$API_DECL$ +}; + +struct soluna_api * +extlua_soluna_api() { + static struct soluna_api api = { + SOLUNA_EXT_API_VERSION, + +$API_STRUCT$ + }; + return &api; +} diff --git a/make.lua b/make.lua index 99b94b3..968162f 100644 --- a/make.lua +++ b/make.lua @@ -121,7 +121,7 @@ local deps = { "soluna_src" } for path in fs.pairs(lm.basedir .. "/clibs") do local name = path:stem():string() - if name ~= "soluna" and fs.exists(path / "make.lua") then + if name ~= "soluna" and name ~= "sample" and fs.exists(path / "make.lua") then local makefile = ("clibs/%s/make.lua"):format(name) lm:import(makefile) deps[#deps + 1] = name .. "_src" @@ -129,6 +129,7 @@ for path in fs.pairs(lm.basedir .. "/clibs") do end lm:import "clibs/soluna/make.lua" +lm:import "clibs/sample/make.lua" lm:exe "soluna" { deps = deps, @@ -150,16 +151,6 @@ lm:exe "soluna" { }, } -lm:dll "sample" { - sources = { - "extlua/extlua.c", - "extlua/extlua_sample.c", - }, - includes = { - "3rd/lua", - }, -} - lm:import "script/act_targets.lua" lm:runlua "cc" { diff --git a/src/embedlua.c b/src/embedlua.c index 189c1cf..d9fe9c9 100644 --- a/src/embedlua.c +++ b/src/embedlua.c @@ -26,7 +26,6 @@ #include "mattext.lua.h" #include "matquad.lua.h" #include "matmask.lua.h" -#include "matpquad.lua.h" #include "lua.h" #include "lauxlib.h" @@ -103,7 +102,6 @@ luaopen_embedsource(lua_State *L) { REG_MATERIAL(mattext) REG_MATERIAL(matquad) REG_MATERIAL(matmask) - REG_MATERIAL(matpquad) lua_setfield(L, -2, "material"); lua_newtable(L); // data list diff --git a/src/extapi.c b/src/extapi.c new file mode 100644 index 0000000..2e45b77 --- /dev/null +++ b/src/extapi.c @@ -0,0 +1,231 @@ +#include +#include +#include +#include +#include +#include + +#include "sokol/sokol_gfx.h" +#include "batch.h" +#include "spritemgr.h" +#include "render_bindings.h" +#include "extapi_types.h" + +#define STREAM_FIX_SCALE 256.0f +#define STREAM_FIX_INV_SCALE (1.0f / STREAM_FIX_SCALE) + +typedef void (*material_submit_stride_func)(lua_State *L, void *ud, void *stream, int n); + +static void +submit_material_stride(lua_State *L, int batch_n, void *ud, material_submit_stride_func submit, size_t stride) { + char *stream = lua_touserdata(L, 2); + int prim_n = luaL_checkinteger(L, 3); + if (stream == NULL) { + luaL_error(L, "Missing material stream"); + } + if (batch_n <= 0) { + luaL_error(L, "Invalid material submit batch %d", batch_n); + } + if (prim_n < 0) { + luaL_error(L, "Invalid material primitive count %d", prim_n); + } + if (submit == NULL) { + luaL_error(L, "Missing material submit function"); + } + if (stride == 0) { + luaL_error(L, "Invalid material submit stride"); + } + int i = 0; + for (;;) { + int n = prim_n - i; + if (n > batch_n) { + submit(L, ud, stream, batch_n); + i += batch_n; + stream += stride * batch_n; + } else { + submit(L, ud, stream, n); + break; + } + } +} + +struct material_submit_context { + void *ud; + soluna_material_submit_func submit; +}; + +static void +submit_external_material(lua_State *L, void *ctx_, void *stream, int n) { + struct material_submit_context *ctx = (struct material_submit_context *)ctx_; + ctx->submit(L, ctx->ud, stream, n); +} + +void +material_submit(lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit) { + struct material_submit_context ctx = { + .ud = ud, + .submit = submit, + }; + submit_material_stride(L, batch_n, &ctx, submit_external_material, sizeof(struct draw_primitive) * 2); +} + +int +material_sprite_rect(lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out) { + (void)L; + struct sprite_bank *b = (struct sprite_bank *)bank; + if (b == NULL || out == NULL || sprite < 0 || sprite >= b->n) { + return 0; + } + struct sprite_rect *r = &b->rect[sprite]; + out->texture = r->texid; + out->u = (float)(r->u >> 16); + out->v = (float)(r->v >> 16); + out->w = (float)(r->u & 0xffffu); + out->h = (float)(r->v & 0xffffu); + out->ox = (float)((r->off >> 16) & 0xffffu) - 0x8000; + out->oy = (float)(r->off & 0xffffu) - 0x8000; + return 1; +} + +sg_bindings +material_bindings(lua_State *L, void *bindings) { + struct soluna_render_bindings *b = (struct soluna_render_bindings *)bindings; + if (b == NULL) { + luaL_error(L, "Missing material bindings"); + } + return b->bindings; +} + +static size_t +stream_payload_max(void) { + return sizeof(struct draw_primitive) - sizeof(struct draw_primitive_external); +} + +struct stream_guard { + void *ptr; +}; + +static int +stream_guard_gc(lua_State *L) { + struct stream_guard *guard = (struct stream_guard *)lua_touserdata(L, 1); + free(guard->ptr); + guard->ptr = NULL; + return 0; +} + +static struct stream_guard * +push_stream_guard(lua_State *L) { + struct stream_guard *guard = (struct stream_guard *)lua_newuserdatauv(L, sizeof(*guard), 0); + guard->ptr = NULL; + if (luaL_newmetatable(L, "SOLUNA_MATERIAL_STREAM_GUARD")) { + luaL_Reg l[] = { + { "__gc", stream_guard_gc }, + { NULL, NULL }, + }; + luaL_setfuncs(L, l, 0); + } + lua_setmetatable(L, -2); + return guard; +} + +static void * +free_stream(void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; + (void)osize; + if (nsize == 0) { + free(ptr); + } + return NULL; +} + +void +material_push_stream(lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud) { + size_t payload_max = stream_payload_max(); + if (material_id <= 0) { + luaL_error(L, "Invalid material id %d", material_id); + } + if (count < 0) { + luaL_error(L, "Invalid material stream count %d", count); + } + if (payload_size > payload_max) { + luaL_error(L, "Invalid material payload size %d > %d", (int)payload_size, (int)payload_max); + } + if (write == NULL) { + luaL_error(L, "Missing material stream writer"); + } + size_t item_size = sizeof(struct draw_primitive) * 2; + if ((size_t)count > (~(size_t)0 - 1) / item_size) { + luaL_error(L, "Material stream is too large"); + } + size_t stream_size = item_size * (size_t)count; + struct stream_guard *guard = push_stream_guard(L); + int guard_index = lua_gettop(L); + char *buffer = (char *)malloc(stream_size + 1); + if (buffer == NULL) { + luaL_error(L, "No memory for material stream"); + } + guard->ptr = buffer; + struct draw_primitive *stream = (struct draw_primitive *)buffer; + int i; + for (i=0; i 0) { + if (item.payload == NULL) { + luaL_error(L, "Missing material stream payload"); + } + memcpy((char *)ext_prim + sizeof(*ext), item.payload, payload_size); + } + pos->x = (int32_t)(item.x * STREAM_FIX_SCALE); + pos->y = (int32_t)(item.y * STREAM_FIX_SCALE); + pos->sprite = -material_id; + ext->sprite = item.sprite; + } + buffer[stream_size] = '\0'; + guard->ptr = NULL; + lua_pushexternalstring(L, buffer, stream_size, free_stream, NULL); + lua_remove(L, guard_index); +} + +void +material_stream_read(lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { + size_t payload_max = stream_payload_max(); + if (payload_size > payload_max) { + luaL_error(L, "Invalid material payload size %d > %d", (int)payload_size, (int)payload_max); + } + if (stream == NULL) { + luaL_error(L, "Missing material stream"); + } + if (index < 0) { + luaL_error(L, "Invalid material stream index %d", index); + } + if (out == NULL) { + luaL_error(L, "Missing material stream output"); + } + if (payload_size > 0 && payload == NULL) { + luaL_error(L, "Missing material stream payload output"); + } + const struct draw_primitive *prim = (const struct draw_primitive *)stream; + const struct draw_primitive *pos = &prim[index * 2]; + const struct draw_primitive *ext_prim = pos + 1; + const struct draw_primitive_external *ext = (const struct draw_primitive_external *)ext_prim; + if (pos->sprite != -material_id) { + luaL_error(L, "Invalid material marker %d", pos->sprite); + } + out->x = (float)pos->x * STREAM_FIX_INV_SCALE; + out->y = (float)pos->y * STREAM_FIX_INV_SCALE; + out->sprite = ext->sprite; + if (payload_size > 0) { + memcpy(payload, (const char *)ext_prim + sizeof(*ext), payload_size); + } +} diff --git a/src/extapi_types.h b/src/extapi_types.h new file mode 100644 index 0000000..3b25358 --- /dev/null +++ b/src/extapi_types.h @@ -0,0 +1,41 @@ +// AUTO GENERATED by ../src/extapi_types.temp.h, DONT EDIT + +#ifndef SOLUNA_EXTAPI_TYPES_H +#define SOLUNA_EXTAPI_TYPES_H + +#include + +#include + +#include "sokol/sokol_gfx.h" + +#define SOLUNA_EXT_API_VERSION 1 + +struct soluna_sprite_rect { + int texture; + float u; + float v; + float w; + float h; + float ox; + float oy; +}; + +struct soluna_material_stream_item { + float x; + float y; + int sprite; + const void *payload; +}; + +struct soluna_material_stream_data { + float x; + float y; + int sprite; +}; + +typedef void (*soluna_material_submit_func)(lua_State *L, void *ud, const void *stream, int n); +typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); + + +#endif diff --git a/src/extapi_types.temp.h b/src/extapi_types.temp.h new file mode 100644 index 0000000..86387cf --- /dev/null +++ b/src/extapi_types.temp.h @@ -0,0 +1,6 @@ +#ifndef SOLUNA_EXTAPI_TYPES_H +#define SOLUNA_EXTAPI_TYPES_H + +$HOST_TYPE_DECL$ + +#endif diff --git a/src/external.c b/src/external.c index 81ca034..6b074cb 100644 --- a/src/external.c +++ b/src/external.c @@ -4,12 +4,33 @@ #include struct lua_api; +struct sokol_api; +struct soluna_api; extern struct lua_api * extlua_api(); +extern struct sokol_api * extlua_sokol_api(); +extern struct soluna_api * extlua_soluna_api(); -struct extraspace { - struct lua_api * api; +struct extlua_apis { + struct lua_api * lua; + struct sokol_api * sokol; + struct soluna_api * soluna; }; +static struct extlua_apis * +host_apis() { + static struct extlua_apis apis; + apis.lua = extlua_api(); + apis.sokol = extlua_sokol_api(); + apis.soluna = extlua_soluna_api(); + return &apis; +} + +static void +init_extraspace(lua_State *L) { + struct extlua_apis **ex = (struct extlua_apis **)lua_getextraspace(L); + *ex = host_apis(); +} + static int get_reg(lua_State *L) { luaL_Reg *l = (luaL_Reg *)lua_touserdata(L, 1); @@ -82,8 +103,7 @@ register_libs_(lua_State *L) { static int load_libs(lua_State *L) { lua_State *dL = luaL_newstate(); - struct extraspace * ex = (struct extraspace *)lua_getextraspace(dL); - ex->api = extlua_api(); + init_extraspace(dL); lua_CFunction init = lua_tocfunction(L, 1); if (init == NULL) return luaL_error(L, "Need C function"); @@ -109,8 +129,7 @@ static struct preload_extlib PRELOAD; static void preload_lib(lua_State *L, lua_CFunction init, int result_index) { lua_State *dL = luaL_newstate(); - struct extraspace * ex = (struct extraspace *)lua_getextraspace(dL); - ex->api = extlua_api(); + init_extraspace(dL); init(dL); lua_pushcfunction(L, register_libs_); lua_pushvalue(L, result_index); diff --git a/src/luamods.c b/src/luamods.c index 65dd451..b01f75e 100644 --- a/src/luamods.c +++ b/src/luamods.c @@ -21,7 +21,6 @@ int luaopen_material_default(lua_State *L); int luaopen_material_text(lua_State *L); int luaopen_material_quad(lua_State *L); int luaopen_material_mask(lua_State *L); -int luaopen_material_perspective_quad(lua_State *L); int luaopen_material_blit(lua_State *L); int luaopen_soluna_app(lua_State *L); int luaopen_font_system(lua_State *L); @@ -53,7 +52,6 @@ void soluna_embed(lua_State* L) { { "soluna.material.text", luaopen_material_text }, { "soluna.material.quad", luaopen_material_quad }, { "soluna.material.mask", luaopen_material_mask }, - { "soluna.material.perspective_quad", luaopen_material_perspective_quad }, { "soluna.material.blit", luaopen_material_blit }, { "soluna.datalist", luaopen_datalist }, { "soluna.file", luaopen_soluna_file }, diff --git a/src/material/matdefault.lua b/src/material/matdefault.lua index 7df0876..d8b254d 100644 --- a/src/material/matdefault.lua +++ b/src/material/matdefault.lua @@ -1,46 +1,44 @@ local render = require "soluna.render" local defmat = require "soluna.material.default" -return function(register) - register { - name = "default", - create = function(ctx) - local state = ctx.state - local setting = ctx.settings - local inst_buffer = render.buffer { - type = "vertex", - usage = "stream", - label = "texquad-instance", - size = defmat.instance_size * setting.draw_instance, - } - local bindings = render.bindings() - bindings:vbuffer(0, inst_buffer) - bindings:view(0, state.views.storage) - bindings:sampler(0, state.default_sampler) +local ctx = ... +local state = ctx.state +local setting = ctx.settings +local inst_buffer = render.buffer { + type = "vertex", + usage = "stream", + label = "texquad-instance", + size = defmat.instance_size * setting.draw_instance, +} +local bindings = render.bindings() +bindings:vbuffer(0, inst_buffer) +bindings:view(0, state.views.storage) +bindings:sampler(0, state.default_sampler) - state.inst = assert(inst_buffer) - state.bindings = bindings - state.material = defmat.new { - inst_buffer = state.inst, - bindings = state.bindings, - uniform = state.uniform, - sr_buffer = state.srbuffer_mem, - sprite_bank = ctx.arg.bank_ptr, - tmp_buffer = ctx.tmp_buffer, - } +state.inst = assert(inst_buffer) +state.bindings = bindings +state.material = defmat.new { + inst_buffer = state.inst, + bindings = state.bindings, + uniform = state.uniform, + sr_buffer = state.srbuffer_mem, + sprite_bank = ctx.arg.bank_ptr, + tmp_buffer = ctx.tmp_buffer, +} - return { - reset = function() - bindings:base(0) - end, - submit = function(ptr, n) - state.material:submit(ptr, n) - end, - draw = function(ptr, n, tex) - bindings:view(1, state.views[tex + 1]) - state.material:draw(ptr, n, tex) - end, - } - end, - } +local material = {} + +function material.reset() + bindings:base(0) +end + +function material.submit(ptr, n) + state.material:submit(ptr, n) end + +function material.draw(ptr, n, tex) + bindings:view(1, state.views[tex + 1]) + state.material:draw(ptr, n, tex) +end + +return material diff --git a/src/material/matmask.lua b/src/material/matmask.lua index b99d055..c2b1e5f 100644 --- a/src/material/matmask.lua +++ b/src/material/matmask.lua @@ -1,45 +1,45 @@ local render = require "soluna.render" local maskmat = require "soluna.material.mask" -return function(register) - register { - name = "mask", - create = function(ctx) - local state = ctx.state - state.mask_inst = render.buffer { - type = "vertex", - usage = "stream", - label = "mask-instance", - size = maskmat.instance_size * ctx.settings.draw_instance, - } - - local mask_bindings = render.bindings() - mask_bindings:vbuffer(0, state.mask_inst) - mask_bindings:view(0, state.views.storage) - mask_bindings:sampler(0, state.default_sampler) - - state.mask_bindings = mask_bindings - state.material_mask = maskmat.new { - inst_buffer = state.mask_inst, - bindings = state.mask_bindings, - uniform = state.uniform, - sr_buffer = state.srbuffer_mem, - sprite_bank = ctx.arg.bank_ptr, - tmp_buffer = ctx.tmp_buffer, - } - - return { - reset = function() - mask_bindings:base(0) - end, - submit = function(ptr, n) - state.material_mask:submit(ptr, n) - end, - draw = function(ptr, n, tex) - mask_bindings:view(1, state.views[tex + 1]) - state.material_mask:draw(ptr, n, tex) - end, - } - end, - } +local ctx = ... +local state = ctx.state +maskmat.set_material_id(ctx.id) + +state.mask_inst = render.buffer { + type = "vertex", + usage = "stream", + label = "mask-instance", + size = maskmat.instance_size * ctx.settings.draw_instance, +} + +local mask_bindings = render.bindings() +mask_bindings:vbuffer(0, state.mask_inst) +mask_bindings:view(0, state.views.storage) +mask_bindings:sampler(0, state.default_sampler) + +state.mask_bindings = mask_bindings +state.material_mask = maskmat.new { + inst_buffer = state.mask_inst, + bindings = state.mask_bindings, + uniform = state.uniform, + sr_buffer = state.srbuffer_mem, + sprite_bank = ctx.arg.bank_ptr, + tmp_buffer = ctx.tmp_buffer, +} + +local material = {} + +function material.reset() + mask_bindings:base(0) end + +function material.submit(ptr, n) + state.material_mask:submit(ptr, n) +end + +function material.draw(ptr, n, tex) + mask_bindings:view(1, state.views[tex + 1]) + state.material_mask:draw(ptr, n, tex) +end + +return material diff --git a/src/material/matpquad.lua b/src/material/matpquad.lua deleted file mode 100644 index d3f4b18..0000000 --- a/src/material/matpquad.lua +++ /dev/null @@ -1,43 +0,0 @@ -local render = require "soluna.render" -local pqmat = require "soluna.material.perspective_quad" - -return function(register) - register { - name = "perspective_quad", - create = function(ctx) - local state = ctx.state - state.perspective_quad_inst = render.buffer { - type = "vertex", - usage = "stream", - label = "perspective-quad-instance", - size = pqmat.instance_size * ctx.settings.draw_instance, - } - - local perspective_quad_bindings = render.bindings() - perspective_quad_bindings:vbuffer(0, state.perspective_quad_inst) - perspective_quad_bindings:sampler(0, state.default_sampler) - - state.perspective_quad_bindings = perspective_quad_bindings - state.material_perspective_quad = pqmat.new { - inst_buffer = state.perspective_quad_inst, - bindings = state.perspective_quad_bindings, - uniform = state.uniform, - sprite_bank = ctx.arg.bank_ptr, - tmp_buffer = ctx.tmp_buffer, - } - - return { - reset = function() - perspective_quad_bindings:base(0) - end, - submit = function(ptr, n) - state.material_perspective_quad:submit(ptr, n) - end, - draw = function(ptr, n, tex) - perspective_quad_bindings:view(1, state.views[tex + 1]) - state.material_perspective_quad:draw(ptr, n, tex) - end, - } - end, - } -end diff --git a/src/material/matquad.lua b/src/material/matquad.lua index 47ab4e5..201c8eb 100644 --- a/src/material/matquad.lua +++ b/src/material/matquad.lua @@ -1,42 +1,42 @@ local render = require "soluna.render" local quadmat = require "soluna.material.quad" -return function(register) - register { - name = "quad", - create = function(ctx) - local state = ctx.state - state.quad_inst = render.buffer { - type = "vertex", - usage = "stream", - label = "quad-instance", - size = quadmat.instance_size * ctx.settings.draw_instance, - } - - local quad_bindings = render.bindings() - quad_bindings:vbuffer(0, state.quad_inst) - quad_bindings:view(0, state.views.storage) - - state.quad_bindings = quad_bindings - state.material_quad = quadmat.new { - inst_buffer = state.quad_inst, - bindings = state.quad_bindings, - uniform = state.uniform, - sr_buffer = state.srbuffer_mem, - tmp_buffer = ctx.tmp_buffer, - } - - return { - reset = function() - quad_bindings:base(0) - end, - submit = function(ptr, n) - state.material_quad:submit(ptr, n) - end, - draw = function(ptr, n) - state.material_quad:draw(ptr, n) - end, - } - end, - } +local ctx = ... +local state = ctx.state +quadmat.set_material_id(ctx.id) + +state.quad_inst = render.buffer { + type = "vertex", + usage = "stream", + label = "quad-instance", + size = quadmat.instance_size * ctx.settings.draw_instance, +} + +local quad_bindings = render.bindings() +quad_bindings:vbuffer(0, state.quad_inst) +quad_bindings:view(0, state.views.storage) + +state.quad_bindings = quad_bindings +state.material_quad = quadmat.new { + inst_buffer = state.quad_inst, + bindings = state.quad_bindings, + uniform = state.uniform, + sr_buffer = state.srbuffer_mem, + tmp_buffer = ctx.tmp_buffer, +} + +local material = {} + +function material.reset() + quad_bindings:base(0) end + +function material.submit(ptr, n) + state.material_quad:submit(ptr, n) +end + +function material.draw(ptr, n) + state.material_quad:draw(ptr, n) +end + +return material diff --git a/src/material/mattext.lua b/src/material/mattext.lua index acb0855..68507a9 100644 --- a/src/material/mattext.lua +++ b/src/material/mattext.lua @@ -1,53 +1,53 @@ local render = require "soluna.render" local textmat = require "soluna.material.text" -return function(register) - register { - name = "text", - create = function(ctx) - local state = ctx.state - local setting = ctx.settings - local text_bindings - local text_sampler_desc = setting.text_sampler - if text_sampler_desc then - text_sampler_desc.label = text_sampler_desc.label or "text-sampler" - state.text_sampler = render.sampler(text_sampler_desc) - state.text_inst = render.buffer { - type = "vertex", - usage = "stream", - label = "text-instance", - size = textmat.instance_size * setting.draw_instance, - } - text_bindings = render.bindings() - text_bindings:vbuffer(0, state.text_inst) - text_bindings:view(0, state.views.storage) - text_bindings:sampler(0, state.text_sampler) - else - state.text_inst = state.inst - text_bindings = state.bindings - end - state.text_bindings = text_bindings - state.material_text = textmat.normal { - inst_buffer = state.text_inst, - bindings = state.text_bindings, - uniform = state.uniform, - sr_buffer = state.srbuffer_mem, - font_manager = ctx.font.cobj, - tmp_buffer = ctx.tmp_buffer, - } +local ctx = ... +local state = ctx.state +local setting = ctx.settings +textmat.set_material_id(ctx.id) - return { - reset = function() - text_bindings:base(0) - end, - submit = function(ptr, n) - state.material_text:submit(ptr, n) - end, - draw = function(ptr, n) - text_bindings:view(1, state.views.font) - state.material_text:draw(ptr, n) - end, - } - end, +local text_bindings +local text_sampler_desc = setting.text_sampler +if text_sampler_desc then + text_sampler_desc.label = text_sampler_desc.label or "text-sampler" + state.text_sampler = render.sampler(text_sampler_desc) + state.text_inst = render.buffer { + type = "vertex", + usage = "stream", + label = "text-instance", + size = textmat.instance_size * setting.draw_instance, } + text_bindings = render.bindings() + text_bindings:vbuffer(0, state.text_inst) + text_bindings:view(0, state.views.storage) + text_bindings:sampler(0, state.text_sampler) +else + state.text_inst = state.inst + text_bindings = state.bindings end +state.text_bindings = text_bindings +state.material_text = textmat.normal { + inst_buffer = state.text_inst, + bindings = state.text_bindings, + uniform = state.uniform, + sr_buffer = state.srbuffer_mem, + font_manager = ctx.font.cobj, + tmp_buffer = ctx.tmp_buffer, +} + +local material = {} + +function material.reset() + text_bindings:base(0) +end + +function material.submit(ptr, n) + state.material_text:submit(ptr, n) +end + +function material.draw(ptr, n) + text_bindings:view(1, state.views.font) + state.material_text:draw(ptr, n) +end + +return material diff --git a/src/material_mask.c b/src/material_mask.c index cc0798c..280973a 100644 --- a/src/material_mask.c +++ b/src/material_mask.c @@ -40,6 +40,8 @@ struct material_mask { struct tmp_buffer tmp; }; +static int material_id = 0; + static void submit(lua_State *L, void *m_, struct draw_primitive *prim, int n) { struct material_mask *m =(struct material_mask *)m_; @@ -48,7 +50,7 @@ submit(lua_State *L, void *m_, struct draw_primitive *prim, int n) { int i; for (i=0;isprite == -MATERIAL_MASK); + assert(p->sprite == -material_id); struct mask * mask = (struct mask *)&prim[i*2+1]; @@ -117,6 +119,16 @@ lmaterial_mask_draw_ex(lua_State *L) { return lmaterial_mask_draw_(L, 1); } +static int +lset_material_id(lua_State *L) { + int id = luaL_checkinteger(L, 1); + if (id <= 0) { + return luaL_error(L, "Invalid mask material id %d", id); + } + material_id = id; + return 0; +} + static void init_pipeline(struct material_mask *p) { sg_pipeline_desc desc = { @@ -173,11 +185,14 @@ struct mask_primitive { static int lmask(lua_State *L) { + if (material_id <= 0) { + return luaL_error(L, "Mask material is not registered"); + } struct mask_primitive prim; prim.pos.x = 0; prim.pos.y = 0; prim.pos.sr = 0; - prim.pos.sprite = -MATERIAL_MASK; + prim.pos.sprite = -material_id; prim.u.m.header.sprite = luaL_checkinteger(L, 1) - 1; uint32_t color = luaL_checkinteger(L, 2); if (!(color & 0xff000000)) @@ -194,6 +209,7 @@ int luaopen_material_mask(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { + { "set_material_id", lset_material_id }, { "mask", lmask }, { "new", lnew_material_mask }, { "instance_size", NULL }, diff --git a/src/material_perspective_quad.c b/src/material_perspective_quad.c deleted file mode 100644 index 92c787c..0000000 --- a/src/material_perspective_quad.c +++ /dev/null @@ -1,462 +0,0 @@ -#include -#include -#include -#include -#include - -#include "sokol/sokol_gfx.h" -#include "perspective_quad.glsl.h" -#include "batch.h" -#include "spritemgr.h" -#include "material_util.h" -#include "render_bindings.h" -#include "tmpbuffer.h" - -#define PQUAD_CORNER_N 4 -#define PQUAD_INFO_CORNER_MASK 0x3u -#define PQUAD_INFO_USE_SPRITE_RECT 0x4u -#define PQUAD_PACK_MASK_16 0xffffu -#define PQUAD_OFF_BIAS 0x8000 -#define PQUAD_POS_FIX_SCALE 256.0f -#define PQUAD_POS_FIX_INV_SCALE (1.0f / PQUAD_POS_FIX_SCALE) - -struct color { - unsigned char channel[4]; -}; - -struct pquad_meta { - struct draw_primitive_external header; - uint32_t info; - float q; - struct color color; -}; - -struct corner_primitive { - struct draw_primitive pos; - union { - struct draw_primitive dummy; - struct pquad_meta meta; - } u; -}; - -struct inst_object { - float pos_h0[3]; - float pos_h1[3]; - float pos_h2[3]; - float uv_rect[4]; - float q[4]; - struct color color; -}; - -struct material_perspective_quad { - sg_pipeline pip; - sg_buffer inst; - struct soluna_render_bindings *bind; - vs_params_t *uniform; - struct sprite_bank *bank; - struct tmp_buffer tmp; -}; - -#define PQUAD_EPSILON 0.000001f - -struct sprite_rect_basis { - float scale_x; - float scale_y; - float shear_x; - float shear_y; - float tx; - float ty; -}; - -struct sprite_rect_data { - float u; - float v; - float w; - float h; - float ox; - float oy; -}; - -static void -set_position_homography(const float pos[PQUAD_CORNER_N][2], struct inst_object *inst) { - const float x0 = pos[0][0], y0 = pos[0][1]; - const float x1 = pos[1][0], y1 = pos[1][1]; - const float x2 = pos[2][0], y2 = pos[2][1]; - const float x3 = pos[3][0], y3 = pos[3][1]; - - const float sx = x0 - x1 + x3 - x2; - const float sy = y0 - y1 + y3 - y2; - const float dx1 = x1 - x3; - const float dx2 = x2 - x3; - const float dy1 = y1 - y3; - const float dy2 = y2 - y3; - const float det = dx1 * dy2 - dx2 * dy1; - - float m31 = 0.0f; - float m32 = 0.0f; - if (fabsf(det) > PQUAD_EPSILON) { - m31 = (sx * dy2 - sy * dx2) / det; - m32 = (sy * dx1 - sx * dy1) / det; - } - - /* M = [m11 m12 m13; m21 m22 m23; m31 m32 1] */ - const float m11 = x1 - x0 + m31 * x1; - const float m12 = x2 - x0 + m32 * x2; - const float m13 = x0; - const float m21 = y1 - y0 + m31 * y1; - const float m22 = y2 - y0 + m32 * y2; - const float m23 = y0; - - inst->pos_h0[0] = m11; - inst->pos_h0[1] = m21; - inst->pos_h0[2] = m31; - inst->pos_h1[0] = m12; - inst->pos_h1[1] = m22; - inst->pos_h1[2] = m32; - inst->pos_h2[0] = m13; - inst->pos_h2[1] = m23; - inst->pos_h2[2] = 1.0f; -} - -static inline int -perspective_quad_count(lua_State *L, int prim_n) { - if (prim_n % PQUAD_CORNER_N != 0) { - luaL_error(L, "Invalid perspective quad primitive count %d", prim_n); - return 0; - } - return prim_n / PQUAD_CORNER_N; -} - -static inline struct sprite_rect_data -unpack_sprite_rect(const struct sprite_rect *r) { - struct sprite_rect_data out; - out.u = (float)(r->u >> 16); - out.v = (float)(r->v >> 16); - out.w = (float)(r->u & PQUAD_PACK_MASK_16); - out.h = (float)(r->v & PQUAD_PACK_MASK_16); - out.ox = (float)((r->off >> 16) & PQUAD_PACK_MASK_16) - PQUAD_OFF_BIAS; - out.oy = (float)(r->off & PQUAD_PACK_MASK_16) - PQUAD_OFF_BIAS; - return out; -} - -static inline void -decode_sprite_rect_basis(struct sprite_rect_basis *basis, uint32_t corner, const struct draw_primitive *p) { - float x = (float)p->x * PQUAD_POS_FIX_INV_SCALE; - float y = (float)p->y * PQUAD_POS_FIX_INV_SCALE; - switch (corner) { - case 0: - basis->scale_x = x; - basis->scale_y = y; - break; - case 1: - basis->shear_x = x; - basis->shear_y = y; - break; - case 2: - basis->tx = x; - basis->ty = y; - break; - } -} - -static inline void -build_quad_from_rect(const struct sprite_rect_basis *basis, const struct sprite_rect_data *rect, float pos[PQUAD_CORNER_N][2]) { - float scale_x = basis->scale_x - basis->tx; - float scale_y = basis->scale_y - basis->ty; - float shear_x = basis->shear_x - basis->tx; - float shear_y = basis->shear_y - basis->ty; - int corner; - for (corner=0; cornerw - rect->ox) : -rect->ox; - float y = (corner >> 1) ? (rect->h - rect->oy) : -rect->oy; - pos[corner][0] = x * scale_x + y * shear_x + basis->tx; - pos[corner][1] = x * shear_y + y * scale_y + basis->ty; - } -} - -static void -submit(lua_State *L, void *m_, struct draw_primitive *prim, int n) { - struct material_perspective_quad *m = (struct material_perspective_quad *)m_; - struct inst_object *tmp = TMPBUFFER_PTR(struct inst_object, &m->tmp); - struct sprite_rect *rect = m->bank->rect; - int out_n = perspective_quad_count(L, n); - int i; - for (i=0;isprite == -MATERIAL_PERSPECTIVE_QUAD); - struct pquad_meta *meta = (struct pquad_meta *)&prim[(base + j) * 2 + 1]; - uint32_t flags = meta->info & PQUAD_INFO_USE_SPRITE_RECT; - if (j == 0) { - sprite = meta->header.sprite; - stream_flags = flags; - inst->color = meta->color; - } else if (meta->header.sprite != sprite || flags != stream_flags) { - luaL_error(L, "Invalid perspective quad stream"); - } - - uint32_t corner = meta->info & PQUAD_INFO_CORNER_MASK; - if (corner >= PQUAD_CORNER_N) - luaL_error(L, "Invalid perspective quad corner %u", corner); - - if (stream_flags & PQUAD_INFO_USE_SPRITE_RECT) { - decode_sprite_rect_basis(&sprite_rect_basis, corner, p); - } else { - pos[corner][0] = (float)p->x * PQUAD_POS_FIX_INV_SCALE; - pos[corner][1] = (float)p->y * PQUAD_POS_FIX_INV_SCALE; - } - - float q = meta->q; - if (q <= PQUAD_EPSILON) { - q = PQUAD_EPSILON; - } - inst->q[corner] = q; - } - struct sprite_rect *r = &rect[sprite]; - struct sprite_rect_data sprite_rect = unpack_sprite_rect(r); - if (stream_flags & PQUAD_INFO_USE_SPRITE_RECT) { - build_quad_from_rect(&sprite_rect_basis, &sprite_rect, pos); - } - set_position_homography(pos, inst); - - inst->uv_rect[0] = sprite_rect.u; - inst->uv_rect[1] = sprite_rect.v; - inst->uv_rect[2] = sprite_rect.w; - inst->uv_rect[3] = sprite_rect.h; - } - sg_append_buffer(m->inst, &(sg_range) { tmp , out_n * sizeof(tmp[0]) }); -} - -static int -lmaterial_perspective_quad_submit(lua_State *L) { - struct material_perspective_quad *m = (struct material_perspective_quad *)luaL_checkudata(L, 1, "SOLUNA_MATERIAL_PERSPECTIVE_QUAD"); - int inst_batch_n = TMPBUFFER_SIZE(struct inst_object, &m->tmp); - if (inst_batch_n < 1) { - return luaL_error(L, "Perspective quad tmp buffer is too small"); - } - int batch_n = inst_batch_n * PQUAD_CORNER_N; - util_submit_material(L, batch_n, m, submit); - return 0; -} - -static inline int -lmaterial_perspective_quad_draw_(lua_State *L, int ex) { - struct material_perspective_quad *m = (struct material_perspective_quad *)luaL_checkudata(L, 1, "SOLUNA_MATERIAL_PERSPECTIVE_QUAD"); - int prim_n = luaL_checkinteger(L, 3); - if (prim_n <= 0) - return 0; - int quad_n = perspective_quad_count(L, prim_n); - - sg_apply_pipeline(m->pip); - sg_apply_uniforms(UB_vs_params, &(sg_range){ m->uniform, sizeof(vs_params_t) }); - - if (ex) { - sg_apply_bindings(&m->bind->bindings); - sg_draw_ex(0, 4, quad_n, 0, m->bind->base); - } else { - size_t base = m->bind->base * sizeof(struct inst_object); - m->bind->bindings.vertex_buffer_offsets[0] += base; - sg_apply_bindings(&m->bind->bindings); - sg_draw(0, 4, quad_n); - m->bind->bindings.vertex_buffer_offsets[0] -= base; - } - m->bind->base += quad_n; - return 0; -} - -static int -lmaterial_perspective_quad_draw(lua_State *L) { - return lmaterial_perspective_quad_draw_(L, 0); -} - -static int -lmaterial_perspective_quad_draw_ex(lua_State *L) { - return lmaterial_perspective_quad_draw_(L, 1); -} - -static void -init_pipeline(struct material_perspective_quad *p) { - sg_pipeline_desc desc = { - .layout.attrs = { - [ATTR_perspective_quad_pos_h0].format = SG_VERTEXFORMAT_FLOAT3, - [ATTR_perspective_quad_pos_h1].format = SG_VERTEXFORMAT_FLOAT3, - [ATTR_perspective_quad_pos_h2].format = SG_VERTEXFORMAT_FLOAT3, - [ATTR_perspective_quad_uv_rect].format = SG_VERTEXFORMAT_FLOAT4, - [ATTR_perspective_quad_q].format = SG_VERTEXFORMAT_FLOAT4, - [ATTR_perspective_quad_color].format = SG_VERTEXFORMAT_UBYTE4N, - }, - }; - p->pip = util_make_pipeline(&desc, perspective_quad_shader_desc, "perspective-quad-pipeline", 1); -} - -static int -lnew_material_perspective_quad(lua_State *L) { - luaL_checktype(L, 1, LUA_TTABLE); - struct material_perspective_quad *m = (struct material_perspective_quad *)lua_newuserdatauv(L, sizeof(*m), 5); - init_pipeline(m); - util_ref_object(L, &m->inst, 1, "inst_buffer", "SOKOL_BUFFER", 0); - util_ref_object(L, &m->bind, 2, "bindings", "SOKOL_BINDINGS", 1); - util_ref_object(L, &m->uniform, 3, "uniform", "SOKOL_UNIFORM", 1); - if (lua_getfield(L, 1, "sprite_bank") != LUA_TLIGHTUSERDATA) { - return luaL_error(L, "Missing .sprite_bank"); - } - m->bank = lua_touserdata(L, -1); - lua_pop(L, 1); - tmp_buffer_init(L, &m->tmp, 4, "tmp_buffer"); - - if (luaL_newmetatable(L, "SOLUNA_MATERIAL_PERSPECTIVE_QUAD")) { - luaL_Reg l[] = { - { "__index", NULL }, - { "submit", lmaterial_perspective_quad_submit }, - { "draw", DRAWFUNC(lmaterial_perspective_quad_draw) }, - { NULL, NULL }, - }; - luaL_setfuncs(L, l, 0); - - lua_pushvalue(L, -1); - lua_setfield(L, -2, "__index"); - } - lua_setmetatable(L, -2); - return 1; -} - -static inline float -get_number_field(lua_State *L, int index, const char *field, float defv) { - float v; - lua_getfield(L, index, field); - v = luaL_optnumber(L, -1, defv); - lua_pop(L, 1); - return v; -} - -static int -get_quad(lua_State *L, int index, float quad[8]) { - if (lua_getfield(L, index, "quad") == LUA_TTABLE) { - int i; - for (i=0;i<8;i++) { - lua_geti(L, -1, i + 1); - quad[i] = luaL_checknumber(L, -1); - lua_pop(L, 1); - } - lua_pop(L, 1); - return 0; - } - lua_pop(L, 1); - return 1; -} - -static void -get_q(lua_State *L, int index, float q[4]) { - int i; - if (lua_getfield(L, index, "q") != LUA_TTABLE) { - for (i=0;i<4;i++) { - q[i] = 1.0f; - } - lua_pop(L, 1); - return; - } - for (i=0;i<4;i++) { - lua_geti(L, -1, i + 1); - q[i] = luaL_optnumber(L, -1, 1.0f); - lua_pop(L, 1); - } - lua_pop(L, 1); -} - -static struct color -get_color(lua_State *L, int index) { - uint32_t color; - struct color c; - lua_getfield(L, index, "color"); - color = (uint32_t)luaL_optinteger(L, -1, 0xffffffff); - if (!(color & 0xff000000)) - color |= 0xff000000; - c.channel[0] = (color >> 16) & 0xff; - c.channel[1] = (color >> 8) & 0xff; - c.channel[2] = color & 0xff; - c.channel[3] = (color >> 24) & 0xff; - lua_pop(L, 1); - return c; -} - -static int -lperspective_quad_sprite(lua_State *L) { - int sprite = luaL_checkinteger(L, 1) - 1; - luaL_checktype(L, 2, LUA_TTABLE); - - float quad[8]; - int use_sprite_rect = get_quad(L, 2, quad); - float scale_x = get_number_field(L, 2, "scale_x", 1.0f); - float scale_y = get_number_field(L, 2, "scale_y", 1.0f); - float shear_x = get_number_field(L, 2, "shear_x", 0.0f); - float shear_y = get_number_field(L, 2, "shear_y", 0.0f); - - float q[4]; - get_q(L, 2, q); - struct color color = get_color(L, 2); - - struct corner_primitive prim[PQUAD_CORNER_N]; - int i; - for (i=0;isprite == -MATERIAL_QUAD); + assert(p->sprite == -material_id); struct quad * q = (struct quad *)&prim[i*2+1]; @@ -111,6 +113,16 @@ lmateraial_quad_draw_ex(lua_State *L) { return lmateraial_quad_draw_(L, 1); } +static int +lset_material_id(lua_State *L) { + int id = luaL_checkinteger(L, 1); + if (id <= 0) { + return luaL_error(L, "Invalid quad material id %d", id); + } + material_id = id; + return 0; +} + static void init_pipeline(struct material_quad *p) { sg_pipeline_desc desc = { @@ -160,11 +172,14 @@ struct quad_primitive { static int lquad(lua_State *L) { + if (material_id <= 0) { + return luaL_error(L, "Quad material is not registered"); + } struct quad_primitive prim; prim.pos.x = 0; prim.pos.y = 0; prim.pos.sr = 0; - prim.pos.sprite = -MATERIAL_QUAD; + prim.pos.sprite = -material_id; prim.u.q.w = luaL_checkinteger(L, 1); prim.u.q.h = luaL_checkinteger(L, 2); uint32_t color = luaL_checkinteger(L, 3); @@ -183,6 +198,7 @@ int luaopen_material_quad(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { + { "set_material_id", lset_material_id }, { "quad", lquad }, { "new", lnew_material_quad }, { "instance_size", NULL }, diff --git a/src/material_text.c b/src/material_text.c index 438824f..ee954bc 100644 --- a/src/material_text.c +++ b/src/material_text.c @@ -44,6 +44,8 @@ struct material_text { struct tmp_buffer tmp; }; +static int material_id = 0; + static void submit(lua_State *L, void *m_, struct draw_primitive *prim, int n) { struct material_text *m = (struct material_text *)m_; @@ -52,7 +54,7 @@ submit(lua_State *L, void *m_, struct draw_primitive *prim, int n) { int count = 0; for (i=0;isprite == -MATERIAL_TEXT_NORMAL); + assert(p->sprite == -material_id); struct text * t = (struct text *)&prim[i*2+1]; struct font_glyph g, og; @@ -210,6 +212,9 @@ lnew_material_text_normal(lua_State *L) { static int lchar_for_batch(lua_State *L) { + if (material_id <= 0) { + return luaL_error(L, "Text material is not registered"); + } struct text * t = (struct text *)lua_touserdata(L, lua_upvalueindex(1)); t->header.sprite = -1; t->codepoint = luaL_checkinteger(L, 1); @@ -222,6 +227,20 @@ lchar_for_batch(lua_State *L) { return 1; } +static int +lset_material_id(lua_State *L) { + int id = luaL_checkinteger(L, 1); + if (id <= 0) { + return luaL_error(L, "Invalid text material id %d", id); + } + material_id = id; + lua_pushvalue(L, lua_upvalueindex(1)); + lua_pushinteger(L, id); + lua_setiuservalue(L, -2, 1); + lua_pop(L, 1); + return 0; +} + struct text_primitive { struct draw_primitive pos; union { @@ -537,7 +556,7 @@ ltext_(lua_State *L, struct position *pos) { prim[n].pos.x = ctx.x * 256; prim[n].pos.y = ctx.y * 256 + dy; prim[n].pos.sr = 0; - prim[n].pos.sprite = -MATERIAL_TEXT_NORMAL; + prim[n].pos.sprite = -material_id; } struct font_glyph g, og; @@ -672,6 +691,9 @@ parse_alignment(lua_State *L, int index) { static int ltext_block(lua_State *L) { + if (material_id <= 0) { + return luaL_error(L, "Text material is not registered"); + } luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); void * font_mgr = lua_touserdata(L, 1); int fontid = luaL_checkinteger(L, 2); @@ -703,6 +725,7 @@ luaopen_material_text(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { { "char", NULL }, + { "set_material_id", NULL }, { "block", ltext_block }, { "normal", lnew_material_text_normal }, { "instance_size", NULL }, @@ -713,8 +736,9 @@ luaopen_material_text(lua_State *L) { // char() struct text * t = lua_newuserdatauv(L, sizeof(*t), 1); memset(t, 0, sizeof(*t)); - lua_pushinteger(L, MATERIAL_TEXT_NORMAL); - lua_setiuservalue(L, -2, 1); + lua_pushvalue(L, -1); + lua_pushcclosure(L, lset_material_id, 1); + lua_setfield(L, -3, "set_material_id"); lua_pushcclosure(L, lchar_for_batch, 1); lua_setfield(L, -2, "char"); diff --git a/src/material_util.h b/src/material_util.h index 74f1c87..10f608d 100644 --- a/src/material_util.h +++ b/src/material_util.h @@ -5,11 +5,6 @@ #include "sokol/sokol_gfx.h" #include "batch.h" -#define MATERIAL_TEXT_NORMAL 1 -#define MATERIAL_QUAD 2 -#define MATERIAL_MASK 3 -#define MATERIAL_PERSPECTIVE_QUAD 4 - void util_ref_object(lua_State *L, void *ptr, int uv_index, const char *key, const char *luatype, int direct); typedef void (*util_submit_func)(lua_State *L, void *m_, struct draw_primitive *prim, int n); diff --git a/src/service/render.lua b/src/service/render.lua index 267bcaa..9a51c51 100644 --- a/src/service/render.lua +++ b/src/service/render.lua @@ -5,97 +5,56 @@ local embedsource = require "soluna.embedsource" local drawmgr = require "soluna.drawmgr" local file = require "soluna.file" -global require, assert, pairs, pcall, ipairs, print, load, type, table +global require, assert, pairs, pcall, ipairs, print, load, type local setting = require "soluna".settings() -local reset_materials - local font = {} local function create_materials(ctx) - local function load_materials() - local registry = {} - - function reset_materials(materials) - for _, desc in ipairs(registry) do - local obj = materials[desc.id] - if obj.reset then - obj.reset() - end - end - end - - local function join_path(path, name) - if path:match "/$" then - return path .. name - else - return path .. "/" .. name - end - end + local materials = {} - local function append(desc, id) - assert(type(desc.name) == "string") - assert(type(desc.create) == "function") - desc.id = id - registry[#registry + 1] = desc - return id - end + local function load_material(source, chunkname, id) + local chunk = assert(load(source, chunkname)) + local mctx = { + id = id, + state = ctx.state, + arg = ctx.arg, + tmp_buffer = ctx.tmp_buffer, + settings = ctx.settings, + font = ctx.font, + render = ctx.render, + } + local material = assert(chunk(mctx), chunkname .. " : no material returned") + assert(type(material.submit) == "function", chunkname .. " : missing submit function") + assert(type(material.draw) == "function", chunkname .. " : missing draw function") + materials[id] = material + end - local function run_source(source, chunkname, register) - local chunk = assert(load(source, chunkname)) - local callback = assert(chunk()) - assert(type(callback) == "function") - callback(register) + local MATERIAL_EXTLUA_BASE = 256 + do + local next_id = 0 + for _, name in ipairs(embedsource.material) do + local id = next_id + assert(id < MATERIAL_EXTLUA_BASE) + next_id = id + 1 + local loader = assert(embedsource.material[name]) + load_material(loader(), "@src/material/" .. name .. ".lua", id) end - local MATERIAL_EXTLUA_BASE = 256 - do - local next_id = 0 - local function register(desc) - local id = next_id - assert(id < MATERIAL_EXTLUA_BASE) - next_id = id + 1 - return append(desc, id) - end - local function load_material(name) - local loader = assert(embedsource.material[name]) - run_source(loader(), "@src/material/" .. name .. ".lua", register) - end - for _, name in ipairs(embedsource.material) do - load_material(name) - end + end + if setting.extlua_material then + local list = setting.extlua_material + if type(list) == "string" then + list = { list } end - if setting.extlua_material_path and setting.extlua_material_path ~= "" then - local path = setting.extlua_material_path - if file.attributes(path, "mode") ~= "directory" then - return registry - end - local files = {} - for name in file.dir(path) do - if name ~= "." and name ~= ".." and name:match "%.lua$" then - files[#files + 1] = name - end - end - table.sort(files) - local next_id = MATERIAL_EXTLUA_BASE - local function register(desc) - local id = next_id - next_id = id + 1 - return append(desc, id) - end - for _, name in ipairs(files) do - local fullname = join_path(path, name) - run_source(assert(file.load(fullname)), "@" .. fullname, register) - end + local path = assert(setting.extlua_material_path) + local next_id = MATERIAL_EXTLUA_BASE + for _, name in ipairs(list) do + local id = next_id + next_id = id + 1 + local fullname = assert(file.searchpath(name, path)) + load_material(file.load(fullname), "@" .. fullname, id) end - return registry - end - local materials = {} - for _, desc in ipairs(load_materials()) do - local obj = assert(desc.create(ctx)) - assert(type(obj.submit) == "function") - assert(type(obj.draw) == "function") - materials[desc.id] = obj end return materials end @@ -218,7 +177,12 @@ local function frame(count) local batch_n = #batch if update_image then update_image() end STATE.drawmgr:reset() - reset_materials(STATE.materials) + for _, obj in pairs(STATE.materials) do + if obj.reset then + obj.reset() + end + end + for i = 1, batch_n do local ptr, size = batch[i][1]() if ptr then diff --git a/test/extlua.game b/test/extlua.game index 99eec13..8f0cca1 100644 --- a/test/extlua.game +++ b/test/extlua.game @@ -1,3 +1,5 @@ entry : extlua.lua extlua_entry : extlua_init extlua_preload : sample +extlua_material : perspective_quad +extlua_material_path : extlua/material/?.lua diff --git a/test/extlua.lua b/test/extlua.lua index 8fffd6f..0eb4713 100644 --- a/test/extlua.lua +++ b/test/extlua.lua @@ -1,4 +1,130 @@ -- bin/soluna.exe test/extlua.game +local soluna = require "soluna" local foobar = require "ext.foobar" +local matpq = require "ext.material.perspective_quad" + print(foobar.hello()) +soluna.set_window_title "extlua perspective quad" + +local args = ... +local batch = args.batch +local callback = {} + +local CARD_W = 160 +local CARD_H = 196 +local HALF_W = CARD_W * 0.5 +local HALF_H = CARD_H * 0.5 +local WHITE = 0xffffffff + +local function rgba(color) + local a = color >> 24 & 0xff + local r = color >> 16 & 0xff + local g = color >> 8 & 0xff + local b = color & 0xff + return string.pack("BBBB", r, g, b, a) +end + +local function create_canvas(width, height) + local pixels = {} + local clear = rgba(0) + for i = 1, width * height do + pixels[i] = clear + end + + local canvas = {} + + function canvas.set_pixel(x, y, color) + if x < 0 or x >= width or y < 0 or y >= height then + return + end + pixels[y * width + x + 1] = rgba(color) + end + + function canvas.to_content() + return table.concat(pixels) + end + + return canvas +end + +local function make_card_sprite() + local canvas = create_canvas(CARD_W, CARD_H) + + for y = 0, CARD_H - 1 do + for x = 0, CARD_W - 1 do + local r = 40 + x * 120 // (CARD_W - 1) + local g = 56 + y * 140 // (CARD_H - 1) + local b = 224 - y * 72 // (CARD_H - 1) + canvas.set_pixel(x, y, 0xff000000 | r << 16 | g << 8 | b) + end + end + + for y = 0, CARD_H - 1 do + for x = 0, CARD_W - 1 do + if x < 3 or x >= CARD_W - 3 or y < 3 or y >= CARD_H - 3 then + canvas.set_pixel(x, y, 0xffffffff) + elseif x % 32 == 0 or y % 32 == 0 then + canvas.set_pixel(x, y, 0x80ffffff) + end + end + end + + soluna.preload { + filename = "@extlua_perspective_card", + content = canvas.to_content(), + w = CARD_W, + h = CARD_H, + } + + return soluna.load_sprites { + { + name = "card", + filename = "@extlua_perspective_card", + }, + } +end + +local sprites = make_card_sprite() +local card = assert(sprites.card) + +local function card_quad(theta) + local dist = 460.0 + local focal = 460.0 + local c = math.cos(theta) + local s = math.sin(theta) + local corners = { + { -HALF_W, -HALF_H }, + { HALF_W, -HALF_H }, + { -HALF_W, HALF_H }, + { HALF_W, HALF_H }, + } + + local quad = {} + local q = {} + for i = 1, 4 do + local x = corners[i][1] + local y = corners[i][2] + local rx = x * c + local rz = -x * s + local w = dist + rz + local scale = focal / w + + quad[#quad + 1] = rx * scale + quad[#quad + 1] = y * scale + q[i] = 1.0 / w + end + return quad, q +end + +function callback.frame(count) + local theta = math.sin(count * 0.021) * 1.15 + local quad, q = card_quad(theta) + batch:add(matpq.sprite(card, { + quad = quad, + q = q, + color = WHITE, + }), args.width * 0.5, args.height * 0.5) +end + +return callback diff --git a/test/extlua/material/perspective_quad.lua b/test/extlua/material/perspective_quad.lua new file mode 100644 index 0000000..f1e44f6 --- /dev/null +++ b/test/extlua/material/perspective_quad.lua @@ -0,0 +1,43 @@ +local render = require "soluna.render" +local pqmat = require "ext.material.perspective_quad" + +local ctx = ... +local state = ctx.state + +pqmat.set_material_id(ctx.id) + +local inst_buffer = render.buffer { + type = "vertex", + usage = "stream", + label = "extlua-perspective-quad-instance", + size = pqmat.instance_size * ctx.settings.draw_instance, +} + +local bindings = render.bindings() +bindings:vbuffer(0, inst_buffer) +bindings:sampler(0, state.default_sampler) + +local cobj = pqmat.new { + inst_buffer = inst_buffer, + bindings = bindings, + uniform = state.uniform, + sprite_bank = ctx.arg.bank_ptr, + tmp_buffer = ctx.tmp_buffer, +} + +local material = {} + +function material.reset() + cobj:reset() +end + +function material.submit(ptr, n) + cobj:submit(ptr, n) +end + +function material.draw(ptr, n, tex) + bindings:view(1, state.views[tex + 1]) + cobj:draw(ptr, n, tex) +end + +return material diff --git a/test/perspective_quad.lua b/test/perspective_quad.lua deleted file mode 100644 index 7925f0e..0000000 --- a/test/perspective_quad.lua +++ /dev/null @@ -1,226 +0,0 @@ --- To run this sample : --- bin/soluna.exe entry=test/perspective_quad.lua -local soluna = require "soluna" -local matpq = require "soluna.material.perspective_quad" -local matquad = require "soluna.material.quad" -local mattext = require "soluna.material.text" -local font = require "soluna.font" -local file = require "soluna.file" - -soluna.set_window_title "perspective quad regression matrix" - -local sprites = soluna.load_sprites "asset/sprites.dl" -local avatar = assert(sprites.avatar2) - -local CARD_W = 160 -local CARD_H = 196 -local HALF_W = CARD_W * 0.5 -local HALF_H = CARD_H * 0.5 -local TILE_BG = 0x303845ff -local WHITE = 0xffffffff -local LABEL_TEXT = 0xe7edf5 -local LABEL_H = 20 - -local function load_font() - if soluna.platform == "wasm" then - local bundled_path = "asset/font/SourceHanSansSC-Regular.ttf" - local bundled_data = file.load(bundled_path) - if bundled_data then - font.import(bundled_data) - local bundled_id = font.name "Source Han Sans SC Regular" - if bundled_id then - return bundled_id - end - end - end - - local sysfont = require "soluna.font.system" - local candidates = { - "WenQuanYi Micro Hei", - "Microsoft YaHei", - "Yuanti SC", - "Source Han Sans SC Regular", - } - for _, name in ipairs(candidates) do - local ok, data = pcall(sysfont.ttfdata, name) - if ok and data then - font.import(data) - local fontid = font.name(name) - if fontid then - return fontid - end - end - end - return nil -end - -local fontid = load_font() -local make_label -if fontid then - make_label = mattext.block(font.cobj(), fontid, 14, LABEL_TEXT, "CV") -end -local label_cache = {} - -local function card_quad(theta) - local dist = 460.0 - local focal = 460.0 - local c = math.cos(theta) - local s = math.sin(theta) - - local corners = { - { -HALF_W, -HALF_H }, - { HALF_W, -HALF_H }, - { -HALF_W, HALF_H }, - { HALF_W, HALF_H }, - } - - local quad = {} - local q = {} - for i = 1, 4 do - local x = corners[i][1] - local y = corners[i][2] - local rx = x * c - local rz = -x * s - local w = dist + rz - local scale = focal / w - - quad[#quad + 1] = rx * scale - quad[#quad + 1] = y * scale - q[i] = 1.0 / w - end - return quad, q -end - -local function draw_tile(batch, x, y, w, h, label) - local left = x - w * 0.5 - local top = y - h * 0.5 - batch:add(matquad.quad(w, h, TILE_BG), left, top) - if make_label and label then - local key = string.format("%s:%d", label, w) - local text = label_cache[key] - if text == nil then - text = make_label(label, w, LABEL_H) - label_cache[key] = text - end - batch:add(text, left, top) - end -end - -local function draw_sprite(batch, x, y, options) - batch:add(matpq.sprite(avatar, options), x, y) -end - -local args = ... -local batch = args.batch -local callback = {} -local base_scale_x = 0.58 -local base_scale_y = 0.58 - -local function draw_flip_cases(t) - local y = 126 - draw_tile(batch, 110, y, 130, 160, "base") - draw_sprite(batch, 110, y, { scale_x = base_scale_x, scale_y = base_scale_y, color = WHITE }) - - draw_tile(batch, 250, y, 130, 160, "flip_x") - draw_sprite(batch, 250, y, { scale_x = -base_scale_x, scale_y = base_scale_y, color = WHITE }) - - draw_tile(batch, 390, y, 130, 160, "flip_y") - draw_sprite(batch, 390, y, { scale_x = base_scale_x, scale_y = -base_scale_y, color = WHITE }) - - draw_tile(batch, 530, y, 130, 160, "flip_xy") - draw_sprite(batch, 530, y, { - scale_x = -base_scale_x, - scale_y = -base_scale_y, - color = WHITE, - }) - - draw_tile(batch, 670, y, 130, 160, "affine") - draw_sprite(batch, 670, y, { - scale_x = base_scale_x * 1.30, - scale_y = base_scale_y * 0.74, - shear_x = math.sin(t * 0.8) * 0.40, - shear_y = math.cos(t * 0.7) * 0.16, - color = WHITE, - }) -end - -local function draw_perspective_compare(t) - local y = args.height * 0.56 - local theta = math.sin(t * 0.72) * 1.15 - local quad, q = card_quad(theta) - local affine_q = { 1.0, 1.0, 1.0, 1.0 } - - draw_tile(batch, args.width * 0.36, y, 220, 250, "q=1") - draw_sprite(batch, args.width * 0.36, y, { - quad = quad, - q = affine_q, - color = WHITE, - }) - - draw_tile(batch, args.width * 0.64, y, 220, 250, "perspective q") - draw_sprite(batch, args.width * 0.64, y, { - quad = quad, - q = q, - color = WHITE, - }) -end - -local function draw_arbitrary_quad_cases(t) - local y = args.height - 120 - local wobble = math.sin(t * 1.1) - local quad_a = { - -80, -72, - 70, -52, - -64, 68, - 78, 82, - } - local quad_b = { - -88, -58, - 84, -90 + wobble * 10, - -74, 92, - 82, 54 + wobble * 24, - } - - draw_tile(batch, 240, y, 220, 200, "irregular") - draw_sprite(batch, 240, y, { - quad = quad_a, - q = { 1.0, 1.0, 1.0, 1.0 }, - color = WHITE, - }) - - draw_tile(batch, 490, y, 220, 200, "irregular + q") - draw_sprite(batch, 490, y, { - quad = quad_b, - q = { 1.0, 1.25, 0.86, 1.42 }, - color = WHITE, - }) -end - -local function draw_degenerate_and_extreme_q(t) - local y = args.height - 120 - local s = math.sin(t * 0.9) - local sliver = { - -90, -6, - 90, -8 + s * 2.0, - -86, 8, - 88, 6 + s * 2.0, - } - - draw_tile(batch, 740, y, 220, 200, "degenerate/extreme q") - draw_sprite(batch, 740, y, { - quad = sliver, - q = { 1.0, 0.0, -3.0, 0.00000001 }, - color = WHITE, - }) -end - -function callback.frame(count) - local t = count * 0.03 - - draw_flip_cases(t) - draw_perspective_compare(t) - draw_arbitrary_quad_cases(t) - draw_degenerate_and_extreme_q(t) -end - -return callback From 5e550cf3b9d1b533a94a64d895eab7a5bc8f4218 Mon Sep 17 00:00:00 2001 From: Hanchin Hsieh Date: Mon, 27 Apr 2026 12:45:03 +0800 Subject: [PATCH 3/5] website: support companion files --- .../astro-theme-soluna/src/client/play.ts | 65 ++++++++++++++++--- .../components/examples/ExamplePlayPage.astro | 15 ++++- website/src/content.config.ts | 5 ++ website/src/lib/content.ts | 61 ++++++++++++++++- 4 files changed, 134 insertions(+), 12 deletions(-) diff --git a/website/packages/astro-theme-soluna/src/client/play.ts b/website/packages/astro-theme-soluna/src/client/play.ts index f9831c2..92eb56b 100644 --- a/website/packages/astro-theme-soluna/src/client/play.ts +++ b/website/packages/astro-theme-soluna/src/client/play.ts @@ -28,12 +28,19 @@ interface StartOptions { interface PlayOptions { exampleSource: string + exampleGameSettings?: string + exampleRuntimeFiles?: RuntimeFile[] } interface RuntimeHandle { stop: () => void } +interface RuntimeFile { + path: string + source: string +} + declare global { interface Window { SOLUNA_PLAY_ACTIVE?: RuntimeHandle @@ -234,8 +241,8 @@ function setupCanvasResize(canvas: HTMLCanvasElement): () => void { return resize } -function buildMainGame(): string { - return [ +function buildMainGame(exampleGameSettings = ''): string { + const lines = [ 'entry : main.lua', 'high_dpi : true', 'text_sampler :', @@ -243,8 +250,39 @@ function buildMainGame(): string { ' mag_filter : linear', 'extlua_entry : extlua_init', 'extlua_preload : sample', - '', - ].join('\n') + ] + const settings = exampleGameSettings.trim() + if (settings) { + lines.push(settings) + } + lines.push('') + return lines.join('\n') +} + +function normalizeRuntimeFilePath(path: string): string { + if (path.startsWith('/') || path.includes('\\')) { + throw new Error(`Invalid runtime file path: ${path}`) + } + const parts = path.split('/') + if (parts.some(part => part === '' || part === '.' || part === '..')) { + throw new Error(`Invalid runtime file path: ${path}`) + } + return path +} + +function buildMainZip(exampleSource: string, exampleGameSettings: string, runtimeFiles: RuntimeFile[]): Uint8Array { + const entries: Record = { + 'main.lua': strToU8(exampleSource), + 'main.game': strToU8(buildMainGame(exampleGameSettings)), + } + runtimeFiles.forEach((file) => { + const runtimePath = normalizeRuntimeFilePath(file.path) + if (runtimePath === 'main.lua' || runtimePath === 'main.game') { + throw new Error(`Reserved runtime file path: ${runtimePath}`) + } + entries[runtimePath] = strToU8(file.source) + }) + return zipSync(entries) } async function destroyActiveRuntime(): Promise { @@ -286,7 +324,12 @@ async function ensureIsolation(basePath: string): Promise { } } -async function loadRuntimeAssets(basePath: string, exampleSource: string) { +async function loadRuntimeAssets( + basePath: string, + exampleSource: string, + exampleGameSettings: string, + exampleRuntimeFiles: RuntimeFile[], +) { setStatus('Preparing assets...') const assetBuffer = normalizeFileData(await fetchArrayBuffer(`${basePath}runtime/asset.zip`)) @@ -303,10 +346,7 @@ async function loadRuntimeAssets(basePath: string, exampleSource: string) { return { assetBuffer, fontZip: zipSync(fontEntries), - mainZip: zipSync({ - 'main.lua': strToU8(exampleSource), - 'main.game': strToU8(buildMainGame()), - }), + mainZip: buildMainZip(exampleSource, exampleGameSettings, exampleRuntimeFiles), sampleWasmBuffer: normalizeFileData(await sampleWasmPromise), } } @@ -379,7 +419,12 @@ export default async function initPlay(options: PlayOptions): Promise { let assets: Awaited> try { - assets = await loadRuntimeAssets(basePath, options.exampleSource) + assets = await loadRuntimeAssets( + basePath, + options.exampleSource, + options.exampleGameSettings ?? '', + options.exampleRuntimeFiles ?? [], + ) } catch (error) { const message = error instanceof Error ? error.message : String(error) diff --git a/website/packages/astro-theme-soluna/src/components/examples/ExamplePlayPage.astro b/website/packages/astro-theme-soluna/src/components/examples/ExamplePlayPage.astro index 25c59ee..80ec505 100644 --- a/website/packages/astro-theme-soluna/src/components/examples/ExamplePlayPage.astro +++ b/website/packages/astro-theme-soluna/src/components/examples/ExamplePlayPage.astro @@ -6,6 +6,11 @@ interface ExampleItem { title: string entry: string source: string + gameSettings: string + runtimeFiles: Array<{ + path: string + source: string + }> } interface Props { @@ -16,6 +21,8 @@ interface Props { const { example, examples } = Astro.props const basePath = import.meta.env.BASE_URL const sourceJson = JSON.stringify(example.source).replace(/ @@ -78,11 +85,17 @@ const sourceJson = JSON.stringify(example.source).replace(/ + + diff --git a/website/src/content.config.ts b/website/src/content.config.ts index a80d95f..8ead82e 100644 --- a/website/src/content.config.ts +++ b/website/src/content.config.ts @@ -7,6 +7,11 @@ const examples = defineCollection({ title: z.string(), entry: z.string(), source: z.string(), + gameSettings: z.string(), + runtimeFiles: z.array(z.object({ + path: z.string(), + source: z.string(), + })), }), }) diff --git a/website/src/lib/content.ts b/website/src/lib/content.ts index e3c108a..75dea94 100644 --- a/website/src/lib/content.ts +++ b/website/src/lib/content.ts @@ -1,12 +1,19 @@ -import { readdir, readFile } from 'node:fs/promises' +import { readdir, readFile, stat } from 'node:fs/promises' import path from 'node:path' import { fileURLToPath } from 'node:url' +export interface ExampleRuntimeFile { + path: string + source: string +} + export interface ExampleEntry { id: string title: string entry: string source: string + gameSettings: string + runtimeFiles: ExampleRuntimeFile[] } export interface DocBlock { @@ -38,6 +45,54 @@ export function titleize(name: string): string { .join(' ') } +async function exists(filePath: string): Promise { + return stat(filePath).then(() => true, () => false) +} + +function normalizeGameSettings(source: string): string { + const skippedKeys = new Set(['entry', 'extlua_entry', 'extlua_preload']) + return source + .split(/\r?\n/) + .filter((line) => { + const match = line.match(/^\s*([a-z_][\w.]*)\s*:/i) + return !match || !skippedKeys.has(match[1]) + }) + .join('\n') + .trim() +} + +async function loadGameSettings(id: string): Promise { + const filename = path.join(testDir, `${id}.game`) + if (!(await exists(filename))) { + return '' + } + return normalizeGameSettings(await readFile(filename, 'utf8')) +} + +async function loadRuntimeFiles(root: string, prefix: string): Promise { + if (!(await exists(root))) { + return [] + } + + const entries = await readdir(root, { withFileTypes: true }) + const files = await Promise.all(entries.map(async (entry) => { + const fullPath = path.join(root, entry.name) + const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name + if (entry.isDirectory()) { + return loadRuntimeFiles(fullPath, relativePath) + } + if (!entry.isFile()) { + return [] + } + return [{ + path: relativePath, + source: await readFile(fullPath, 'utf8'), + }] + })) + + return files.flat().sort((a, b) => a.path.localeCompare(b.path)) +} + export async function loadExamples(): Promise { const names = (await readdir(testDir)) .filter(name => name.endsWith('.lua')) @@ -47,11 +102,15 @@ export async function loadExamples(): Promise { names.map(async (name) => { const id = name.slice(0, -4) const source = await readFile(path.join(testDir, name), 'utf8') + const gameSettings = await loadGameSettings(id) + const runtimeFiles = await loadRuntimeFiles(path.join(testDir, id), id) return { id, title: titleize(id), entry: `test/${name}`, source, + gameSettings, + runtimeFiles, } }), ) From 6fa0613b5f23d6d99466aab4bf98182d231eba80 Mon Sep 17 00:00:00 2001 From: Hanchin Hsieh Date: Mon, 27 Apr 2026 15:37:50 +0800 Subject: [PATCH 4/5] rework: decouple ext material stream errors from Lua --- extlua/extlua_sample.c | 66 ++++++++--- extlua/gen_soluna.lua | 48 ++++++-- extlua/solunaapi.c | 50 +++++--- extlua/solunaapi.h | 21 +++- extlua/solunaapi_impl.c | 39 ++++--- src/extapi.c | 248 ++++++++++++++++++++++++---------------- src/extapi_types.h | 10 +- 7 files changed, 315 insertions(+), 167 deletions(-) diff --git a/extlua/extlua_sample.c b/extlua/extlua_sample.c index c110c88..402ecda 100644 --- a/extlua/extlua_sample.c +++ b/extlua/extlua_sample.c @@ -62,6 +62,16 @@ struct sprite_rect_basis { static int material_id = 0; +static void * +free_material_stream(void *ud, void *ptr, size_t osize, size_t nsize) { + (void)ud; + (void)osize; + if (nsize == 0) { + soluna_material_stream_free(ptr); + } + return NULL; +} + static sg_pipeline make_pipeline(sg_pipeline_desc *desc) { sg_shader shd = sg_make_shader(perspective_quad_shader_desc(sg_query_backend())); @@ -116,13 +126,13 @@ set_position_homography(const float pos[PQUAD_CORNER_N][2], struct pquad_inst *i inst->pos_h2[2] = 1.0f; } -static inline int -perspective_quad_count(lua_State *L, int prim_n) { +static inline soluna_material_error +perspective_quad_count(int prim_n, int *out) { if (prim_n % PQUAD_CORNER_N != 0) { - luaL_error(L, "Invalid perspective quad primitive count %d", prim_n); - return 0; + return "Invalid perspective quad primitive count"; } - return prim_n / PQUAD_CORNER_N; + *out = prim_n / PQUAD_CORNER_N; + return NULL; } static inline void @@ -161,10 +171,15 @@ build_quad_from_rect(const struct sprite_rect_basis *basis, const struct soluna_ } static void -submit(lua_State *L, void *m_, const void *stream, int n) { +submit(void *m_, void *ctx, int n) { struct material_perspective_quad *m = (struct material_perspective_quad *)m_; struct pquad_inst *tmp = (struct pquad_inst *)m->tmp_ptr; - int out_n = perspective_quad_count(L, n); + int out_n; + soluna_material_error err = perspective_quad_count(n, &out_n); + if (err != NULL) { + soluna_material_stream_error(ctx, err); + return; + } int i; for (i=0; icolor = payload.color; } else if (item.sprite != sprite || flags != stream_flags) { - luaL_error(L, "Invalid perspective quad stream"); + soluna_material_stream_error(ctx, "Invalid perspective quad stream"); + return; } uint32_t corner = payload.info & PQUAD_INFO_CORNER_MASK; if (corner >= PQUAD_CORNER_N) { - luaL_error(L, "Invalid perspective quad corner %u", corner); + soluna_material_stream_error(ctx, "Invalid perspective quad corner"); + return; } if (stream_flags & PQUAD_INFO_USE_SPRITE_RECT) { decode_sprite_rect_basis(&sprite_rect_basis, corner, &item); @@ -203,8 +222,9 @@ submit(lua_State *L, void *m_, const void *stream, int n) { inst->q[corner] = q; } struct soluna_sprite_rect sprite_rect; - if (!soluna_material_sprite_rect(L, m->bank, sprite, &sprite_rect)) { - luaL_error(L, "Invalid perspective quad sprite %d", sprite); + if (!soluna_material_sprite_rect(m->bank, sprite, &sprite_rect)) { + soluna_material_stream_error(ctx, "Invalid perspective quad sprite"); + return; } if (stream_flags & PQUAD_INFO_USE_SPRITE_RECT) { build_quad_from_rect(&sprite_rect_basis, &sprite_rect, pos); @@ -225,7 +245,12 @@ lmaterial_perspective_quad_submit(lua_State *L) { if (inst_batch_n < 1) { return luaL_error(L, "Perspective quad tmp buffer is too small"); } - soluna_material_submit(L, inst_batch_n * PQUAD_CORNER_N, m, submit); + const void *stream = lua_touserdata(L, 2); + int prim_n = luaL_checkinteger(L, 3); + soluna_material_error err = soluna_material_submit(stream, prim_n, material_id, inst_batch_n * PQUAD_CORNER_N, m, submit); + if (err != NULL) { + return luaL_error(L, "%s", err); + } return 0; } @@ -236,10 +261,14 @@ lmaterial_perspective_quad_draw(lua_State *L) { if (prim_n <= 0) { return 0; } - int quad_n = perspective_quad_count(L, prim_n); + int quad_n; + soluna_material_error err = perspective_quad_count(prim_n, &quad_n); + if (err != NULL) { + return luaL_error(L, "%s", err); + } sg_apply_pipeline(m->pip); sg_apply_uniforms(UB_vs_params, &(sg_range) { m->uniform, sizeof(vs_params_t) }); - sg_bindings bindings = soluna_material_bindings(L, m->bind); + sg_bindings bindings = soluna_material_bindings(m->bind); bindings.vertex_buffer_offsets[0] += (size_t)m->base * sizeof(struct pquad_inst); sg_apply_bindings(&bindings); sg_draw(0, 4, quad_n); @@ -468,7 +497,12 @@ lperspective_quad_sprite(lua_State *L) { ctx.shear_y = get_number_field(L, 2, "shear_y", 0.0f); get_q(L, 2, ctx.q); ctx.color = get_color(L, 2); - soluna_material_push_stream(L, material_id, PQUAD_CORNER_N, sizeof(struct pquad_payload), write_perspective_quad_stream, &ctx); + struct soluna_material_stream stream; + soluna_material_error err = soluna_material_push_stream(material_id, PQUAD_CORNER_N, sizeof(struct pquad_payload), write_perspective_quad_stream, &ctx, &stream); + if (err != NULL) { + return luaL_error(L, "%s", err); + } + lua_pushexternalstring(L, stream.data, stream.size, free_material_stream, NULL); return 1; } diff --git a/extlua/gen_soluna.lua b/extlua/gen_soluna.lua index 6d19e92..58f6b51 100644 --- a/extlua/gen_soluna.lua +++ b/extlua/gen_soluna.lua @@ -2,10 +2,12 @@ local apis = { { - ret = "void", + ret = "soluna_material_error", name = "soluna_material_submit", params = { - { type = "lua_State *", name = "L" }, + { type = "const void *", name = "stream" }, + { type = "int ", name = "prim_n" }, + { type = "int ", name = "material_id" }, { type = "int ", name = "batch_n" }, { type = "void *", name = "ud" }, { type = "soluna_material_submit_func ", name = "submit" }, @@ -15,7 +17,6 @@ local apis = { ret = "int", name = "soluna_material_sprite_rect", params = { - { type = "lua_State *", name = "L" }, { type = "void *", name = "bank" }, { type = "int ", name = "sprite" }, { type = "struct soluna_sprite_rect *", name = "out" }, @@ -25,35 +26,54 @@ local apis = { ret = "sg_bindings", name = "soluna_material_bindings", params = { - { type = "lua_State *", name = "L" }, { type = "void *", name = "bindings" }, }, }, { - ret = "void", + ret = "soluna_material_error", name = "soluna_material_push_stream", params = { - { type = "lua_State *", name = "L" }, { type = "int ", name = "material_id" }, { type = "int ", name = "count" }, { type = "size_t ", name = "payload_size" }, { type = "soluna_material_stream_write_func ", name = "write" }, { type = "void *", name = "ud" }, + { type = "struct soluna_material_stream *", name = "out" }, }, }, { ret = "void", + name = "soluna_material_stream_free", + params = { + { type = "void *", name = "ptr" }, + }, + }, + { + ret = "int", name = "soluna_material_stream_read", params = { - { type = "lua_State *", name = "L" }, - { type = "const void *", name = "stream" }, + { type = "void *", name = "ctx" }, { type = "int ", name = "index" }, - { type = "int ", name = "material_id" }, { type = "size_t ", name = "payload_size" }, { type = "void *", name = "payload" }, { type = "struct soluna_material_stream_data *", name = "out" }, }, }, + { + ret = "void", + name = "soluna_material_stream_error", + params = { + { type = "void *", name = "ctx" }, + { type = "const char *", name = "error" }, + }, + }, + { + ret = "int", + name = "soluna_material_stream_failed", + params = { + { type = "void *", name = "ctx" }, + }, + }, } local type_decl = [[ @@ -82,15 +102,19 @@ struct soluna_material_stream_data { int sprite; }; -typedef void (*soluna_material_submit_func)(lua_State *L, void *ud, const void *stream, int n); +struct soluna_material_stream { + char *data; + size_t size; +}; + +typedef const char *soluna_material_error; +typedef void (*soluna_material_submit_func)(void *ud, void *ctx, int n); typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); ]] local host_type_decl = [[ #include -#include - #include "sokol/sokol_gfx.h" ]] .. type_decl diff --git a/extlua/solunaapi.c b/extlua/solunaapi.c index 5ff7176..e312232 100644 --- a/extlua/solunaapi.c +++ b/extlua/solunaapi.c @@ -7,38 +7,56 @@ struct soluna_api { int version; - void (*material_submit) (lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit); - int (*material_sprite_rect) (lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out); - sg_bindings (*material_bindings) (lua_State *L, void *bindings); - void (*material_push_stream) (lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud); - void (*material_stream_read) (lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out); + soluna_material_error (*material_submit) (const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit); + int (*material_sprite_rect) (void *bank, int sprite, struct soluna_sprite_rect *out); + sg_bindings (*material_bindings) (void *bindings); + soluna_material_error (*material_push_stream) (int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out); + void (*material_stream_free) (void *ptr); + int (*material_stream_read) (void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); + void (*material_stream_error) (void *ctx, const char *error); + int (*material_stream_failed) (void *ctx); }; static struct soluna_api API; -void -soluna_material_submit(lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit) { - API.material_submit(L, batch_n, ud, submit); +soluna_material_error +soluna_material_submit(const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit) { + return API.material_submit(stream, prim_n, material_id, batch_n, ud, submit); } int -soluna_material_sprite_rect(lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out) { - return API.material_sprite_rect(L, bank, sprite, out); +soluna_material_sprite_rect(void *bank, int sprite, struct soluna_sprite_rect *out) { + return API.material_sprite_rect(bank, sprite, out); } sg_bindings -soluna_material_bindings(lua_State *L, void *bindings) { - return API.material_bindings(L, bindings); +soluna_material_bindings(void *bindings) { + return API.material_bindings(bindings); +} + +soluna_material_error +soluna_material_push_stream(int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out) { + return API.material_push_stream(material_id, count, payload_size, write, ud, out); } void -soluna_material_push_stream(lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud) { - API.material_push_stream(L, material_id, count, payload_size, write, ud); +soluna_material_stream_free(void *ptr) { + API.material_stream_free(ptr); +} + +int +soluna_material_stream_read(void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { + return API.material_stream_read(ctx, index, payload_size, payload, out); } void -soluna_material_stream_read(lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { - API.material_stream_read(L, stream, index, material_id, payload_size, payload, out); +soluna_material_stream_error(void *ctx, const char *error) { + API.material_stream_error(ctx, error); +} + +int +soluna_material_stream_failed(void *ctx) { + return API.material_stream_failed(ctx); } diff --git a/extlua/solunaapi.h b/extlua/solunaapi.h index 26b1da0..e59d883 100644 --- a/extlua/solunaapi.h +++ b/extlua/solunaapi.h @@ -34,15 +34,24 @@ struct soluna_material_stream_data { int sprite; }; -typedef void (*soluna_material_submit_func)(lua_State *L, void *ud, const void *stream, int n); +struct soluna_material_stream { + char *data; + size_t size; +}; + +typedef const char *soluna_material_error; +typedef void (*soluna_material_submit_func)(void *ud, void *ctx, int n); typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); void solunaapi_init(lua_State *L); -void soluna_material_submit(lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit); -int soluna_material_sprite_rect(lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out); -sg_bindings soluna_material_bindings(lua_State *L, void *bindings); -void soluna_material_push_stream(lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud); -void soluna_material_stream_read(lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out); +soluna_material_error soluna_material_submit(const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit); +int soluna_material_sprite_rect(void *bank, int sprite, struct soluna_sprite_rect *out); +sg_bindings soluna_material_bindings(void *bindings); +soluna_material_error soluna_material_push_stream(int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out); +void soluna_material_stream_free(void *ptr); +int soluna_material_stream_read(void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); +void soluna_material_stream_error(void *ctx, const char *error); +int soluna_material_stream_failed(void *ctx); #endif diff --git a/extlua/solunaapi_impl.c b/extlua/solunaapi_impl.c index 5295b34..1ba71d8 100644 --- a/extlua/solunaapi_impl.c +++ b/extlua/solunaapi_impl.c @@ -2,8 +2,6 @@ #include -#include - #include "sokol/sokol_gfx.h" #define SOLUNA_EXT_API_VERSION 1 @@ -31,24 +29,36 @@ struct soluna_material_stream_data { int sprite; }; -typedef void (*soluna_material_submit_func)(lua_State *L, void *ud, const void *stream, int n); +struct soluna_material_stream { + char *data; + size_t size; +}; + +typedef const char *soluna_material_error; +typedef void (*soluna_material_submit_func)(void *ud, void *ctx, int n); typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); -extern void material_submit(lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit); -extern int material_sprite_rect(lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out); -extern sg_bindings material_bindings(lua_State *L, void *bindings); -extern void material_push_stream(lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud); -extern void material_stream_read(lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out); +extern soluna_material_error material_submit(const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit); +extern int material_sprite_rect(void *bank, int sprite, struct soluna_sprite_rect *out); +extern sg_bindings material_bindings(void *bindings); +extern soluna_material_error material_push_stream(int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out); +extern void material_stream_free(void *ptr); +extern int material_stream_read(void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); +extern void material_stream_error(void *ctx, const char *error); +extern int material_stream_failed(void *ctx); struct soluna_api { int version; - void (*material_submit) (lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit); - int (*material_sprite_rect) (lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out); - sg_bindings (*material_bindings) (lua_State *L, void *bindings); - void (*material_push_stream) (lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud); - void (*material_stream_read) (lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out); + soluna_material_error (*material_submit) (const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit); + int (*material_sprite_rect) (void *bank, int sprite, struct soluna_sprite_rect *out); + sg_bindings (*material_bindings) (void *bindings); + soluna_material_error (*material_push_stream) (int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out); + void (*material_stream_free) (void *ptr); + int (*material_stream_read) (void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); + void (*material_stream_error) (void *ctx, const char *error); + int (*material_stream_failed) (void *ctx); }; struct soluna_api * @@ -60,7 +70,10 @@ extlua_soluna_api() { material_sprite_rect, material_bindings, material_push_stream, + material_stream_free, material_stream_read, + material_stream_error, + material_stream_failed, }; return &api; } diff --git a/src/extapi.c b/src/extapi.c index 2e45b77..8fb2893 100644 --- a/src/extapi.c +++ b/src/extapi.c @@ -1,5 +1,4 @@ -#include -#include +#include #include #include #include @@ -13,65 +12,110 @@ #define STREAM_FIX_SCALE 256.0f #define STREAM_FIX_INV_SCALE (1.0f / STREAM_FIX_SCALE) +#define STREAM_ERROR_SIZE 128 -typedef void (*material_submit_stride_func)(lua_State *L, void *ud, void *stream, int n); +#if defined(_MSC_VER) +#define SOLUNA_THREAD_LOCAL __declspec(thread) +#elif defined(__GNUC__) +#define SOLUNA_THREAD_LOCAL __thread +#else +#define SOLUNA_THREAD_LOCAL _Thread_local +#endif -static void -submit_material_stride(lua_State *L, int batch_n, void *ud, material_submit_stride_func submit, size_t stride) { - char *stream = lua_touserdata(L, 2); - int prim_n = luaL_checkinteger(L, 3); - if (stream == NULL) { - luaL_error(L, "Missing material stream"); +typedef void (*material_submit_stride_func)(void *ud, void *ctx, int n); + +struct material_stream_context { + const char *data; + int n; + int material_id; + soluna_material_error error; + char error_buffer[STREAM_ERROR_SIZE]; +}; + +static SOLUNA_THREAD_LOCAL char submit_error_buffer[STREAM_ERROR_SIZE]; + +static soluna_material_error +copy_error(char *buffer, size_t size, const char *error) { + const char *message = error != NULL ? error : "Material stream error"; + size_t len = strlen(message); + if (len >= size) { + len = size - 1; + } + memcpy(buffer, message, len); + buffer[len] = '\0'; + return buffer; +} + +void +material_stream_error(void *ctx_, const char *error) { + struct material_stream_context *ctx = (struct material_stream_context *)ctx_; + if (ctx != NULL && ctx->error == NULL) { + ctx->error = copy_error(ctx->error_buffer, sizeof(ctx->error_buffer), error); + } +} + +int +material_stream_failed(void *ctx_) { + struct material_stream_context *ctx = (struct material_stream_context *)ctx_; + return ctx == NULL || ctx->error != NULL; +} + +static soluna_material_error +submit_material_stride(const void *data_, int prim_n, int material_id, int batch_n, void *ud, material_submit_stride_func submit, size_t stride) { + const char *data = (const char *)data_; + if (data == NULL) { + return "Missing material stream"; + } + if (material_id <= 0) { + return "Invalid material id"; } if (batch_n <= 0) { - luaL_error(L, "Invalid material submit batch %d", batch_n); + return "Invalid material submit batch"; } if (prim_n < 0) { - luaL_error(L, "Invalid material primitive count %d", prim_n); + return "Invalid material primitive count"; } if (submit == NULL) { - luaL_error(L, "Missing material submit function"); + return "Missing material submit function"; } if (stride == 0) { - luaL_error(L, "Invalid material submit stride"); + return "Invalid material submit stride"; } int i = 0; for (;;) { int n = prim_n - i; + struct material_stream_context ctx = { + .data = data, + .n = n > batch_n ? batch_n : n, + .material_id = material_id, + .error = NULL, + .error_buffer = { 0 }, + }; if (n > batch_n) { - submit(L, ud, stream, batch_n); + submit(ud, &ctx, batch_n); + if (ctx.error != NULL) { + return copy_error(submit_error_buffer, sizeof(submit_error_buffer), ctx.error); + } i += batch_n; - stream += stride * batch_n; + data += stride * batch_n; } else { - submit(L, ud, stream, n); + submit(ud, &ctx, n); + if (ctx.error != NULL) { + return copy_error(submit_error_buffer, sizeof(submit_error_buffer), ctx.error); + } break; } } + return NULL; } -struct material_submit_context { - void *ud; - soluna_material_submit_func submit; -}; - -static void -submit_external_material(lua_State *L, void *ctx_, void *stream, int n) { - struct material_submit_context *ctx = (struct material_submit_context *)ctx_; - ctx->submit(L, ctx->ud, stream, n); -} - -void -material_submit(lua_State *L, int batch_n, void *ud, soluna_material_submit_func submit) { - struct material_submit_context ctx = { - .ud = ud, - .submit = submit, - }; - submit_material_stride(L, batch_n, &ctx, submit_external_material, sizeof(struct draw_primitive) * 2); +soluna_material_error +material_submit(const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit) { + return submit_material_stride(stream, prim_n, material_id, batch_n, ud, submit, sizeof(struct draw_primitive) * 2); } int -material_sprite_rect(lua_State *L, void *bank, int sprite, struct soluna_sprite_rect *out) { - (void)L; +material_sprite_rect(void *bank, int sprite, struct soluna_sprite_rect *out) { struct sprite_bank *b = (struct sprite_bank *)bank; if (b == NULL || out == NULL || sprite < 0 || sprite >= b->n) { return 0; @@ -88,11 +132,9 @@ material_sprite_rect(lua_State *L, void *bank, int sprite, struct soluna_sprite_ } sg_bindings -material_bindings(lua_State *L, void *bindings) { +material_bindings(void *bindings) { struct soluna_render_bindings *b = (struct soluna_render_bindings *)bindings; - if (b == NULL) { - luaL_error(L, "Missing material bindings"); - } + assert(b != NULL); return b->bindings; } @@ -101,70 +143,40 @@ stream_payload_max(void) { return sizeof(struct draw_primitive) - sizeof(struct draw_primitive_external); } -struct stream_guard { - void *ptr; -}; - -static int -stream_guard_gc(lua_State *L) { - struct stream_guard *guard = (struct stream_guard *)lua_touserdata(L, 1); - free(guard->ptr); - guard->ptr = NULL; - return 0; -} - -static struct stream_guard * -push_stream_guard(lua_State *L) { - struct stream_guard *guard = (struct stream_guard *)lua_newuserdatauv(L, sizeof(*guard), 0); - guard->ptr = NULL; - if (luaL_newmetatable(L, "SOLUNA_MATERIAL_STREAM_GUARD")) { - luaL_Reg l[] = { - { "__gc", stream_guard_gc }, - { NULL, NULL }, - }; - luaL_setfuncs(L, l, 0); - } - lua_setmetatable(L, -2); - return guard; -} - -static void * -free_stream(void *ud, void *ptr, size_t osize, size_t nsize) { - (void)ud; - (void)osize; - if (nsize == 0) { - free(ptr); - } - return NULL; +void +material_stream_free(void *ptr) { + free(ptr); } -void -material_push_stream(lua_State *L, int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud) { +soluna_material_error +material_push_stream(int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out) { size_t payload_max = stream_payload_max(); + if (out == NULL) { + return "Missing material stream output"; + } + out->data = NULL; + out->size = 0; if (material_id <= 0) { - luaL_error(L, "Invalid material id %d", material_id); + return "Invalid material id"; } if (count < 0) { - luaL_error(L, "Invalid material stream count %d", count); + return "Invalid material stream count"; } if (payload_size > payload_max) { - luaL_error(L, "Invalid material payload size %d > %d", (int)payload_size, (int)payload_max); + return "Invalid material payload size"; } if (write == NULL) { - luaL_error(L, "Missing material stream writer"); + return "Missing material stream writer"; } size_t item_size = sizeof(struct draw_primitive) * 2; if ((size_t)count > (~(size_t)0 - 1) / item_size) { - luaL_error(L, "Material stream is too large"); + return "Material stream is too large"; } size_t stream_size = item_size * (size_t)count; - struct stream_guard *guard = push_stream_guard(L); - int guard_index = lua_gettop(L); char *buffer = (char *)malloc(stream_size + 1); if (buffer == NULL) { - luaL_error(L, "No memory for material stream"); + return "No memory for material stream"; } - guard->ptr = buffer; struct draw_primitive *stream = (struct draw_primitive *)buffer; int i; for (i=0; i 0) { if (item.payload == NULL) { - luaL_error(L, "Missing material stream payload"); + material_stream_free(buffer); + return "Missing material stream payload"; } memcpy((char *)ext_prim + sizeof(*ext), item.payload, payload_size); } @@ -192,35 +205,67 @@ material_push_stream(lua_State *L, int material_id, int count, size_t payload_si ext->sprite = item.sprite; } buffer[stream_size] = '\0'; - guard->ptr = NULL; - lua_pushexternalstring(L, buffer, stream_size, free_stream, NULL); - lua_remove(L, guard_index); + out->data = buffer; + out->size = stream_size; + return NULL; } -void -material_stream_read(lua_State *L, const void *stream, int index, int material_id, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { +static void +clear_stream_read(size_t payload_size, void *payload, struct soluna_material_stream_data *out) { + if (out != NULL) { + memset(out, 0, sizeof(*out)); + } + if (payload != NULL && payload_size > 0 && payload_size <= stream_payload_max()) { + memset(payload, 0, payload_size); + } +} + +static int +fail_stream_read(void *ctx, const char *error, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { + material_stream_error(ctx, error); + clear_stream_read(payload_size, payload, out); + return 0; +} + +int +material_stream_read(void *ctx_, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { + struct material_stream_context *ctx = (struct material_stream_context *)ctx_; size_t payload_max = stream_payload_max(); + if (ctx == NULL) { + clear_stream_read(payload_size, payload, out); + return 0; + } + if (ctx->error != NULL) { + clear_stream_read(payload_size, payload, out); + return 0; + } if (payload_size > payload_max) { - luaL_error(L, "Invalid material payload size %d > %d", (int)payload_size, (int)payload_max); + return fail_stream_read(ctx_, "Invalid material payload size", payload_size, payload, out); } - if (stream == NULL) { - luaL_error(L, "Missing material stream"); + if (ctx->data == NULL) { + return fail_stream_read(ctx_, "Missing material stream", payload_size, payload, out); } if (index < 0) { - luaL_error(L, "Invalid material stream index %d", index); + return fail_stream_read(ctx_, "Invalid material stream index", payload_size, payload, out); + } + if (index >= ctx->n) { + return fail_stream_read(ctx_, "Invalid material stream index", payload_size, payload, out); + } + if (ctx->material_id <= 0) { + return fail_stream_read(ctx_, "Invalid material id", payload_size, payload, out); } if (out == NULL) { - luaL_error(L, "Missing material stream output"); + return fail_stream_read(ctx_, "Missing material stream output", payload_size, payload, out); } if (payload_size > 0 && payload == NULL) { - luaL_error(L, "Missing material stream payload output"); + return fail_stream_read(ctx_, "Missing material stream payload output", payload_size, payload, out); } - const struct draw_primitive *prim = (const struct draw_primitive *)stream; + const struct draw_primitive *prim = (const struct draw_primitive *)ctx->data; const struct draw_primitive *pos = &prim[index * 2]; const struct draw_primitive *ext_prim = pos + 1; const struct draw_primitive_external *ext = (const struct draw_primitive_external *)ext_prim; - if (pos->sprite != -material_id) { - luaL_error(L, "Invalid material marker %d", pos->sprite); + if (pos->sprite != -ctx->material_id) { + return fail_stream_read(ctx_, "Invalid material marker", payload_size, payload, out); } out->x = (float)pos->x * STREAM_FIX_INV_SCALE; out->y = (float)pos->y * STREAM_FIX_INV_SCALE; @@ -228,4 +273,5 @@ material_stream_read(lua_State *L, const void *stream, int index, int material_i if (payload_size > 0) { memcpy(payload, (const char *)ext_prim + sizeof(*ext), payload_size); } + return 1; } diff --git a/src/extapi_types.h b/src/extapi_types.h index 3b25358..7f2baac 100644 --- a/src/extapi_types.h +++ b/src/extapi_types.h @@ -5,8 +5,6 @@ #include -#include - #include "sokol/sokol_gfx.h" #define SOLUNA_EXT_API_VERSION 1 @@ -34,7 +32,13 @@ struct soluna_material_stream_data { int sprite; }; -typedef void (*soluna_material_submit_func)(lua_State *L, void *ud, const void *stream, int n); +struct soluna_material_stream { + char *data; + size_t size; +}; + +typedef const char *soluna_material_error; +typedef void (*soluna_material_submit_func)(void *ud, void *ctx, int n); typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); From 376c4d0a90c6979decf20da0f4cf75617e2a83ba Mon Sep 17 00:00:00 2001 From: Hanchin Hsieh Date: Mon, 27 Apr 2026 18:16:13 +0800 Subject: [PATCH 5/5] rework: use opaque type for extapi --- extlua/extlua_sample.c | 14 +++++++----- extlua/gen_soluna.lua | 25 +++++++++++++++------ extlua/solunaapi.c | 20 ++++++++--------- extlua/solunaapi.h | 25 +++++++++++++++------ extlua/solunaapi_impl.c | 35 ++++++++++++++++++++---------- src/extapi.c | 48 ++++++++++++++++++++++++----------------- src/extapi_types.h | 15 ++++++++++++- src/material_blit.c | 2 +- src/material_default.c | 2 +- src/material_mask.c | 2 +- src/material_quad.c | 2 +- src/material_text.c | 2 +- src/render_bindings.c | 6 +++--- src/render_bindings.h | 4 ++-- 14 files changed, 133 insertions(+), 69 deletions(-) diff --git a/extlua/extlua_sample.c b/extlua/extlua_sample.c index 402ecda..53d6b84 100644 --- a/extlua/extlua_sample.c +++ b/extlua/extlua_sample.c @@ -43,10 +43,10 @@ struct pquad_inst { struct material_perspective_quad { sg_pipeline pip; sg_buffer inst; - void *bind; + struct soluna_render_bindings bind; int base; vs_params_t *uniform; - void *bank; + struct soluna_sprite_bank bank; void *tmp_ptr; size_t tmp_size; }; @@ -171,7 +171,7 @@ build_quad_from_rect(const struct sprite_rect_basis *basis, const struct soluna_ } static void -submit(void *m_, void *ctx, int n) { +submit(void *m_, struct soluna_material_stream_context ctx, int n) { struct material_perspective_quad *m = (struct material_perspective_quad *)m_; struct pquad_inst *tmp = (struct pquad_inst *)m->tmp_ptr; int out_n; @@ -328,7 +328,9 @@ lnew_material_perspective_quad(lua_State *L) { if (lua_getfield(L, 1, "bindings") != LUA_TUSERDATA) { return luaL_error(L, "Invalid key .bindings"); } - m->bind = luaL_checkudata(L, -1, "SOKOL_BINDINGS"); + m->bind = (struct soluna_render_bindings) { + .ctx = luaL_checkudata(L, -1, "SOKOL_BINDINGS"), + }; lua_pushvalue(L, -1); lua_setiuservalue(L, material_index, 2); lua_pop(L, 1); @@ -344,7 +346,9 @@ lnew_material_perspective_quad(lua_State *L) { if (lua_getfield(L, 1, "sprite_bank") != LUA_TLIGHTUSERDATA) { return luaL_error(L, "Invalid key .sprite_bank"); } - m->bank = lua_touserdata(L, -1); + m->bank = (struct soluna_sprite_bank) { + .ctx = lua_touserdata(L, -1), + }; lua_pop(L, 1); if (lua_getfield(L, 1, "tmp_buffer") != LUA_TUSERDATA) { diff --git a/extlua/gen_soluna.lua b/extlua/gen_soluna.lua index 58f6b51..8ca6b97 100644 --- a/extlua/gen_soluna.lua +++ b/extlua/gen_soluna.lua @@ -17,7 +17,7 @@ local apis = { ret = "int", name = "soluna_material_sprite_rect", params = { - { type = "void *", name = "bank" }, + { type = "struct soluna_sprite_bank ", name = "bank" }, { type = "int ", name = "sprite" }, { type = "struct soluna_sprite_rect *", name = "out" }, }, @@ -26,7 +26,7 @@ local apis = { ret = "sg_bindings", name = "soluna_material_bindings", params = { - { type = "void *", name = "bindings" }, + { type = "struct soluna_render_bindings ", name = "bindings" }, }, }, { @@ -52,7 +52,7 @@ local apis = { ret = "int", name = "soluna_material_stream_read", params = { - { type = "void *", name = "ctx" }, + { type = "struct soluna_material_stream_context ", name = "ctx" }, { type = "int ", name = "index" }, { type = "size_t ", name = "payload_size" }, { type = "void *", name = "payload" }, @@ -63,7 +63,7 @@ local apis = { ret = "void", name = "soluna_material_stream_error", params = { - { type = "void *", name = "ctx" }, + { type = "struct soluna_material_stream_context ", name = "ctx" }, { type = "const char *", name = "error" }, }, }, @@ -71,7 +71,7 @@ local apis = { ret = "int", name = "soluna_material_stream_failed", params = { - { type = "void *", name = "ctx" }, + { type = "struct soluna_material_stream_context ", name = "ctx" }, }, }, } @@ -108,7 +108,20 @@ struct soluna_material_stream { }; typedef const char *soluna_material_error; -typedef void (*soluna_material_submit_func)(void *ud, void *ctx, int n); + +struct soluna_material_stream_context { + void *ctx; +}; + +struct soluna_render_bindings { + void *ctx; +}; + +struct soluna_sprite_bank { + void *ctx; +}; + +typedef void (*soluna_material_submit_func)(void *ud, struct soluna_material_stream_context ctx, int n); typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); ]] diff --git a/extlua/solunaapi.c b/extlua/solunaapi.c index e312232..32009e6 100644 --- a/extlua/solunaapi.c +++ b/extlua/solunaapi.c @@ -8,13 +8,13 @@ struct soluna_api { int version; soluna_material_error (*material_submit) (const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit); - int (*material_sprite_rect) (void *bank, int sprite, struct soluna_sprite_rect *out); - sg_bindings (*material_bindings) (void *bindings); + int (*material_sprite_rect) (struct soluna_sprite_bank bank, int sprite, struct soluna_sprite_rect *out); + sg_bindings (*material_bindings) (struct soluna_render_bindings bindings); soluna_material_error (*material_push_stream) (int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out); void (*material_stream_free) (void *ptr); - int (*material_stream_read) (void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); - void (*material_stream_error) (void *ctx, const char *error); - int (*material_stream_failed) (void *ctx); + int (*material_stream_read) (struct soluna_material_stream_context ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); + void (*material_stream_error) (struct soluna_material_stream_context ctx, const char *error); + int (*material_stream_failed) (struct soluna_material_stream_context ctx); }; static struct soluna_api API; @@ -25,12 +25,12 @@ soluna_material_submit(const void *stream, int prim_n, int material_id, int batc } int -soluna_material_sprite_rect(void *bank, int sprite, struct soluna_sprite_rect *out) { +soluna_material_sprite_rect(struct soluna_sprite_bank bank, int sprite, struct soluna_sprite_rect *out) { return API.material_sprite_rect(bank, sprite, out); } sg_bindings -soluna_material_bindings(void *bindings) { +soluna_material_bindings(struct soluna_render_bindings bindings) { return API.material_bindings(bindings); } @@ -45,17 +45,17 @@ soluna_material_stream_free(void *ptr) { } int -soluna_material_stream_read(void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { +soluna_material_stream_read(struct soluna_material_stream_context ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { return API.material_stream_read(ctx, index, payload_size, payload, out); } void -soluna_material_stream_error(void *ctx, const char *error) { +soluna_material_stream_error(struct soluna_material_stream_context ctx, const char *error) { API.material_stream_error(ctx, error); } int -soluna_material_stream_failed(void *ctx) { +soluna_material_stream_failed(struct soluna_material_stream_context ctx) { return API.material_stream_failed(ctx); } diff --git a/extlua/solunaapi.h b/extlua/solunaapi.h index e59d883..3a7bc8d 100644 --- a/extlua/solunaapi.h +++ b/extlua/solunaapi.h @@ -40,18 +40,31 @@ struct soluna_material_stream { }; typedef const char *soluna_material_error; -typedef void (*soluna_material_submit_func)(void *ud, void *ctx, int n); + +struct soluna_material_stream_context { + void *ctx; +}; + +struct soluna_render_bindings { + void *ctx; +}; + +struct soluna_sprite_bank { + void *ctx; +}; + +typedef void (*soluna_material_submit_func)(void *ud, struct soluna_material_stream_context ctx, int n); typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); void solunaapi_init(lua_State *L); soluna_material_error soluna_material_submit(const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit); -int soluna_material_sprite_rect(void *bank, int sprite, struct soluna_sprite_rect *out); -sg_bindings soluna_material_bindings(void *bindings); +int soluna_material_sprite_rect(struct soluna_sprite_bank bank, int sprite, struct soluna_sprite_rect *out); +sg_bindings soluna_material_bindings(struct soluna_render_bindings bindings); soluna_material_error soluna_material_push_stream(int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out); void soluna_material_stream_free(void *ptr); -int soluna_material_stream_read(void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); -void soluna_material_stream_error(void *ctx, const char *error); -int soluna_material_stream_failed(void *ctx); +int soluna_material_stream_read(struct soluna_material_stream_context ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); +void soluna_material_stream_error(struct soluna_material_stream_context ctx, const char *error); +int soluna_material_stream_failed(struct soluna_material_stream_context ctx); #endif diff --git a/extlua/solunaapi_impl.c b/extlua/solunaapi_impl.c index 1ba71d8..252935b 100644 --- a/extlua/solunaapi_impl.c +++ b/extlua/solunaapi_impl.c @@ -35,30 +35,43 @@ struct soluna_material_stream { }; typedef const char *soluna_material_error; -typedef void (*soluna_material_submit_func)(void *ud, void *ctx, int n); + +struct soluna_material_stream_context { + void *ctx; +}; + +struct soluna_render_bindings { + void *ctx; +}; + +struct soluna_sprite_bank { + void *ctx; +}; + +typedef void (*soluna_material_submit_func)(void *ud, struct soluna_material_stream_context ctx, int n); typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); extern soluna_material_error material_submit(const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit); -extern int material_sprite_rect(void *bank, int sprite, struct soluna_sprite_rect *out); -extern sg_bindings material_bindings(void *bindings); +extern int material_sprite_rect(struct soluna_sprite_bank bank, int sprite, struct soluna_sprite_rect *out); +extern sg_bindings material_bindings(struct soluna_render_bindings bindings); extern soluna_material_error material_push_stream(int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out); extern void material_stream_free(void *ptr); -extern int material_stream_read(void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); -extern void material_stream_error(void *ctx, const char *error); -extern int material_stream_failed(void *ctx); +extern int material_stream_read(struct soluna_material_stream_context ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); +extern void material_stream_error(struct soluna_material_stream_context ctx, const char *error); +extern int material_stream_failed(struct soluna_material_stream_context ctx); struct soluna_api { int version; soluna_material_error (*material_submit) (const void *stream, int prim_n, int material_id, int batch_n, void *ud, soluna_material_submit_func submit); - int (*material_sprite_rect) (void *bank, int sprite, struct soluna_sprite_rect *out); - sg_bindings (*material_bindings) (void *bindings); + int (*material_sprite_rect) (struct soluna_sprite_bank bank, int sprite, struct soluna_sprite_rect *out); + sg_bindings (*material_bindings) (struct soluna_render_bindings bindings); soluna_material_error (*material_push_stream) (int material_id, int count, size_t payload_size, soluna_material_stream_write_func write, void *ud, struct soluna_material_stream *out); void (*material_stream_free) (void *ptr); - int (*material_stream_read) (void *ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); - void (*material_stream_error) (void *ctx, const char *error); - int (*material_stream_failed) (void *ctx); + int (*material_stream_read) (struct soluna_material_stream_context ctx, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out); + void (*material_stream_error) (struct soluna_material_stream_context ctx, const char *error); + int (*material_stream_failed) (struct soluna_material_stream_context ctx); }; struct soluna_api * diff --git a/src/extapi.c b/src/extapi.c index 8fb2893..4b9ecf3 100644 --- a/src/extapi.c +++ b/src/extapi.c @@ -22,9 +22,9 @@ #define SOLUNA_THREAD_LOCAL _Thread_local #endif -typedef void (*material_submit_stride_func)(void *ud, void *ctx, int n); +typedef void (*material_submit_stride_func)(void *ud, struct soluna_material_stream_context ctx, int n); -struct material_stream_context { +struct material_stream_context_impl { const char *data; int n; int material_id; @@ -34,6 +34,11 @@ struct material_stream_context { static SOLUNA_THREAD_LOCAL char submit_error_buffer[STREAM_ERROR_SIZE]; +static struct material_stream_context_impl * +stream_context(struct soluna_material_stream_context ctx) { + return (struct material_stream_context_impl *)ctx.ctx; +} + static soluna_material_error copy_error(char *buffer, size_t size, const char *error) { const char *message = error != NULL ? error : "Material stream error"; @@ -47,16 +52,16 @@ copy_error(char *buffer, size_t size, const char *error) { } void -material_stream_error(void *ctx_, const char *error) { - struct material_stream_context *ctx = (struct material_stream_context *)ctx_; +material_stream_error(struct soluna_material_stream_context ctx_, const char *error) { + struct material_stream_context_impl *ctx = stream_context(ctx_); if (ctx != NULL && ctx->error == NULL) { ctx->error = copy_error(ctx->error_buffer, sizeof(ctx->error_buffer), error); } } int -material_stream_failed(void *ctx_) { - struct material_stream_context *ctx = (struct material_stream_context *)ctx_; +material_stream_failed(struct soluna_material_stream_context ctx_) { + struct material_stream_context_impl *ctx = stream_context(ctx_); return ctx == NULL || ctx->error != NULL; } @@ -84,24 +89,27 @@ submit_material_stride(const void *data_, int prim_n, int material_id, int batch int i = 0; for (;;) { int n = prim_n - i; - struct material_stream_context ctx = { + struct material_stream_context_impl impl = { .data = data, .n = n > batch_n ? batch_n : n, .material_id = material_id, .error = NULL, .error_buffer = { 0 }, }; + struct soluna_material_stream_context ctx = { + .ctx = &impl, + }; if (n > batch_n) { - submit(ud, &ctx, batch_n); - if (ctx.error != NULL) { - return copy_error(submit_error_buffer, sizeof(submit_error_buffer), ctx.error); + submit(ud, ctx, batch_n); + if (impl.error != NULL) { + return copy_error(submit_error_buffer, sizeof(submit_error_buffer), impl.error); } i += batch_n; data += stride * batch_n; } else { - submit(ud, &ctx, n); - if (ctx.error != NULL) { - return copy_error(submit_error_buffer, sizeof(submit_error_buffer), ctx.error); + submit(ud, ctx, n); + if (impl.error != NULL) { + return copy_error(submit_error_buffer, sizeof(submit_error_buffer), impl.error); } break; } @@ -115,8 +123,8 @@ material_submit(const void *stream, int prim_n, int material_id, int batch_n, vo } int -material_sprite_rect(void *bank, int sprite, struct soluna_sprite_rect *out) { - struct sprite_bank *b = (struct sprite_bank *)bank; +material_sprite_rect(struct soluna_sprite_bank bank, int sprite, struct soluna_sprite_rect *out) { + struct sprite_bank *b = (struct sprite_bank *)bank.ctx; if (b == NULL || out == NULL || sprite < 0 || sprite >= b->n) { return 0; } @@ -132,8 +140,8 @@ material_sprite_rect(void *bank, int sprite, struct soluna_sprite_rect *out) { } sg_bindings -material_bindings(void *bindings) { - struct soluna_render_bindings *b = (struct soluna_render_bindings *)bindings; +material_bindings(struct soluna_render_bindings bindings) { + struct render_bindings *b = (struct render_bindings *)bindings.ctx; assert(b != NULL); return b->bindings; } @@ -221,15 +229,15 @@ clear_stream_read(size_t payload_size, void *payload, struct soluna_material_str } static int -fail_stream_read(void *ctx, const char *error, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { +fail_stream_read(struct soluna_material_stream_context ctx, const char *error, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { material_stream_error(ctx, error); clear_stream_read(payload_size, payload, out); return 0; } int -material_stream_read(void *ctx_, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { - struct material_stream_context *ctx = (struct material_stream_context *)ctx_; +material_stream_read(struct soluna_material_stream_context ctx_, int index, size_t payload_size, void *payload, struct soluna_material_stream_data *out) { + struct material_stream_context_impl *ctx = stream_context(ctx_); size_t payload_max = stream_payload_max(); if (ctx == NULL) { clear_stream_read(payload_size, payload, out); diff --git a/src/extapi_types.h b/src/extapi_types.h index 7f2baac..6c8737f 100644 --- a/src/extapi_types.h +++ b/src/extapi_types.h @@ -38,7 +38,20 @@ struct soluna_material_stream { }; typedef const char *soluna_material_error; -typedef void (*soluna_material_submit_func)(void *ud, void *ctx, int n); + +struct soluna_material_stream_context { + void *ctx; +}; + +struct soluna_render_bindings { + void *ctx; +}; + +struct soluna_sprite_bank { + void *ctx; +}; + +typedef void (*soluna_material_submit_func)(void *ud, struct soluna_material_stream_context ctx, int n); typedef void (*soluna_material_stream_write_func)(void *ud, int index, struct soluna_material_stream_item *item); diff --git a/src/material_blit.c b/src/material_blit.c index c95db94..a1d347e 100644 --- a/src/material_blit.c +++ b/src/material_blit.c @@ -8,7 +8,7 @@ struct material_blit { sg_pipeline pip; - struct soluna_render_bindings *bind; + struct render_bindings *bind; }; static int diff --git a/src/material_default.c b/src/material_default.c index 27dfea2..0b9f4c5 100644 --- a/src/material_default.c +++ b/src/material_default.c @@ -23,7 +23,7 @@ struct inst_object { struct material_default { sg_pipeline pip; sg_buffer inst; - struct soluna_render_bindings *bind; + struct render_bindings *bind; vs_params_t *uniform; struct sr_buffer *srbuffer; struct sprite_bank *bank; diff --git a/src/material_mask.c b/src/material_mask.c index 280973a..6343c43 100644 --- a/src/material_mask.c +++ b/src/material_mask.c @@ -33,7 +33,7 @@ struct mask { struct material_mask { sg_pipeline pip; sg_buffer inst; - struct soluna_render_bindings *bind; + struct render_bindings *bind; vs_params_t *uniform; struct sr_buffer *srbuffer; struct sprite_bank *bank; diff --git a/src/material_quad.c b/src/material_quad.c index ad31735..e3cfe98 100644 --- a/src/material_quad.c +++ b/src/material_quad.c @@ -33,7 +33,7 @@ struct inst_object { struct material_quad { sg_pipeline pip; sg_buffer inst; - struct soluna_render_bindings *bind; + struct render_bindings *bind; vs_params_t *uniform; struct sr_buffer *srbuffer; struct tmp_buffer tmp; diff --git a/src/material_text.c b/src/material_text.c index ee954bc..8271174 100644 --- a/src/material_text.c +++ b/src/material_text.c @@ -36,7 +36,7 @@ struct inst_object { struct material_text { sg_pipeline pip; sg_buffer inst; - struct soluna_render_bindings *bind; + struct render_bindings *bind; vs_params_t *uniform; struct sr_buffer *srbuffer; struct font_manager *font; diff --git a/src/render_bindings.c b/src/render_bindings.c index cb9a07b..fe718de 100644 --- a/src/render_bindings.c +++ b/src/render_bindings.c @@ -6,13 +6,13 @@ static inline sg_bindings * get_bindings(lua_State *L) { - struct soluna_render_bindings *b = luaL_checkudata(L, 1, "SOKOL_BINDINGS"); + struct render_bindings *b = luaL_checkudata(L, 1, "SOKOL_BINDINGS"); return &b->bindings; } static int lbindings_set_base(lua_State *L) { - struct soluna_render_bindings *b = luaL_checkudata(L, 1, "SOKOL_BINDINGS"); + struct render_bindings *b = luaL_checkudata(L, 1, "SOKOL_BINDINGS"); int base = luaL_checkinteger(L, 2); b->base = base; return 0; @@ -220,7 +220,7 @@ lview_new(lua_State *L) { int lbindings_new(lua_State *L) { - struct soluna_render_bindings *b = (struct soluna_render_bindings *)lua_newuserdatauv(L, sizeof(*b), 0); + struct render_bindings *b = (struct render_bindings *)lua_newuserdatauv(L, sizeof(*b), 0); memset(b, 0, sizeof(*b)); if (luaL_newmetatable(L, "SOKOL_BINDINGS")) { luaL_Reg l[] = { diff --git a/src/render_bindings.h b/src/render_bindings.h index dfdd41a..d343fbf 100644 --- a/src/render_bindings.h +++ b/src/render_bindings.h @@ -3,11 +3,11 @@ #include "sokol/sokol_gfx.h" -struct soluna_render_bindings { +struct render_bindings { int base; sg_bindings bindings; }; #define DRAWFUNC(name) (sg_query_features().draw_base_instance ? name##_ex : name) -#endif \ No newline at end of file +#endif