From 0d4838facf61dbcacc256eda90ac7d57d2e19db1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 13 Nov 2025 18:06:47 +0300 Subject: [PATCH] feat: autoresize (extend/shrink) canvas element --- src/graphics/core/ImageData.cpp | 26 +++++++++++++++++++++++++ src/graphics/core/ImageData.hpp | 1 + src/graphics/core/Texture.cpp | 4 ++-- src/graphics/core/Texture.hpp | 2 +- src/graphics/ui/elements/Canvas.cpp | 18 +++++++++++------ src/graphics/ui/elements/Canvas.hpp | 16 ++++++++------- src/logic/scripting/lua/libs/libgui.cpp | 2 +- 7 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/graphics/core/ImageData.cpp b/src/graphics/core/ImageData.cpp index bd243832..218428e7 100644 --- a/src/graphics/core/ImageData.cpp +++ b/src/graphics/core/ImageData.cpp @@ -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(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) { uint comps; switch (format) { diff --git a/src/graphics/core/ImageData.hpp b/src/graphics/core/ImageData.hpp index a1597a98..94987886 100644 --- a/src/graphics/core/ImageData.hpp +++ b/src/graphics/core/ImageData.hpp @@ -36,6 +36,7 @@ public: void mulColor(const ImageData& other); void addColor(const glm::ivec4& color, int multiplier); void addColor(const ImageData& other, int multiplier); + void extend(int newWidth, int newHeight); std::unique_ptr cropped(int x, int y, int width, int height) const; diff --git a/src/graphics/core/Texture.cpp b/src/graphics/core/Texture.cpp index 04285aa8..dcd29e37 100644 --- a/src/graphics/core/Texture.cpp +++ b/src/graphics/core/Texture.cpp @@ -44,10 +44,10 @@ void Texture::unbind() const { void Texture::reload(const ImageData& image) { width = image.getWidth(); 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); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast(data)); diff --git a/src/graphics/core/Texture.hpp b/src/graphics/core/Texture.hpp index 5e67890c..3c8f1b4c 100644 --- a/src/graphics/core/Texture.hpp +++ b/src/graphics/core/Texture.hpp @@ -18,7 +18,7 @@ public: virtual void bind() 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 setNearestFilter(); diff --git a/src/graphics/ui/elements/Canvas.cpp b/src/graphics/ui/elements/Canvas.cpp index 8d48f6a5..6f43f944 100644 --- a/src/graphics/ui/elements/Canvas.cpp +++ b/src/graphics/ui/elements/Canvas.cpp @@ -4,11 +4,11 @@ #include "graphics/core/DrawContext.hpp" #include "graphics/core/Texture.hpp" -gui::Canvas::Canvas(GUI& gui, ImageFormat inFormat, glm::uvec2 inSize) - : UINode(gui, inSize) { - auto data = std::make_shared(inFormat, inSize.x, inSize.y); - mTexture = Texture::from(data.get()); - mData = std::move(data); +gui::Canvas::Canvas(GUI& gui, ImageFormat format, glm::uvec2 size) + : UINode(gui, size) { + auto data = std::make_shared(format, size.x, size.y); + texture = Texture::from(data.get()); + this->data = std::move(data); } 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 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); } + +void gui::Canvas::setSize(glm::vec2 size) { + UINode::setSize(size); + data->extend(size.x, size.y); + texture->reload(*data); +} diff --git a/src/graphics/ui/elements/Canvas.hpp b/src/graphics/ui/elements/Canvas.hpp index 0ed70cd1..63430b8f 100644 --- a/src/graphics/ui/elements/Canvas.hpp +++ b/src/graphics/ui/elements/Canvas.hpp @@ -9,21 +9,23 @@ class Texture; namespace gui { class Canvas final : public UINode { public: - explicit Canvas(GUI& gui, ImageFormat inFormat, glm::uvec2 inSize); + explicit Canvas(GUI& gui, ImageFormat format, glm::uvec2 size); ~Canvas() override = default; void draw(const DrawContext& pctx, const Assets& assets) override; - [[nodiscard]] auto texture() const { - return mTexture; + void setSize(glm::vec2 size) override; + + [[nodiscard]] auto getTexture() const { + return texture; } - [[nodiscard]] auto data() const { - return mData; + [[nodiscard]] auto getData() const { + return data; } private: - std::shared_ptr<::Texture> mTexture; - std::shared_ptr mData; + std::shared_ptr<::Texture> texture; + std::shared_ptr data; }; } diff --git a/src/logic/scripting/lua/libs/libgui.cpp b/src/logic/scripting/lua/libs/libgui.cpp index cdf65898..6e703104 100644 --- a/src/logic/scripting/lua/libs/libgui.cpp +++ b/src/logic/scripting/lua/libs/libgui.cpp @@ -380,7 +380,7 @@ static int p_get_region(UINode* node, lua::State* L) { static int p_get_data(UINode* node, lua::State* L) { if (auto canvas = dynamic_cast(node)) { - return lua::newuserdata(L, canvas->texture(), canvas->data()); + return lua::newuserdata(L, canvas->getTexture(), canvas->getData()); } return 0; }