summaryrefslogtreecommitdiff
path: root/plugingui/pixelbuffer.cc
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2020-03-03 19:16:04 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2020-03-07 19:23:12 +0100
commitdf71bccf9c4731af9bcca79eee8d95651646bd82 (patch)
tree1c9485bed0fdd64410282156537553b8fde3bb86 /plugingui/pixelbuffer.cc
parent560574d2e565510edd39dd9daf1d957a85f2220c (diff)
Further optimize pixel blending. And re-introduce lineBlending in Painter::drawImage.
Diffstat (limited to 'plugingui/pixelbuffer.cc')
-rw-r--r--plugingui/pixelbuffer.cc78
1 files changed, 47 insertions, 31 deletions
diff --git a/plugingui/pixelbuffer.cc b/plugingui/pixelbuffer.cc
index fd02703..918298b 100644
--- a/plugingui/pixelbuffer.cc
+++ b/plugingui/pixelbuffer.cc
@@ -269,7 +269,9 @@ void PixelBufferAlpha::writeLine(std::size_t x, std::size_t y,
std::memcpy(offset, line, len * 4);
}
+
// SIMD: https://github.com/WojciechMula/toys/blob/master/blend_32bpp/blend_32bpp.c
+// Alpha blending: http://en.wikipedia.org/wiki/Alpha_compositing
void PixelBufferAlpha::blendLine(std::size_t x, std::size_t y,
const std::uint8_t* line, std::size_t len)
@@ -279,56 +281,70 @@ void PixelBufferAlpha::blendLine(std::size_t x, std::size_t y,
return; // out of bounds
}
+ int a, b;
std::uint8_t* target = &buf[PX(0)];
- for(std::size_t x = 0; x < len; ++x)
+ while(len)
{
- unsigned int a = line[3];
- unsigned int b = 255 - a;
+ if(line[3] == 0xff)
+ {
+ const std::uint8_t* end = line;
+ while(end[3] == 0xff && end < line + len * 4)
+ {
+ end += 4;
+ }
+ auto chunk_len = end - line;
+ memcpy(target, line, chunk_len);
+ line += chunk_len;
+ target += chunk_len;
+ len -= chunk_len / 4;
+ continue;
+ }
+ else if(line[3] == 0)
+ {
+ // Do nothing
+ }
+ else
+ {
+ a = line[3];
+ b = target[3] * (255 - a) / 255;
+
+ target[0] = (line[0] * a + target[0] * b) / (a + b);
+ target[1] = (line[1] * a + target[1] * b) / (a + b);
+ target[2] = (line[2] * a + target[2] * b) / (a + b);
+ target[3] = (int)target[3] + line[3] * (255 - target[3]) / 255;
+ }
- target[0] = (std::uint8_t)((line[0] * a + target[0] * b) / 255);
- target[1] = (std::uint8_t)((line[1] * a + target[1] * b) / 255);
- target[2] = (std::uint8_t)((line[2] * a + target[2] * b) / 255);
- target[3] = a * b / 255;
line += 4;
target += 4;
+ --len;
}
}
-
-// http://en.wikipedia.org/wiki/Alpha_compositing
-static inline void getAlpha(std::uint8_t _a, std::uint8_t _b,
- float &a, float &b)
-{
- a = _a / 255.0;
- b = _b / 255.0;
- b *= (1 - a);
-}
-
void PixelBufferAlpha::addPixel(std::size_t x, std::size_t y, const Colour& c)
{
- if(c.alpha() == 0)
+ const std::uint8_t* colour = c.data();
+
+ if(colour[3] == 0)
{
return;
}
- std::uint8_t* pixel = &buf[PX(0)];
+ int a, b;
+ std::uint8_t* target = &buf[PX(0)];
- if(c.alpha() < 255)
+ if(colour[3] == 0xff)
{
- float a, b;
- getAlpha(c.alpha(), buf[PX(3)], a, b);
-
- *pixel = (std::uint8_t)((c.red() * a + *pixel * b) / (a + b));
- ++pixel;
- *pixel = (std::uint8_t)((c.green() * a + *pixel * b) / (a + b));
- ++pixel;
- *pixel = (std::uint8_t)((c.blue() * a + *pixel * b) / (a + b));
- ++pixel;
- *pixel = (a + b) * 255;
+ memcpy(target, colour, 4);
}
else
{
- memcpy(pixel, c.data(), 4);
+ a = colour[3];
+ b = target[3] * (255 - a) / 255;
+
+ target[0] = (colour[0] * a + target[0] * b) / (a + b);
+ target[1] = (colour[1] * a + target[1] * b) / (a + b);
+ target[2] = (colour[2] * a + target[2] * b) / (a + b);
+ target[3] = (int)target[3] + colour[3] * (255 - target[3]) / 255;
}
}