add Canvas constructor & add canvas:blit
This commit is contained in:
parent
5bbba7f39d
commit
2af55a0227
@ -97,7 +97,7 @@ std::unique_ptr<Atlas> AtlasBuilder::build(uint extrusion, bool prepare, uint ma
|
||||
uint y = rect.y;
|
||||
uint w = rect.width;
|
||||
uint h = rect.height;
|
||||
canvas->blit(entry.image.get(), rect.x, rect.y);
|
||||
canvas->blit(*entry.image, rect.x, rect.y);
|
||||
for (uint j = 0; j < extrusion; j++) {
|
||||
canvas->extrude(x - j, y - j, w + j*2, h + j*2);
|
||||
}
|
||||
|
||||
@ -81,13 +81,13 @@ void ImageData::flipY() {
|
||||
}
|
||||
}
|
||||
|
||||
void ImageData::blit(const ImageData* image, int x, int y) {
|
||||
if (format == image->format) {
|
||||
void ImageData::blit(const ImageData& image, int x, int y) {
|
||||
if (format == image.format) {
|
||||
blitMatchingFormat(image, x, y);
|
||||
return;
|
||||
}
|
||||
if (format == ImageFormat::rgba8888 &&
|
||||
image->format == ImageFormat::rgb888) {
|
||||
image.format == ImageFormat::rgb888) {
|
||||
blitRGB_on_RGBA(image, x, y);
|
||||
return;
|
||||
}
|
||||
@ -187,10 +187,10 @@ void ImageData::drawLine(int x1, int y1, int x2, int y2, const glm::ivec4& color
|
||||
}
|
||||
}
|
||||
|
||||
void ImageData::blitRGB_on_RGBA(const ImageData* image, int x, int y) {
|
||||
ubyte* source = image->getData();
|
||||
uint srcwidth = image->getWidth();
|
||||
uint srcheight = image->getHeight();
|
||||
void ImageData::blitRGB_on_RGBA(const ImageData& image, int x, int y) {
|
||||
ubyte* source = image.getData();
|
||||
uint srcwidth = image.getWidth();
|
||||
uint srcheight = image.getHeight();
|
||||
|
||||
for (uint srcy = std::max(0, -y);
|
||||
srcy < std::min(srcheight, height - y);
|
||||
@ -210,7 +210,7 @@ void ImageData::blitRGB_on_RGBA(const ImageData* image, int x, int y) {
|
||||
}
|
||||
}
|
||||
|
||||
void ImageData::blitMatchingFormat(const ImageData* image, int x, int y) {
|
||||
void ImageData::blitMatchingFormat(const ImageData& image, int x, int y) {
|
||||
uint comps;
|
||||
switch (format) {
|
||||
case ImageFormat::rgb888: comps = 3; break;
|
||||
@ -218,20 +218,24 @@ void ImageData::blitMatchingFormat(const ImageData* image, int x, int y) {
|
||||
default:
|
||||
throw std::runtime_error("only unsigned byte formats supported");
|
||||
}
|
||||
ubyte* source = image->getData();
|
||||
uint srcwidth = image->getWidth();
|
||||
uint srcheight = image->getHeight();
|
||||
ubyte* source = image.getData();
|
||||
|
||||
const uint width = this->width;
|
||||
const uint height = this->height;
|
||||
const uint src_width = image.getWidth();
|
||||
const uint src_height = image.getHeight();
|
||||
ubyte* data = this->data.get();
|
||||
|
||||
for (uint srcy = std::max(0, -y);
|
||||
srcy < std::min(srcheight, height - y);
|
||||
srcy < std::min(src_height, height - y);
|
||||
srcy++) {
|
||||
for (uint srcx = std::max(0, -x);
|
||||
srcx < std::min(srcwidth, width - x);
|
||||
srcx < std::min(src_width, width - x);
|
||||
srcx++) {
|
||||
uint dstx = srcx + x;
|
||||
uint dsty = srcy + y;
|
||||
uint dstidx = (dsty * width + dstx) * comps;
|
||||
uint srcidx = (srcy * srcwidth + srcx) * comps;
|
||||
uint srcidx = (srcy * src_width + srcx) * comps;
|
||||
for (uint c = 0; c < comps; c++) {
|
||||
data[dstidx + c] = source[srcidx + c];
|
||||
}
|
||||
|
||||
@ -15,6 +15,9 @@ class ImageData {
|
||||
uint width;
|
||||
uint height;
|
||||
std::unique_ptr<ubyte[]> data;
|
||||
|
||||
void blitRGB_on_RGBA(const ImageData& image, int x, int y);
|
||||
void blitMatchingFormat(const ImageData& image, int x, int y);
|
||||
public:
|
||||
ImageData(ImageFormat format, uint width, uint height);
|
||||
ImageData(ImageFormat format, uint width, uint height, std::unique_ptr<ubyte[]> data);
|
||||
@ -25,9 +28,7 @@ public:
|
||||
void flipY();
|
||||
|
||||
void drawLine(int x1, int y1, int x2, int y2, const glm::ivec4& color);
|
||||
void blitRGB_on_RGBA(const ImageData* image, int x, int y);
|
||||
void blitMatchingFormat(const ImageData* image, int x, int y);
|
||||
void blit(const ImageData* image, int x, int y);
|
||||
void blit(const ImageData& image, int x, int y);
|
||||
void extrude(int x, int y, int w, int h);
|
||||
void fixAlphaColor();
|
||||
|
||||
|
||||
@ -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>());
|
||||
|
||||
@ -79,12 +79,18 @@ static int l_set(State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_clear(State* L) {
|
||||
auto canvas = touserdata<LuaCanvas>(L, 1);
|
||||
if (canvas == nullptr) {
|
||||
throw std::runtime_error("used canvas.clear instead of canvas:clear");
|
||||
static LuaCanvas& require_canvas(State* L, int idx) {
|
||||
if (const auto canvas = touserdata<LuaCanvas>(L, idx)) {
|
||||
return *canvas;
|
||||
}
|
||||
auto& image = canvas->data();
|
||||
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) {
|
||||
@ -117,9 +123,20 @@ static int l_line(State* L) {
|
||||
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_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;
|
||||
}
|
||||
@ -128,8 +145,10 @@ static std::unordered_map<std::string, lua_CFunction> methods {
|
||||
{"at", lua::wrap<l_at>},
|
||||
{"set", lua::wrap<l_set>},
|
||||
{"line", lua::wrap<l_line>},
|
||||
{"blit", lua::wrap<l_blit>},
|
||||
{"clear", lua::wrap<l_clear>},
|
||||
{"update", lua::wrap<l_update>}};
|
||||
{"update", lua::wrap<l_update>},
|
||||
};
|
||||
|
||||
static int l_meta_index(State* L) {
|
||||
auto texture = touserdata<LuaCanvas>(L, 1);
|
||||
@ -171,11 +190,28 @@ static int l_meta_newindex(State* L) {
|
||||
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;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user