Merge branch 'main' into precipitation

This commit is contained in:
MihailRis
2025-03-09 23:13:04 +03:00
26 changed files with 577 additions and 110 deletions
+5 -1
View File
@@ -114,10 +114,14 @@ namespace lua {
return *mData;
}
[[nodiscard]] bool hasTexture() const {
return mTexture != nullptr;
}
static int createMetatable(lua::State*);
inline static std::string TYPENAME = "Canvas";
private:
std::shared_ptr<Texture> mTexture;
std::shared_ptr<Texture> mTexture; // nullable
std::shared_ptr<ImageData> mData;
};
static_assert(!std::is_abstract<LuaCanvas>());
+11 -8
View File
@@ -88,14 +88,17 @@ static void create_libs(State* L, StateType stateType) {
void lua::init_state(State* L, StateType stateType) {
// Allowed standard libraries
pop(L, luaopen_base(L));
pop(L, luaopen_math(L));
pop(L, luaopen_string(L));
pop(L, luaopen_table(L));
pop(L, luaopen_debug(L));
pop(L, luaopen_jit(L));
pop(L, luaopen_bit(L));
pop(L, luaopen_os(L));
luaL_openlibs(L);
if (getglobal(L, "require")) {
pushstring(L, "ffi");
if (call_nothrow(L, 1, 1)) {
setglobal(L, "ffi");
}
}
pushnil(L);
setglobal(L, "io");
const char* removed_os[] {
"execute", "exit", "remove", "rename", "setlocale", "tmpname", nullptr};
remove_lib_funcs(L, "os", removed_os);
+6 -2
View File
@@ -163,20 +163,23 @@ int lua::call(State* L, int argc, int nresults) {
int handler_pos = gettop(L) - argc;
pushcfunction(L, l_error_handler);
insert(L, handler_pos);
int top = gettop(L);
if (lua_pcall(L, argc, nresults, handler_pos)) {
std::string log = tostring(L, -1);
pop(L);
remove(L, handler_pos);
throw luaerror(log);
}
int added = gettop(L) - (top - argc - 1);
remove(L, handler_pos);
return nresults == -1 ? 1 : nresults;
return added;
}
int lua::call_nothrow(State* L, int argc, int nresults) {
int handler_pos = gettop(L) - argc;
pushcfunction(L, l_error_handler);
insert(L, handler_pos);
int top = gettop(L);
if (lua_pcall(L, argc, -1, handler_pos)) {
auto errorstr = tostring(L, -1);
if (errorstr) {
@@ -188,8 +191,9 @@ int lua::call_nothrow(State* L, int argc, int nresults) {
remove(L, handler_pos);
return 0;
}
int added = gettop(L) - (top - argc - 1);
remove(L, handler_pos);
return 1;
return added;
}
void lua::dump_stack(State* L) {
+5 -1
View File
@@ -25,7 +25,8 @@ namespace lua {
if (n < 0) {
abort();
}
if (lua_gettop(L) < n) {
int top = lua_gettop(L);
if (top < n) {
abort();
}
#endif
@@ -63,6 +64,9 @@ namespace lua {
inline void rawseti(lua::State* L, int n, int idx = -2) {
lua_rawseti(L, idx, n);
}
inline void rawset(lua::State* L, int idx = -3) {
lua_rawset(L, idx);
}
inline int createtable(lua::State* L, int narr, int nrec) {
lua_createtable(L, narr, nrec);
@@ -17,6 +17,7 @@ union RGBA {
struct {
uint8_t r, g, b, a;
};
uint8_t arr[4];
uint32_t rgba;
};
@@ -49,38 +50,118 @@ static int l_at(State* L) {
return 0;
}
static RGBA get_rgba(State* L, int first) {
RGBA rgba {};
rgba.a = 255;
switch (gettop(L) - first) {
case 0:
rgba.rgba = static_cast<uint>(tointeger(L, first));
break;
case 3:
rgba.a = static_cast<ubyte>(tointeger(L, first + 3));
[[fallthrough]];
case 2:
rgba.r = static_cast<ubyte>(tointeger(L, first));
rgba.g = static_cast<ubyte>(tointeger(L, first + 1));
rgba.b = static_cast<ubyte>(tointeger(L, first + 2));
break;
}
return rgba;
}
static int l_set(State* L) {
auto x = static_cast<uint>(tointeger(L, 2));
auto y = static_cast<uint>(tointeger(L, 3));
if (auto pixel = get_at(L, x, y)) {
switch (gettop(L)) {
case 4:
pixel->rgba = static_cast<uint>(tointeger(L, 4));
return 1;
case 6:
pixel->r = static_cast<ubyte>(tointeger(L, 4));
pixel->g = static_cast<ubyte>(tointeger(L, 5));
pixel->b = static_cast<ubyte>(tointeger(L, 6));
pixel->a = 255;
return 1;
case 7:
pixel->r = static_cast<ubyte>(tointeger(L, 4));
pixel->g = static_cast<ubyte>(tointeger(L, 5));
pixel->b = static_cast<ubyte>(tointeger(L, 6));
pixel->a = static_cast<ubyte>(tointeger(L, 7));
return 1;
default:
return 0;
}
*pixel = get_rgba(L, 4);
}
return 0;
}
static LuaCanvas& require_canvas(State* L, int idx) {
if (const auto canvas = touserdata<LuaCanvas>(L, idx)) {
return *canvas;
}
throw std::runtime_error(
"canvas expected as argument #" + std::to_string(idx)
);
}
static int l_clear(State* L) {
auto& canvas = require_canvas(L, 1);
auto& image = canvas.data();
ubyte* data = image.getData();
RGBA rgba {};
if (gettop(L) == 1) {
std::fill(data, data + image.getDataSize(), 0);
return 0;
}
rgba = get_rgba(L, 2);
size_t pixels = image.getWidth() * image.getHeight();
const size_t channels = 4;
for (size_t i = 0; i < pixels * channels; i++) {
data[i] = rgba.arr[i % channels];
}
return 0;
}
static int l_line(State* L) {
int x1 = tointeger(L, 2);
int y1 = tointeger(L, 3);
int x2 = tointeger(L, 4);
int y2 = tointeger(L, 5);
RGBA rgba = get_rgba(L, 6);
if (auto canvas = touserdata<LuaCanvas>(L, 1)) {
auto& image = canvas->data();
image.drawLine(
x1, y1, x2, y2, glm::ivec4 {rgba.r, rgba.g, rgba.b, rgba.a}
);
}
return 0;
}
static int l_blit(State* L) {
auto& dst = require_canvas(L, 1);
auto& src = require_canvas(L, 2);
int dst_x = tointeger(L, 3);
int dst_y = tointeger(L, 4);
dst.data().blit(src.data(), dst_x, dst_y);
return 0;
}
static int l_set_data(State* L) {
auto& canvas = require_canvas(L, 1);
auto& image = canvas.data();
auto data = image.getData();
if (lua::isstring(L, 2)) {
auto ptr = reinterpret_cast<ubyte*>(std::stoull(lua::tostring(L, 2)));
std::memcpy(data, ptr, image.getDataSize());
return 0;
}
int len = objlen(L, 2);
if (len < image.getDataSize()) {
throw std::runtime_error(
"data size mismatch expected " +
std::to_string(image.getDataSize()) + ", got " + std::to_string(len)
);
}
for (size_t i = 0; i < len; i++) {
rawgeti(L, i + 1, 2);
data[i] = tointeger(L, -1);
pop(L);
}
return 0;
}
static int l_update(State* L) {
if (auto canvas = touserdata<LuaCanvas>(L, 1)) {
canvas->texture().reload(canvas->data());
if (canvas->hasTexture()) {
canvas->texture().reload(canvas->data());
}
}
return 0;
}
@@ -88,7 +169,11 @@ static int l_update(State* L) {
static std::unordered_map<std::string, lua_CFunction> methods {
{"at", lua::wrap<l_at>},
{"set", lua::wrap<l_set>},
{"update", lua::wrap<l_update>}
{"line", lua::wrap<l_line>},
{"blit", lua::wrap<l_blit>},
{"clear", lua::wrap<l_clear>},
{"update", lua::wrap<l_update>},
{"_set_data", lua::wrap<l_set_data>},
};
static int l_meta_index(State* L) {
@@ -110,6 +195,9 @@ static int l_meta_index(State* L) {
if (!strcmp(name, "height")) {
return pushinteger(L, data.getHeight());
}
if (!strcmp(name, "set_data")) {
return getglobal(L, "__vc_Canvas_set_data");
}
if (auto func = methods.find(tostring(L, 2)); func != methods.end()) {
return pushcfunction(L, func->second);
}
@@ -126,18 +214,33 @@ static int l_meta_newindex(State* L) {
if (isnumber(L, 2) && isnumber(L, 3)) {
if (auto pixel = get_at(data, static_cast<uint>(tointeger(L, 2)))) {
pixel->rgba = static_cast<uint>(tointeger(L, 3));
return 1;
}
return 1;
}
return 0;
}
static int l_meta_meta_call(lua::State* L) {
auto size = glm::ivec2(tovec2(L, 2));
if (size.x <= 0 || size.y <= 0) {
throw std::runtime_error("size must be positive");
}
return newuserdata<LuaCanvas>(
L,
nullptr,
std::make_shared<ImageData>(ImageFormat::rgba8888, size.x, size.y)
);
}
int LuaCanvas::createMetatable(State* L) {
createtable(L, 0, 3);
pushcfunction(L, lua::wrap<l_meta_index>);
setfield(L, "__index");
pushcfunction(L, lua::wrap<l_meta_newindex>);
setfield(L, "__newindex");
createtable(L, 0, 1);
pushcfunction(L, lua::wrap<l_meta_meta_call>);
setfield(L, "__call");
setmetatable(L);
return 1;
}
+1 -1
View File
@@ -120,7 +120,7 @@ std::unique_ptr<Process> scripting::start_coroutine(
lua::loadbuffer(L, 0, source, script.name());
if (lua::call(L, 1)) {
int id = lua::tointeger(L, -1);
lua::pop(L, 2);
lua::pop(L, 1);
return std::make_unique<LuaCoroutine>(L, id);
}
lua::pop(L);