Merge branch 'main' into precipitation
This commit is contained in:
@@ -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>());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user