From a8eea6e9c1f32d5562594656c68dc4b9f985b790 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sat, 14 Nov 2020 09:46:34 +0100 Subject: Add x_offset to drawable::line to be able to have drawImage render images outside the parent area. --- plugingui/drawable.h | 3 +- plugingui/image.cc | 4 +-- plugingui/image.h | 5 +-- plugingui/painter.cc | 12 +++---- plugingui/texture.cc | 4 +-- plugingui/texture.h | 3 +- plugingui/texturedbox.cc | 2 +- plugingui/texturedbox.h | 3 +- test/paintertest.cc | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 112 insertions(+), 16 deletions(-) diff --git a/plugingui/drawable.h b/plugingui/drawable.h index e793a27..95492d6 100644 --- a/plugingui/drawable.h +++ b/plugingui/drawable.h @@ -43,7 +43,8 @@ public: virtual std::size_t height() const = 0; virtual const Colour& getPixel(std::size_t x, std::size_t y) const = 0; - virtual const std::uint8_t* line(std::size_t y) const = 0; + virtual const std::uint8_t* line(std::size_t y, + std::size_t x_offset = 0) const = 0; virtual bool hasAlpha() const = 0; }; diff --git a/plugingui/image.cc b/plugingui/image.cc index 1b858ad..118203e 100644 --- a/plugingui/image.cc +++ b/plugingui/image.cc @@ -198,9 +198,9 @@ const Colour& Image::getPixel(size_t x, size_t y) const return image_data[x + y * _width]; } -const std::uint8_t* Image::line(std::size_t y) const +const std::uint8_t* Image::line(std::size_t y, std::size_t x_offset) const { - return image_data_raw.data() + y * _width * 4; + return image_data_raw.data() + y * _width * 4 + x_offset * 4; } bool Image::hasAlpha() const diff --git a/plugingui/image.h b/plugingui/image.h index 4d140ab..d162a75 100644 --- a/plugingui/image.h +++ b/plugingui/image.h @@ -50,13 +50,14 @@ public: size_t height() const override; const Colour& getPixel(size_t x, size_t y) const override; - const std::uint8_t* line(std::size_t y) const override; + const std::uint8_t* line(std::size_t y, + std::size_t x_offset = 0) const override; bool hasAlpha() const override; bool isValid() const; -private: +protected: void setError(); bool valid{false}; diff --git a/plugingui/painter.cc b/plugingui/painter.cc index f2fc66a..f746f83 100644 --- a/plugingui/painter.cc +++ b/plugingui/painter.cc @@ -437,21 +437,21 @@ void Painter::drawImage(int x0, int y0, const Drawable& image) } else { - std::size_t x = -1 * std::min(0, x0); + std::size_t x_offset = -1 * std::min(0, x0); for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) { - pixbuf.blendLine(x + x0, y + y0, image.line(y), - std::min((int)image.width(), fw - (int)x)); + pixbuf.blendLine(x_offset + x0, y + y0, image.line(y, x_offset), + std::min((int)image.width(), fw - (int)x_offset)); } } } else { - std::size_t x = -1 * std::min(0, x0); + std::size_t x_offset = -1 * std::min(0, x0); for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) { - pixbuf.writeLine(x + x0, y + y0, image.line(y), - std::min((int)image.width(), fw - (int)x)); + pixbuf.writeLine(x_offset + x0, y + y0, image.line(y, x_offset), + std::min((int)image.width(), fw - (int)x_offset)); } } } diff --git a/plugingui/texture.cc b/plugingui/texture.cc index a5908cb..8cd7040 100644 --- a/plugingui/texture.cc +++ b/plugingui/texture.cc @@ -59,9 +59,9 @@ const Colour& Texture::getPixel(size_t x, size_t y) const return image.getPixel(x + _x, y + _y); } -const std::uint8_t* Texture::line(std::size_t y) const +const std::uint8_t* Texture::line(std::size_t y, std::size_t x_offset) const { - return image.line(y + _y) + _x * 4; + return image.line(y + _y) + _x * 4 + x_offset * 4; } bool Texture::hasAlpha() const diff --git a/plugingui/texture.h b/plugingui/texture.h index e5b0472..c751ed4 100644 --- a/plugingui/texture.h +++ b/plugingui/texture.h @@ -49,7 +49,8 @@ public: size_t height() const override; const Colour& getPixel(size_t x, size_t y) const override; - const std::uint8_t* line(std::size_t y) const override; + const std::uint8_t* line(std::size_t y, + std::size_t x_offset = 0) const override; bool hasAlpha() const override; private: diff --git a/plugingui/texturedbox.cc b/plugingui/texturedbox.cc index 21bf946..e48353a 100644 --- a/plugingui/texturedbox.cc +++ b/plugingui/texturedbox.cc @@ -133,7 +133,7 @@ const Colour& TexturedBox::getPixel(std::size_t x, std::size_t y) const return outOfRange; } -const std::uint8_t* TexturedBox::line(std::size_t y) const +const std::uint8_t* TexturedBox::line(std::size_t y, std::size_t x_offset) const { // TODO: Gather line into temporary buffer? return nullptr; diff --git a/plugingui/texturedbox.h b/plugingui/texturedbox.h index 0ff0490..7aa3967 100644 --- a/plugingui/texturedbox.h +++ b/plugingui/texturedbox.h @@ -89,7 +89,8 @@ public: void setSize(std::size_t width, std::size_t height); const Colour& getPixel(std::size_t x, std::size_t y) const override; - const std::uint8_t* line(std::size_t y) const override; + const std::uint8_t* line(std::size_t y, + std::size_t x_offset = 0) const override; bool hasAlpha() const override; private: diff --git a/test/paintertest.cc b/test/paintertest.cc index f471313..fb17a91 100644 --- a/test/paintertest.cc +++ b/test/paintertest.cc @@ -31,6 +31,37 @@ #include "../plugingui/image.h" #include "../plugingui/font.h" +class TestColour +{ +public: + TestColour(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a) + : colour(r, g, b, a) {} + TestColour(const GUI::Colour& colour) + : colour(colour) {} + + bool operator!=(const TestColour& other) const + { + return + colour.red() != other.colour.red() || + colour.green() != other.colour.green() || + colour.blue() != other.colour.blue() || + colour.alpha() != other.colour.alpha() + ; + } + + const GUI::Colour colour; +}; + +std::ostream& operator<<(std::ostream& stream, const TestColour& col) +{ + stream << "(" << + static_cast(col.colour.red()) << ", " << + static_cast(col.colour.green()) << ", " << + static_cast(col.colour.blue()) << ", " << + static_cast(col.colour.alpha()) << ")"; + return stream; +} + class TestableCanvas : public GUI::Canvas { @@ -48,6 +79,37 @@ private: GUI::PixelBufferAlpha pixbuf; }; +class TestImage + : public GUI::Image +{ +public: + TestImage(std::uint8_t width, std::uint8_t height, bool alpha) + : GUI::Image(":resources/logo.png") // just load some default image + { + _width = width; + _height = height; + has_alpha = alpha; + + image_data.resize(_width * _height); + image_data_raw.resize(_width * _height); + + // Store x and y coordinates as red and green colour components + for(std::uint8_t x = 0; x < _width; ++x) + { + for(std::uint8_t y = 0; y < _height; ++y) + { + image_data[x + _width * y] = GUI::Colour(x, y, 0, alpha ? 128 : 255); + image_data_raw[4 * (x + _width * y) + 0] = x; + image_data_raw[4 * (x + _width * y) + 1] = y; + image_data_raw[4 * (x + _width * y) + 2] = 0; + image_data_raw[4 * (x + _width * y) + 3] = alpha ? 128 : 255; + } + } + + valid = true; + } +}; + class PainterTest : public uUnit { @@ -56,6 +118,7 @@ public: { uUNIT_TEST(PainterTest::testDrawImage); uUNIT_TEST(PainterTest::testDrawText); + uUNIT_TEST(PainterTest::testClipping); } void testDrawImage() @@ -153,6 +216,35 @@ public: font, someText); } } + + // Test rendering images outside the container is being clipped correctly. + void testClipping() + { + TestableCanvas canvas(100, 100); + GUI::Painter painter(canvas); + + { // Without alpha + TestImage image(16, 16, false); + painter.clear(); + painter.drawImage(-10, -10, image); + auto& pixbuf = canvas.getPixelBuffer(); + + // Top left corner pixel should have the RGBA value (10, 10, 0, 255) + uUNIT_ASSERT_EQUAL(TestColour(10, 10, 0, 255), + TestColour(pixbuf.pixel(0, 0))); + } + + { // With alpha (different pipeline) + TestImage image(16, 16, true); + painter.clear(); + painter.drawImage(-10, -10, image); + auto& pixbuf = canvas.getPixelBuffer(); + + // Top left corner pixel should have the RGBA value (10, 10, 0, 128) + uUNIT_ASSERT_EQUAL(TestColour(10, 10, 0, 128), + TestColour(pixbuf.pixel(0, 0))); + } + } }; // Registers the fixture into the 'registry' -- cgit v1.2.3