summaryrefslogtreecommitdiff
path: root/plugingui
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2020-02-29 16:12:26 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2020-03-07 19:22:34 +0100
commita65278c7bc9c0dbca8a74db09fd0aebf1c26ef28 (patch)
treef6137641afd154dca1c45480137e9b56afb1a7d6 /plugingui
parent450e39c5b02ace3c50d116e4cba825ff695c8665 (diff)
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.
Diffstat (limited to 'plugingui')
-rw-r--r--plugingui/colour.cc29
-rw-r--r--plugingui/colour.h16
-rw-r--r--plugingui/drawable.h4
-rw-r--r--plugingui/font.cc8
-rw-r--r--plugingui/image.cc23
-rw-r--r--plugingui/image.h5
-rw-r--r--plugingui/painter.cc153
-rw-r--r--plugingui/pixelbuffer.cc248
-rw-r--r--plugingui/pixelbuffer.h46
-rw-r--r--plugingui/texture.cc10
-rw-r--r--plugingui/texture.h2
-rw-r--r--plugingui/texturedbox.cc11
-rw-r--r--plugingui/texturedbox.h2
-rw-r--r--plugingui/window.cc16
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 <cstring>
-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<float, 4> data;
+ std::array<std::uint8_t, 4> 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 <cstdlib>
+#include <cstdint>
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<Colour> image_data;
+ std::vector<std::uint8_t> 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 <cassert>
#include <cstdlib>
+#include <cstring>
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);
}
}