add canvas:clear(...), canvas:line(...)
This commit is contained in:
parent
ee3fbc6831
commit
dca4f283cc
@ -17,6 +17,7 @@ union RGBA {
|
||||
struct {
|
||||
uint8_t r, g, b, a;
|
||||
};
|
||||
uint8_t arr[4];
|
||||
uint32_t rgba;
|
||||
};
|
||||
|
||||
@ -49,32 +50,140 @@ 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 int l_clear(State* L) {
|
||||
RGBA rgba {};
|
||||
if (gettop(L) > 1) {
|
||||
rgba = get_rgba(L, 2);
|
||||
}
|
||||
if (auto canvas = touserdata<LuaCanvas>(L, 1)) {
|
||||
auto& image = canvas->data();
|
||||
ubyte* data = image.getData();
|
||||
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;
|
||||
}
|
||||
|
||||
bool clip_line(int& x1, int& y1, int& x2, int& y2, int width, int height) {
|
||||
const int left = 0;
|
||||
const int right = width;
|
||||
const int bottom = 0;
|
||||
const int top = height;
|
||||
|
||||
int dx = x2 - x1;
|
||||
int dy = y2 - y1;
|
||||
|
||||
float t0 = 0.0f;
|
||||
float t1 = 1.0f;
|
||||
|
||||
auto clip = [](int p, int q, float& t0, float& t1) {
|
||||
if (p == 0) {
|
||||
return q >= 0;
|
||||
}
|
||||
float t = static_cast<float>(q) / p;
|
||||
if (p < 0) {
|
||||
if (t > t1) return false;
|
||||
if (t > t0) t0 = t;
|
||||
} else {
|
||||
if (t < t0) return false;
|
||||
if (t < t1) t1 = t;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!clip(-dx, x1 - left, t0, t1)) return false;
|
||||
if (!clip( dx, right - x1, t0, t1)) return false;
|
||||
if (!clip(-dy, y1 - bottom, t0, t1)) return false;
|
||||
if (!clip( dy, top - y1, t0, t1)) return false;
|
||||
|
||||
if (t1 < 1.0f) {
|
||||
x2 = x1 + static_cast<int>(std::round(t1 * dx));
|
||||
y2 = y1 + static_cast<int>(std::round(t1 * dy));
|
||||
}
|
||||
if (t0 > 0.0f) {
|
||||
x1 = x1 + static_cast<int>(std::round(t0 * dx));
|
||||
y1 = y1 + static_cast<int>(std::round(t0 * dy));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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();
|
||||
ubyte* data = image.getData();
|
||||
uint width = image.getWidth();
|
||||
uint height = image.getHeight();
|
||||
const uint channels = 4;
|
||||
|
||||
if ((x1 < 0 || x1 >= width || x2 < 0 || x2 >= width ||
|
||||
y1 < 0 || y1 >= height || y2 < 0 || y2 >= height) &&
|
||||
!clip_line(x1, y1, x2, y2, width, height)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dx = glm::abs(x2 - x1);
|
||||
int dy = -glm::abs(y2 - y1);
|
||||
int sx = x1 < x2 ? 1 : -1;
|
||||
int sy = y1 < y2 ? 1 : -1;
|
||||
int err = dx + dy;
|
||||
|
||||
while (true) {
|
||||
size_t pos = (y1 * width + x1) * channels;
|
||||
for (int i = 0; i < channels; i++) {
|
||||
data[pos + i] = rgba.arr[i];
|
||||
}
|
||||
if (x1 == x2 && y1 == y2) break;
|
||||
|
||||
int e2 = 2 * err;
|
||||
if (e2 >= dy) {
|
||||
err += dy;
|
||||
x1 += sx;
|
||||
}
|
||||
if (e2 <= dx) {
|
||||
err += dx;
|
||||
y1 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -88,6 +197,8 @@ 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>},
|
||||
{"clear", lua::wrap<l_clear>},
|
||||
{"line", lua::wrap<l_line>},
|
||||
{"update", lua::wrap<l_update>}
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user