feat: autoresize (extend/shrink) canvas element

This commit is contained in:
MihailRis 2025-11-13 18:06:47 +03:00
parent b644a76904
commit 0d4838facf
7 changed files with 52 additions and 17 deletions

View File

@ -470,6 +470,32 @@ void ImageData::addColor(const ImageData& other, int multiplier) {
} }
} }
void ImageData::extend(int newWidth, int newHeight) {
size_t comps;
switch (format) {
case ImageFormat::rgb888: comps = 3; break;
case ImageFormat::rgba8888: comps = 4; break;
default:
throw std::runtime_error("only unsigned byte formats supported");
}
auto newData = std::make_unique<ubyte[]>(newWidth * newHeight * comps);
for (uint y = 0; y < newHeight; y++) {
for (uint x = 0; x < newWidth; x++) {
for (size_t c = 0; c < comps; c++) {
if (x < width && y < height) {
newData[(y * newWidth + x) * comps + c] =
data[(y * width + x) * comps + c];
} else {
newData[(y * newWidth + x) * comps + c] = 0;
}
}
}
}
data = std::move(newData);
width = newWidth;
height = newHeight;
}
void ImageData::addColor(const glm::ivec4& color, int multiplier) { void ImageData::addColor(const glm::ivec4& color, int multiplier) {
uint comps; uint comps;
switch (format) { switch (format) {

View File

@ -36,6 +36,7 @@ public:
void mulColor(const ImageData& other); void mulColor(const ImageData& other);
void addColor(const glm::ivec4& color, int multiplier); void addColor(const glm::ivec4& color, int multiplier);
void addColor(const ImageData& other, int multiplier); void addColor(const ImageData& other, int multiplier);
void extend(int newWidth, int newHeight);
std::unique_ptr<ImageData> cropped(int x, int y, int width, int height) const; std::unique_ptr<ImageData> cropped(int x, int y, int width, int height) const;

View File

@ -44,10 +44,10 @@ void Texture::unbind() const {
void Texture::reload(const ImageData& image) { void Texture::reload(const ImageData& image) {
width = image.getWidth(); width = image.getWidth();
height = image.getHeight(); height = image.getHeight();
reload(image.getData()); reload(image.getData(), width, height);
} }
void Texture::reload(const ubyte* data) { void Texture::reload(const ubyte* data, uint width, uint height) {
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data)); GL_RGBA, GL_UNSIGNED_BYTE, static_cast<const GLvoid*>(data));

View File

@ -18,7 +18,7 @@ public:
virtual void bind() const; virtual void bind() const;
virtual void unbind() const; virtual void unbind() const;
void reload(const ubyte* data); void reload(const ubyte* data, uint w, uint h);
void reloadPartial(const ImageData& image, uint x, uint y, uint w, uint h); void reloadPartial(const ImageData& image, uint x, uint y, uint w, uint h);
void setNearestFilter(); void setNearestFilter();

View File

@ -4,11 +4,11 @@
#include "graphics/core/DrawContext.hpp" #include "graphics/core/DrawContext.hpp"
#include "graphics/core/Texture.hpp" #include "graphics/core/Texture.hpp"
gui::Canvas::Canvas(GUI& gui, ImageFormat inFormat, glm::uvec2 inSize) gui::Canvas::Canvas(GUI& gui, ImageFormat format, glm::uvec2 size)
: UINode(gui, inSize) { : UINode(gui, size) {
auto data = std::make_shared<ImageData>(inFormat, inSize.x, inSize.y); auto data = std::make_shared<ImageData>(format, size.x, size.y);
mTexture = Texture::from(data.get()); texture = Texture::from(data.get());
mData = std::move(data); this->data = std::move(data);
} }
void gui::Canvas::draw(const DrawContext& pctx, const Assets& assets) { void gui::Canvas::draw(const DrawContext& pctx, const Assets& assets) {
@ -16,6 +16,12 @@ void gui::Canvas::draw(const DrawContext& pctx, const Assets& assets) {
auto col = calcColor(); auto col = calcColor();
auto batch = pctx.getBatch2D(); auto batch = pctx.getBatch2D();
batch->texture(mTexture.get()); batch->texture(texture.get());
batch->rect(pos.x, pos.y, size.x, size.y, 0, 0, 0, {}, false, false, col); batch->rect(pos.x, pos.y, size.x, size.y, 0, 0, 0, {}, false, false, col);
} }
void gui::Canvas::setSize(glm::vec2 size) {
UINode::setSize(size);
data->extend(size.x, size.y);
texture->reload(*data);
}

View File

@ -9,21 +9,23 @@ class Texture;
namespace gui { namespace gui {
class Canvas final : public UINode { class Canvas final : public UINode {
public: public:
explicit Canvas(GUI& gui, ImageFormat inFormat, glm::uvec2 inSize); explicit Canvas(GUI& gui, ImageFormat format, glm::uvec2 size);
~Canvas() override = default; ~Canvas() override = default;
void draw(const DrawContext& pctx, const Assets& assets) override; void draw(const DrawContext& pctx, const Assets& assets) override;
[[nodiscard]] auto texture() const { void setSize(glm::vec2 size) override;
return mTexture;
[[nodiscard]] auto getTexture() const {
return texture;
} }
[[nodiscard]] auto data() const { [[nodiscard]] auto getData() const {
return mData; return data;
} }
private: private:
std::shared_ptr<::Texture> mTexture; std::shared_ptr<::Texture> texture;
std::shared_ptr<ImageData> mData; std::shared_ptr<ImageData> data;
}; };
} }

View File

@ -380,7 +380,7 @@ static int p_get_region(UINode* node, lua::State* L) {
static int p_get_data(UINode* node, lua::State* L) { static int p_get_data(UINode* node, lua::State* L) {
if (auto canvas = dynamic_cast<Canvas*>(node)) { if (auto canvas = dynamic_cast<Canvas*>(node)) {
return lua::newuserdata<lua::LuaCanvas>(L, canvas->texture(), canvas->data()); return lua::newuserdata<lua::LuaCanvas>(L, canvas->getTexture(), canvas->getData());
} }
return 0; return 0;
} }