From a65278c7bc9c0dbca8a74db09fd0aebf1c26ef28 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Sat, 29 Feb 2020 16:12:26 +0100 Subject: Read images as uint8_t instead of float. Convert Colour and all colour related operations to use uint8_t instade of float and finally optimize rendering to render lines instead of single pixels. --- plugingui/colour.cc | 29 +++--- plugingui/colour.h | 16 +-- plugingui/drawable.h | 4 + plugingui/font.cc | 8 +- plugingui/image.cc | 23 +++++ plugingui/image.h | 5 + plugingui/painter.cc | 153 +++++++++++++++++++++-------- plugingui/pixelbuffer.cc | 248 +++++++++++++++++++++++++++++++++++------------ plugingui/pixelbuffer.h | 46 +++++---- plugingui/texture.cc | 10 ++ plugingui/texture.h | 2 + plugingui/texturedbox.cc | 11 +++ plugingui/texturedbox.h | 2 + plugingui/window.cc | 16 +-- 14 files changed, 422 insertions(+), 151 deletions(-) diff --git a/plugingui/colour.cc b/plugingui/colour.cc index 02d03c6..7fd649c 100644 --- a/plugingui/colour.cc +++ b/plugingui/colour.cc @@ -28,43 +28,50 @@ #include -namespace GUI { +namespace GUI +{ Colour::Colour() { - data = {{1.0f, 1.0f, 1.0f, 1.0f}}; } Colour::Colour(float grey, float a) + : pixel({{(std::uint8_t)(grey * 255), + (std::uint8_t)(grey * 255), + (std::uint8_t)(grey * 255), + (std::uint8_t)(a * 255)}}) { - data = {{grey, grey, grey, a}}; } Colour::Colour(float r, float g, float b, float a) + : pixel({{(std::uint8_t)(r * 255), + (std::uint8_t)(g * 255), + (std::uint8_t)(b * 255), + (std::uint8_t)(a * 255)}}) { - data = {{r, g, b, a}}; } Colour::Colour(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a) - : Colour(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f) -{} + : pixel({{r, g, b, a}}) +{ +} Colour::Colour(const Colour& other) + : pixel(other.pixel) { - data = other.data; } Colour& Colour::operator=(const Colour& other) { - data = other.data; + pixel = other.pixel; return *this; } bool Colour::operator==(const Colour& other) const { - return data[0] == other.data[0] && - data[1] == other.data[1] && - data[2] == other.data[2]; + return pixel[0] == other.pixel[0] && + pixel[1] == other.pixel[1] && + pixel[2] == other.pixel[2]; } bool Colour::operator!=(const Colour& other) const diff --git a/plugingui/colour.h b/plugingui/colour.h index 3a135fc..0bc8659 100644 --- a/plugingui/colour.h +++ b/plugingui/colour.h @@ -32,7 +32,8 @@ namespace GUI { -class Colour { +class Colour +{ public: Colour(); Colour(float grey, float alpha = 1.0f); @@ -45,13 +46,16 @@ public: bool operator==(const Colour& other) const; bool operator!=(const Colour& other) const; - inline float red() const { return data[0]; } - inline float green() const { return data[1]; } - inline float blue() const { return data[2]; } - inline float alpha() const { return data[3]; } + inline std::uint8_t red() const { return pixel[0]; } + inline std::uint8_t green() const { return pixel[1]; } + inline std::uint8_t blue() const { return pixel[2]; } + inline std::uint8_t alpha() const { return pixel[3]; } + + std::uint8_t* data() { return pixel.data(); } + const std::uint8_t* data() const { return pixel.data(); } private: - std::array data; + std::array pixel{{255, 255, 255, 255}}; }; } // GUI:: diff --git a/plugingui/drawable.h b/plugingui/drawable.h index ff9a4ff..e793a27 100644 --- a/plugingui/drawable.h +++ b/plugingui/drawable.h @@ -27,6 +27,7 @@ #pragma once #include +#include namespace GUI { @@ -42,6 +43,9 @@ 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 bool hasAlpha() const = 0; }; } // GUI:: diff --git a/plugingui/font.cc b/plugingui/font.cc index 9f54b16..0500e81 100644 --- a/plugingui/font.cc +++ b/plugingui/font.cc @@ -59,8 +59,8 @@ Font::Font(const std::string& fontfile) auto& pixel = img_font.getPixel(px, 0); // Find next purple pixel in top row: - if((pixel.red() == 1.0f) && (pixel.green() == 0.0f) && - (pixel.blue() == 1.0f) && (pixel.alpha() == 1.0f)) + if((pixel.red() == 255) && (pixel.green() == 0) && + (pixel.blue() == 255) && (pixel.alpha() == 255)) { break; } @@ -124,9 +124,7 @@ PixelBufferAlpha *Font::render(const std::string& text) const for(size_t y = 0; y < img_font.height(); ++y) { auto& c = img_font.getPixel(x + character.offset, y); - pb->setPixel(x + x_offset + character.pre_bias, y, - c.red() * 255, c.green() * 255, - c.blue() * 255, c.alpha() * 255); + pb->setPixel(x + x_offset + character.pre_bias, y, c); } } x_offset += character.width + spacing + character.post_bias; diff --git a/plugingui/image.cc b/plugingui/image.cc index 70ee08e..54fd15e 100644 --- a/plugingui/image.cc +++ b/plugingui/image.cc @@ -60,6 +60,7 @@ Image::Image(Image&& other) : _width(other._width) , _height(other._height) , image_data(std::move(other.image_data)) + , image_data_raw(std::move(other.image_data_raw)) , filename(other.filename) { other._width = 0; @@ -74,6 +75,8 @@ Image& Image::operator=(Image&& other) { image_data.clear(); image_data = std::move(other.image_data); + image_data_raw.clear(); + image_data_raw = std::move(other.image_data_raw); _width = other._width; _height = other._height; valid = other.valid; @@ -111,6 +114,10 @@ void Image::setError() image_data.clear(); image_data.reserve(_width * _height); + image_data_raw.clear(); + image_data_raw.reserve(_width * _height * 4); + memcpy(image_data_raw.data(), ptr, _height * _width); + for(std::size_t y = 0; y < _height; ++y) { for(std::size_t x = 0; x < _width; ++x) @@ -125,6 +132,7 @@ void Image::setError() void Image::load(const char* data, size_t size) { + has_alpha = false; unsigned int iw{0}, ih{0}; std::uint8_t* char_image_data{nullptr}; unsigned int res = lodepng_decode32((std::uint8_t**)&char_image_data, @@ -145,12 +153,17 @@ void Image::load(const char* data, size_t size) image_data.clear(); image_data.reserve(_width * _height); + image_data_raw.clear(); + image_data_raw.reserve(_width * _height * 4); + memcpy(image_data_raw.data(), char_image_data, _height * _width * 4); + for(std::size_t y = 0; y < _height; ++y) { for(std::size_t x = 0; x < _width; ++x) { std::uint8_t* ptr = &char_image_data[(x + y * _width) * 4]; image_data.emplace_back(Colour{ptr[0], ptr[1], ptr[2], ptr[3]}); + has_alpha |= ptr[3] != 0xff; } } @@ -180,6 +193,16 @@ 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 +{ + return image_data_raw.data() + y * _width * 4; +} + +bool Image::hasAlpha() const +{ + return has_alpha; +} + bool Image::isValid() const { return valid; diff --git a/plugingui/image.h b/plugingui/image.h index dd7f347..4d140ab 100644 --- a/plugingui/image.h +++ b/plugingui/image.h @@ -50,6 +50,9 @@ 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; + + bool hasAlpha() const override; bool isValid() const; @@ -62,8 +65,10 @@ private: std::size_t _width{0}; std::size_t _height{0}; std::vector image_data; + std::vector image_data_raw; Colour out_of_range{0.0f, 0.0f, 0.0f, 0.0f}; std::string filename; + bool has_alpha{false}; }; } // GUI:: diff --git a/plugingui/painter.cc b/plugingui/painter.cc index acc92cb..89d7498 100644 --- a/plugingui/painter.cc +++ b/plugingui/painter.cc @@ -65,12 +65,7 @@ static void plot(PixelBufferAlpha& pixbuf, const Colour& colour, } // plot the pixel at (x, y) with brightness c (where 0 ≤ c ≤ 1) - pixbuf.addPixel(x, y, - (unsigned char)(colour.red() * 255.0), - (unsigned char)(colour.green() * 255.0), - (unsigned char)(colour.blue() * 255.0), - (unsigned char)(colour.alpha() * 255 * c)); - + pixbuf.addPixel(x, y, colour.red(), colour.green(), colour.blue(), colour.alpha() * c); } static inline double fpart(double x) @@ -171,13 +166,7 @@ void Painter::drawFilledRectangle(int x1, int y1, int x2, int y2) void Painter::clear() { - for(int x = 0; x < (int)pixbuf.width; ++x) - { - for(int y = 0; y < (int)pixbuf.height; ++y) - { - pixbuf.setPixel(x, y, 0, 0, 0, 0); - } - } + pixbuf.clear(); } void Painter::drawText(int x0, int y0, const Font& font, @@ -251,11 +240,8 @@ void Painter::drawText(int x0, int y0, const Font& font, assert(x + x0 < (int)pixbuf.width); assert(y + y0 < (int)pixbuf.height); - pixbuf.addPixel(x + x0, y + y0, - colour.red() * 255, - colour.green() * 255, - colour.blue() * 255, - colour.alpha() * a); + pixbuf.addPixel(x + x0, y + y0, colour.red(), colour.green(), + colour.blue(), (int)(colour.alpha() * a) / 255); } } } @@ -265,11 +251,7 @@ void Painter::drawText(int x0, int y0, const Font& font, void Painter::drawPoint(int x, int y) { - pixbuf.setPixel(x, y, - (unsigned char)(colour.red() * 255.0), - (unsigned char)(colour.green() * 255.0), - (unsigned char)(colour.blue() * 255.0), - (unsigned char)(colour.alpha() * 255.0)); + pixbuf.setPixel(x, y, colour); } static void plot4points(Painter *p, int cx, int cy, int x, int y) @@ -387,28 +369,123 @@ void Painter::drawImage(int x0, int y0, const Drawable& image) return; } - for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) + if(image.hasAlpha()) { - for(std::size_t x = -1 * std::min(0, x0); x < (std::size_t)fw; ++x) + if(true || !image.line(0)) + { + for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) + { + for(std::size_t x = -1 * std::min(0, x0); x < (std::size_t)fw; ++x) + { + assert(x >= 0); + assert(y >= 0); + assert(x < image.width()); + assert(y < image.height()); + auto& c = image.getPixel(x, y); + + assert(x0 + x >= 0); + assert(y0 + y >= 0); + assert(x0 + x < pixbuf.width); + assert(y0 + y < pixbuf.height); + + if (!has_restriction || c == restriction_colour) + { + pixbuf.addPixel(x0 + x, y0 + y, c); + } + } + } + } + else { - assert(x >= 0); - assert(y >= 0); - assert(x < image.width()); - assert(y < image.height()); - auto& c = image.getPixel(x, y); - - assert(x0 + x >= 0); - assert(y0 + y >= 0); - assert(x0 + x < pixbuf.width); - assert(y0 + y < pixbuf.height); - - if (!has_restriction || c == restriction_colour) + std::size_t x = -1 * std::min(0, x0); + for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) { - pixbuf.addPixel(x0 + x, y0 + y, c); + pixbuf.blendLine(x + x0, y + y0, image.line(y), image.width()); + } + } + } + else + { + std::size_t x = -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), image.width()); + } + } +} + +#if 0 +void Painter::drawImage(int x0, int y0, const Drawable& image) +{ + int fw = image.width(); + int fh = image.height(); + + // Make sure we don't try to draw outside the pixbuf. + if(fw > (int)(pixbuf.width - x0)) + { + fw = (int)(pixbuf.width - x0); + } + + if(fh > (int)(pixbuf.height - y0)) + { + fh = (int)(pixbuf.height - y0); + } + + if((fw < 1) || (fh < 1)) + { + return; + } + + if(image.hasAlpha()) + { + for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) + { + for(std::size_t x = -1 * std::min(0, x0); x < (std::size_t)fw; ++x) + { + assert(x >= 0); + assert(y >= 0); + assert(x < image.width()); + assert(y < image.height()); + auto& c = image.getPixel(x, y); + + assert(x0 + x >= 0); + assert(y0 + y >= 0); + assert(x0 + x < pixbuf.width); + assert(y0 + y < pixbuf.height); + + if (!has_restriction || c == restriction_colour) + { + pixbuf.addPixel(x0 + x, y0 + y, c); + } + } + } + } + else + { + for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) + { + for(std::size_t x = -1 * std::min(0, x0); x < (std::size_t)fw; ++x) + { + assert(x >= 0); + assert(y >= 0); + assert(x < image.width()); + assert(y < image.height()); + auto& c = image.getPixel(x, y); + + assert(x0 + x >= 0); + assert(y0 + y >= 0); + assert(x0 + x < pixbuf.width); + assert(y0 + y < pixbuf.height); + + if (!has_restriction || c == restriction_colour) + { + pixbuf.setPixel(x0 + x, y0 + y, c); + } } } } } +#endif void Painter::drawRestrictedImage(int x0, int y0, Colour const& colour, const Drawable& image) { diff --git a/plugingui/pixelbuffer.cc b/plugingui/pixelbuffer.cc index 360ad06..1df1d5a 100644 --- a/plugingui/pixelbuffer.cc +++ b/plugingui/pixelbuffer.cc @@ -29,6 +29,7 @@ #include #include +#include namespace GUI { @@ -47,43 +48,63 @@ PixelBuffer::~PixelBuffer() void PixelBuffer::realloc(std::size_t width, std::size_t height) { free(buf); - buf = (unsigned char *)calloc(width * height, 3); + buf = (std::uint8_t *)calloc(width * height, 3); this->width = width; this->height = height; } #define PX(k) ((x + y * width) * 3 + k) -void PixelBuffer::setPixel(std::size_t x, std::size_t y, - unsigned char red, - unsigned char green, - unsigned char blue, - unsigned char alpha) +void PixelBuffer::setPixel(std::size_t x, std::size_t y, const Colour& c) { - assert(x < width); - assert(y < height); - - if(alpha == 0) + if(c.alpha() == 0) { return; } - if(alpha < 255) + if(c.alpha() < 255) { - unsigned int a = alpha; - unsigned int b = 255 - alpha; + unsigned int a = c.alpha(); + unsigned int b = 255 - a; - buf[PX(0)] = (unsigned char)(((int)red * a + (int)buf[PX(0)] * b) / 255); - buf[PX(1)] = (unsigned char)(((int)green * a + (int)buf[PX(1)] * b) / 255); - buf[PX(2)] = (unsigned char)(((int)blue * a + (int)buf[PX(2)] * b) / 255); + std::uint8_t* pixel = &buf[PX(0)]; + *pixel = (std::uint8_t)(((int)c.red() * a + (int)*pixel * b) / 255); + ++pixel; + *pixel = (std::uint8_t)(((int)c.green() * a + (int)*pixel * b) / 255); + ++pixel; + *pixel = (std::uint8_t)(((int)c.blue() * a + (int)*pixel * b) / 255); } else { - buf[PX(0)] = red; - buf[PX(1)] = green; - buf[PX(2)] = blue; + memcpy(&buf[PX(0)], c.data(), 3); + } +} + +void PixelBuffer::writeLine(std::size_t x, std::size_t y, + const std::uint8_t* line, std::size_t len) +{ + std::uint8_t* target = &buf[PX(0)]; + while(len) + { + if(line[3] == 0xff) + { + memcpy(target, line, 3); + } + else + { + unsigned int a = line[3]; + unsigned int b = 255 - a; + + target[0] = (std::uint8_t)(((int)line[0] * a + (int)target[0] * b) / 255); + target[1] = (std::uint8_t)(((int)line[1] * a + (int)target[1] * b) / 255); + target[2] = (std::uint8_t)(((int)line[2] * a + (int)target[2] * b) / 255); + } + target += 3; + line += 4; + --len; } } + PixelBufferAlpha::PixelBufferAlpha(std::size_t width, std::size_t height) : managed(true) , buf(nullptr) @@ -104,30 +125,110 @@ PixelBufferAlpha::~PixelBufferAlpha() void PixelBufferAlpha::realloc(std::size_t width, std::size_t height) { free(buf); - buf = (unsigned char *)calloc(width * height, 4); + buf = (std::uint8_t *)calloc(width * height, 4); this->width = width; this->height = height; } +void PixelBufferAlpha::clear() +{ + memset(buf, 0, width * height * 4); +} + #undef PX #define PX(k) ((x + y * width) * 4 + k) -void PixelBufferAlpha::setPixel(std::size_t x, std::size_t y, - unsigned char red, - unsigned char green, - unsigned char blue, - unsigned char alpha) +//void PixelBufferAlpha::setPixel(std::size_t x, std::size_t y, +// std::uint8_t red, +// std::uint8_t green, +// std::uint8_t blue, +// std::uint8_t alpha) +//{ +// //assert(x < width); +// //assert(y < height); +// +// std::uint8_t* pixel = &buf[PX(0)]; +// *pixel = red; +// ++pixel; +// *pixel = green; +// ++pixel; +// *pixel = blue; +// ++pixel; +// *pixel = alpha; +//} + +void PixelBufferAlpha::setPixel(std::size_t x, std::size_t y, const Colour& c) { - assert(x < width); - assert(y < height); + std::uint8_t* pixel = &buf[PX(0)]; + *pixel = c.red(); + ++pixel; + *pixel = c.green(); + ++pixel; + *pixel = c.blue(); + ++pixel; + *pixel = c.alpha(); +} - buf[PX(0)] = red; - buf[PX(1)] = green; - buf[PX(2)] = blue; - buf[PX(3)] = alpha; +void PixelBufferAlpha::writeLine(std::size_t x, std::size_t y, + const std::uint8_t* line, std::size_t len) +{ + auto offset = &buf[PX(0)]; + if(x + y * width + len > width * height) + { + return; // out of bounds + } + std::memcpy(offset, line, len * 4); } +// SIMD: https://github.com/WojciechMula/toys/blob/master/blend_32bpp/blend_32bpp.c + +void PixelBufferAlpha::blendLine(std::size_t x, std::size_t y, + const std::uint8_t* line, std::size_t len) +{ + auto offset = &buf[PX(0)]; + if(x + y * width + len > width * height) + { + return; // out of bounds + } + + std::uint32_t* foreground = (std::uint32_t*)line; + std::uint32_t* background = (std::uint32_t*)offset; + for(std::size_t x = 0; x < len; ++x) + { + auto Rf = *foreground & 0xff; + auto Gf = (*foreground >> 8) & 0xff; + auto Bf = (*foreground >> 16) & 0xff; + auto Af = (*foreground >> 24) & 0xff; + + auto Rb = *background & 0xff; + auto Gb = (*background >> 8) & 0xff; + auto Bb = (*background >> 16) & 0xff; + auto Ab = (*background >> 24) & 0xff; + + auto R = (Rf * Af)/256 + Rb; + auto G = (Gf * Af)/256 + Gb; + auto B = (Bf * Af)/256 + Bb; + + if (R > 255) R = 255; + if (G > 255) G = 255; + if (B > 255) B = 255; + +// auto a = Ab / 255.0; +// auto b = Af / 255.0; +// b *= (1 - a); + +// (Af / 255.0 * (1 - Ab / 255.0)) * 255 + auto b = Ab * (255 - Af); + + *background = R | (G << 8) | (B << 16) | b << 24; + + ++foreground; + ++background; + } +} + + // http://en.wikipedia.org/wiki/Alpha_compositing -static inline void getAlpha(unsigned char _a, unsigned char _b, +static inline void getAlpha(std::uint8_t _a, std::uint8_t _b, float &a, float &b) { a = _a / 255.0; @@ -136,61 +237,80 @@ static inline void getAlpha(unsigned char _a, unsigned char _b, } void PixelBufferAlpha::addPixel(std::size_t x, std::size_t y, - unsigned char red, - unsigned char green, - unsigned char blue, - unsigned char alpha) + std::uint8_t red, + std::uint8_t green, + std::uint8_t blue, + std::uint8_t alpha) { - assert(x < width); - assert(y < height); + //assert(x < width); + //assert(y < height); if(alpha == 0) { return; } + std::uint8_t* pixel = &buf[PX(0)]; + if(alpha < 255) { float a, b; getAlpha(alpha, buf[PX(3)], a, b); - buf[PX(0)] = (unsigned char)((float)red * a + (float)buf[PX(0)] * b); - buf[PX(0)] /= (a + b); - buf[PX(1)] = (unsigned char)((float)green * a + (float)buf[PX(1)] * b); - buf[PX(1)] /= (a + b); - buf[PX(2)] = (unsigned char)((float)blue * a + (float)buf[PX(2)] * b); - buf[PX(2)] /= (a + b); - - buf[PX(3)] = (a + b) * 255; + *pixel = (std::uint8_t)((red * a + *pixel * b) / (a + b)); + ++pixel; + *pixel = (std::uint8_t)((green * a + *pixel * b) / (a + b)); + ++pixel; + *pixel = (std::uint8_t)((blue * a + *pixel * b) / (a + b)); + ++pixel; + *pixel = (a + b) * 255; } else { - buf[PX(0)] = red; - buf[PX(1)] = green; - buf[PX(2)] = blue; - buf[PX(3)] = alpha; + *pixel = red; + ++pixel; + *pixel = green; + ++pixel; + *pixel = blue; + ++pixel; + *pixel = alpha; } } void PixelBufferAlpha::addPixel(std::size_t x, std::size_t y, const Colour& c) { - addPixel(x, y, - c.red() * 255, c.green() * 255, c.blue() * 255, c.alpha() * 255); + addPixel(x, y, c.red(), c.green(), c.blue(), c.alpha()); } void PixelBufferAlpha::pixel(std::size_t x, std::size_t y, - unsigned char* red, - unsigned char* green, - unsigned char* blue, - unsigned char* alpha) const -{ - assert(x < width); - assert(y < height); - - *red = buf[PX(0)]; - *green = buf[PX(1)]; - *blue = buf[PX(2)]; - *alpha = buf[PX(3)]; + std::uint8_t* red, + std::uint8_t* green, + std::uint8_t* blue, + std::uint8_t* alpha) const +{ + //assert(x < width); + //assert(y < height); + + std::uint8_t* pixel = &buf[PX(0)]; + *red = *pixel; + ++pixel; + *green = *pixel; + ++pixel; + *blue = *pixel; + ++pixel; + *alpha = *pixel; +} + +const Colour& PixelBufferAlpha::pixel(std::size_t x, std::size_t y) const +{ + static Colour c; + c = Colour(buf[PX(0)], buf[PX(1)], buf[PX(2)], buf[PX(3)]); + return c; +} + +const std::uint8_t* PixelBufferAlpha::getLine(std::size_t x, std::size_t y) const +{ + return &buf[PX(0)]; } } // GUI:: diff --git a/plugingui/pixelbuffer.h b/plugingui/pixelbuffer.h index 71869a0..499940d 100644 --- a/plugingui/pixelbuffer.h +++ b/plugingui/pixelbuffer.h @@ -41,13 +41,12 @@ public: void realloc(std::size_t width, std::size_t height); - void setPixel(std::size_t x, std::size_t y, - unsigned char red, - unsigned char green, - unsigned char blue, - unsigned char alpha); + void setPixel(std::size_t x, std::size_t y, const Colour& c); - unsigned char* buf{nullptr}; + void writeLine(std::size_t x, std::size_t y, + const std::uint8_t* line, std::size_t len); + + std::uint8_t* buf{nullptr}; std::size_t width{0}; std::size_t height{0}; }; @@ -61,28 +60,35 @@ public: void realloc(std::size_t width, std::size_t height); - void setPixel(std::size_t x, std::size_t y, - unsigned char red, - unsigned char green, - unsigned char blue, - unsigned char alpha); + void clear(); + + void setPixel(std::size_t x, std::size_t y, const Colour& c); + + void writeLine(std::size_t x, std::size_t y, + const std::uint8_t* line, std::size_t len); + void blendLine(std::size_t x, std::size_t y, + const std::uint8_t* line, std::size_t len); void addPixel(std::size_t x, std::size_t y, - unsigned char red, - unsigned char green, - unsigned char blue, - unsigned char alpha); + std::uint8_t red, + std::uint8_t green, + std::uint8_t blue, + std::uint8_t alpha); void addPixel(std::size_t x, std::size_t y, const Colour& c); void pixel(std::size_t x, std::size_t y, - unsigned char* red, - unsigned char* green, - unsigned char* blue, - unsigned char* alpha) const; + std::uint8_t* red, + std::uint8_t* green, + std::uint8_t* blue, + std::uint8_t* alpha) const; + + const Colour& pixel(std::size_t x, std::size_t y) const; + + const std::uint8_t* getLine(std::size_t x, std::size_t y) const; bool managed{false}; - unsigned char* buf{nullptr}; + std::uint8_t* buf{nullptr}; std::size_t width{0}; std::size_t height{0}; int x{0}; diff --git a/plugingui/texture.cc b/plugingui/texture.cc index 6dc6441..39d417d 100644 --- a/plugingui/texture.cc +++ b/plugingui/texture.cc @@ -59,4 +59,14 @@ 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 +{ + return image.line(y + _y); +} + +bool Texture::hasAlpha() const +{ + return true; +} + } // GUI:: diff --git a/plugingui/texture.h b/plugingui/texture.h index c165f19..e5b0472 100644 --- a/plugingui/texture.h +++ b/plugingui/texture.h @@ -49,6 +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; + bool hasAlpha() const override; private: std::size_t _x; diff --git a/plugingui/texturedbox.cc b/plugingui/texturedbox.cc index a03eecd..21bf946 100644 --- a/plugingui/texturedbox.cc +++ b/plugingui/texturedbox.cc @@ -133,4 +133,15 @@ 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 +{ + // TODO: Gather line into temporary buffer? + return nullptr; +} + +bool TexturedBox::hasAlpha() const +{ + return true; +} + } // GUI:: diff --git a/plugingui/texturedbox.h b/plugingui/texturedbox.h index dc84183..0ff0490 100644 --- a/plugingui/texturedbox.h +++ b/plugingui/texturedbox.h @@ -89,6 +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; + bool hasAlpha() const override; private: Texture seg_a; diff --git a/plugingui/window.cc b/plugingui/window.cc index a9deed5..acde008 100644 --- a/plugingui/window.cc +++ b/plugingui/window.cc @@ -349,8 +349,6 @@ bool Window::updateBuffer() update_height = ((int)wpixbuf.height - pixel_buffer->y); } - std::uint8_t r, g, b, a; - auto from_x = (int)dirty_rect.x1 - pixel_buffer->x; from_x = std::max(0, from_x); auto from_y = (int)dirty_rect.y1 - pixel_buffer->y; @@ -361,13 +359,17 @@ bool Window::updateBuffer() auto to_y = (int)dirty_rect.y2 - pixel_buffer->y; to_y = std::min(to_y, (int)update_height); + if(to_x < from_x) + { + continue; + } + for(int y = from_y; y < to_y; y++) { - for(int x = from_x; x < to_x; x++) - { - pixel_buffer->pixel(x, y, &r, &g, &b, &a); - wpixbuf.setPixel(x + pixel_buffer->x, y + pixel_buffer->y, r, g, b, a); - } + wpixbuf.writeLine(pixel_buffer->x + from_x, + pixel_buffer->y + y, + pixel_buffer->getLine(from_x, y), + to_x - from_x); } } -- cgit v1.2.3