diff options
| author | Bent Bisballe Nyeng <deva@aasimon.org> | 2020-02-29 16:12:26 +0100 | 
|---|---|---|
| committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2020-03-07 19:22:34 +0100 | 
| commit | a65278c7bc9c0dbca8a74db09fd0aebf1c26ef28 (patch) | |
| tree | f6137641afd154dca1c45480137e9b56afb1a7d6 /plugingui | |
| parent | 450e39c5b02ace3c50d116e4cba825ff695c8665 (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.cc | 29 | ||||
| -rw-r--r-- | plugingui/colour.h | 16 | ||||
| -rw-r--r-- | plugingui/drawable.h | 4 | ||||
| -rw-r--r-- | plugingui/font.cc | 8 | ||||
| -rw-r--r-- | plugingui/image.cc | 23 | ||||
| -rw-r--r-- | plugingui/image.h | 5 | ||||
| -rw-r--r-- | plugingui/painter.cc | 153 | ||||
| -rw-r--r-- | plugingui/pixelbuffer.cc | 248 | ||||
| -rw-r--r-- | plugingui/pixelbuffer.h | 46 | ||||
| -rw-r--r-- | plugingui/texture.cc | 10 | ||||
| -rw-r--r-- | plugingui/texture.h | 2 | ||||
| -rw-r--r-- | plugingui/texturedbox.cc | 11 | ||||
| -rw-r--r-- | plugingui/texturedbox.h | 2 | ||||
| -rw-r--r-- | 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 <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);  		}  	} | 
