/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * pixelbuffer.cc * * Thu Nov 10 09:00:38 CET 2011 * Copyright 2011 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of DrumGizmo. * * DrumGizmo is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * DrumGizmo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "pixelbuffer.h" #include #include #include namespace GUI { PixelBuffer::PixelBuffer(std::size_t width, std::size_t height) : buf(nullptr) { realloc(width, height); } PixelBuffer::~PixelBuffer() { free(buf); } void PixelBuffer::realloc(std::size_t width, std::size_t height) { free(buf); 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, const Colour& c) { if(c.alpha() == 0) { return; } if(c.alpha() < 255) { unsigned int a = c.alpha(); unsigned int b = 255 - a; 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 { 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) , x(0) , y(0) { realloc(width, height); } PixelBufferAlpha::~PixelBufferAlpha() { if(managed) { free(buf); } } void PixelBufferAlpha::realloc(std::size_t width, std::size_t height) { free(buf); 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, // 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) { std::uint8_t* pixel = &buf[PX(0)]; *pixel = c.red(); ++pixel; *pixel = c.green(); ++pixel; *pixel = c.blue(); ++pixel; *pixel = c.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(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, std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha) { //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); *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 { *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(), c.green(), c.blue(), c.alpha()); } void PixelBufferAlpha::pixel(std::size_t x, std::size_t y, 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::