From d0d42b8aa28b05d680573ca5ad72e7e19ec88691 Mon Sep 17 00:00:00 2001 From: Aaron <10217842+byteduck@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:14:17 -0800 Subject: [PATCH 1/4] Pond: Allow windows to blur what's behind them Work in progress. Adds a new window hint to blur contents behind a window. It currently uses an approximated gaussian blur by applying 3 passes of a box blur. There are currently a few visual artifacts (such as when moving the cursor around a blurred window) due to the way partial redraws work. --- libraries/libgraphics/Color.h | 9 + libraries/libgraphics/Framebuffer.cpp | 78 +++ libraries/libgraphics/Framebuffer.cpp.orig | 471 ++++++++++++++++++ libraries/libgraphics/Framebuffer.h | 7 + .../libgraphics/Framebuffer_BACKUP_140866.h | 206 ++++++++ .../libgraphics/Framebuffer_BASE_140866.h | 188 +++++++ .../libgraphics/Framebuffer_LOCAL_140866.h | 198 ++++++++ .../libgraphics/Framebuffer_REMOTE_140866.h | 195 ++++++++ libraries/libpond/Window.cpp | 4 + libraries/libpond/Window.h | 4 + libraries/libui/Window.cpp | 7 +- services/pond/Display.cpp | 7 +- services/pond/Window.cpp | 12 + services/pond/Window.h | 13 +- 14 files changed, 1393 insertions(+), 6 deletions(-) create mode 100644 libraries/libgraphics/Framebuffer.cpp.orig create mode 100644 libraries/libgraphics/Framebuffer_BACKUP_140866.h create mode 100644 libraries/libgraphics/Framebuffer_BASE_140866.h create mode 100644 libraries/libgraphics/Framebuffer_LOCAL_140866.h create mode 100644 libraries/libgraphics/Framebuffer_REMOTE_140866.h diff --git a/libraries/libgraphics/Color.h b/libraries/libgraphics/Color.h index 35142ad7..f83aaca0 100644 --- a/libraries/libgraphics/Color.h +++ b/libraries/libgraphics/Color.h @@ -46,6 +46,15 @@ typedef union Color { return *this = *this * other; } + [[nodiscard]] constexpr Color operator+(Color other) const { + return { + (uint8_t)(r + other.r), + (uint8_t)(g + other.g), + (uint8_t)(b + other.b), + (uint8_t)(a + other.a) + }; + } + [[nodiscard]] constexpr Color lightened(float amount = 0.25) const { return darkened(1 + amount); } diff --git a/libraries/libgraphics/Framebuffer.cpp b/libraries/libgraphics/Framebuffer.cpp index ea3631db..60ac3a33 100644 --- a/libraries/libgraphics/Framebuffer.cpp +++ b/libraries/libgraphics/Framebuffer.cpp @@ -126,6 +126,7 @@ void Framebuffer::copy_blitting(const Framebuffer& other, Rect other_area, const } } +<<<<<<< HEAD void Framebuffer::copy_blitting_flipped(const Framebuffer& other, Rect other_area, const Point& pos, bool flip_h, bool flip_v) const { //Make sure self_area is in bounds of the framebuffer Rect self_area = {pos.x, pos.y, other_area.width, other_area.height}; @@ -149,6 +150,83 @@ void Framebuffer::copy_blitting_flipped(const Framebuffer& other, Rect other_are this_val = this_val.blended(other_val); } } +======= +inline int math_mod(int a, int b) { + return (a % b + b) % b; +} + +void Framebuffer::blur(Gfx::Rect area, int radius) const { + int window_size = radius * 2 + 1; + + auto do_pass = [&]() { ; + // First, apply blur horizontally. + for(int y = area.y; y < area.y + area.height; y++) { + int window[3] = {0, 0, 0}; + Color window_preblur[window_size]; + int preblur_index = 0; + + // Populate window + for(int i = -radius; i <= radius; i++) { + auto color = data[(std::min(std::max(area.x + i, 0), width - 1)) + y * width]; + window_preblur[i + radius] = color; + window[0] += color.r; + window[1] += color.g; + window[2] += color.b; + } + + for(int x = area.x; x < area.x + area.width; x++) { + data[x + y * width] = { + (uint8_t) (window[0] / window_size), + (uint8_t) (window[1] / window_size), + (uint8_t) (window[2] / window_size), + }; + auto window_add = data[(std::min(x + 5, width - 1)) + y * width]; + auto window_sub = window_preblur[preblur_index]; + preblur_index++; + preblur_index %= window_size; + window_preblur[((preblur_index - 1) % window_size + window_size) % window_size] = window_add; + window[0] += (int) window_add.r - (int) window_sub.r; + window[1] += (int) window_add.g - (int) window_sub.g; + window[2] += (int) window_add.b - (int) window_sub.b; + } + } + + // Then, apply blur vertically. + for(int x = area.x; x < area.x + area.width; x++) { + int window[3] = {0, 0, 0}; + Color window_preblur[window_size]; + int preblur_index = 0; + + // Populate window + for(int i = -radius; i <= radius; i++) { + auto color = data[(x + std::min(std::max(area.y + i, 0), height - 1)) * width]; + window_preblur[i + radius] = color; + window[0] += color.r; + window[1] += color.g; + window[2] += color.b; + } + + for(int y = area.y; y < area.y + area.height; y++) { + data[x + y * width] = { + (uint8_t) (window[0] / window_size), + (uint8_t) (window[1] / window_size), + (uint8_t) (window[2] / window_size), + }; + auto window_add = data[x + (std::min(y + 5, height - 1)) * width]; + auto window_sub = window_preblur[preblur_index]; + preblur_index++; + preblur_index %= window_size; + window_preblur[((preblur_index - 1) % window_size + window_size) % window_size] = window_add; + window[0] += (int) window_add.r - (int) window_sub.r; + window[1] += (int) window_add.g - (int) window_sub.g; + window[2] += (int) window_add.b - (int) window_sub.b; + } + } + }; + + for(int i = 0; i < 3; i++) + do_pass(); +>>>>>>> fb5c657 (Pond: Allow windows to blur what's behind them) } void Framebuffer::copy_tiled(const Framebuffer& other, Rect other_area, const Point& pos) const { diff --git a/libraries/libgraphics/Framebuffer.cpp.orig b/libraries/libgraphics/Framebuffer.cpp.orig new file mode 100644 index 00000000..60ac3a33 --- /dev/null +++ b/libraries/libgraphics/Framebuffer.cpp.orig @@ -0,0 +1,471 @@ +/* + This file is part of duckOS. + + duckOS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + duckOS 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with duckOS. If not, see . + + Copyright (c) Byteduck 2016-2021. All rights reserved. +*/ + +#include "Framebuffer.h" +#include "Graphics.h" +#include "Font.h" +#include "Memory.h" +#include "Geometry.h" + +using namespace Gfx; + +Framebuffer::Framebuffer(): data(nullptr), width(0), height(0) {} +Framebuffer::Framebuffer(Color* buffer, int width, int height): data(buffer), width(width), height(height) {} +Framebuffer::Framebuffer(int width, int height): data(new Color[width * height]), width(width), height(height), should_free(true) {} +Framebuffer::Framebuffer(Framebuffer&& other) noexcept: data(other.data), width(other.width), height(other.height), should_free(other.should_free) { + other.data = nullptr; +} +Framebuffer::Framebuffer(Framebuffer& other) noexcept: data(other.data), width(other.width), height(other.height), should_free(false) {} + +Framebuffer::~Framebuffer() noexcept { + if(should_free) + free(); +} + +Framebuffer& Framebuffer::operator=(const Framebuffer& other) { + if(should_free) + free(); + width = other.width; + height = other.height; + data = other.data; + should_free = false; + return *this; +} + +Framebuffer& Framebuffer::operator=(Framebuffer&& other) noexcept { + if(should_free) + free(); + width = other.width; + height = other.height; + data = other.data; + should_free = other.should_free; + other.data = nullptr; + return *this; +} + +void Framebuffer::free() { + if(data) { + delete data; + data = nullptr; + } +} + +void Framebuffer::copy(const Framebuffer& other, Rect other_area, const Point& pos) const { + //Make sure self_area is in bounds of the framebuffer + Rect self_area = {pos.x, pos.y, other_area.width, other_area.height}; + self_area = self_area.overlapping_area({0, 0, width, height}); + if(self_area.empty()) + return; + + //Update other area with the changes made to self_area + other_area.x += self_area.x - pos.x; + other_area.y += self_area.y - pos.y; + other_area.width = self_area.width; + other_area.height = self_area.height; + + for(int y = 0; y < self_area.height; y++) { + memcpy_uint32((uint32_t*) &data[self_area.x + (self_area.y + y) * width], (uint32_t*) &other.data[other_area.x + (other_area.y + y) * other.width], self_area.width); + } +} + +void Framebuffer::copy_noalpha(const Framebuffer& other, Rect other_area, const Point& pos) const { + //Make sure self_area is in bounds of the framebuffer + Rect self_area = {pos.x, pos.y, other_area.width, other_area.height}; + self_area = self_area.overlapping_area({0, 0, width, height}); + if(self_area.empty()) + return; + + //Update other area with the changes made to self_area + other_area.x += self_area.x - pos.x; + other_area.y += self_area.y - pos.y; + other_area.width = self_area.width; + other_area.height = self_area.height; + + for(int y = 0; y < self_area.height; y++) { + for(int x = 0; x < self_area.width; x++) { + data[(self_area.x + x) + (self_area.y + y) * width] = RGBA(0, 0, 0, 255) | other.data[(other_area.x + x) + (other_area.y + y) * other.width]; + } + } +} + +void Framebuffer::copy_blitting(const Framebuffer& other, Rect other_area, const Point& pos) const { + //Make sure self_area is in bounds of the framebuffer + Rect self_area = {pos.x, pos.y, other_area.width, other_area.height}; + self_area = self_area.overlapping_area({0, 0, width, height}); + if(self_area.empty()) + return; + + //Update other area with the changes made to self_area + other_area.x += self_area.x - pos.x; + other_area.y += self_area.y - pos.y; + other_area.width = self_area.width; + other_area.height = self_area.height; + + for(int y = 0; y < self_area.height; y++) { + for(int x = 0; x < self_area.width; x++) { + auto& this_val = data[(self_area.x + x) + (self_area.y + y) * width]; + auto& other_val = other.data[(other_area.x + x) + (other_area.y + y) * other.width]; + this_val = this_val.blended(other_val); + } + } +} + +<<<<<<< HEAD +void Framebuffer::copy_blitting_flipped(const Framebuffer& other, Rect other_area, const Point& pos, bool flip_h, bool flip_v) const { + //Make sure self_area is in bounds of the framebuffer + Rect self_area = {pos.x, pos.y, other_area.width, other_area.height}; + self_area = self_area.overlapping_area({0, 0, width, height}); + if(self_area.empty()) + return; + + //Update other area with the changes made to self_area + other_area.x += self_area.x - pos.x; + other_area.y += self_area.y - pos.y; + other_area.width = self_area.width; + other_area.height = self_area.height; + + for(int y = 0; y < self_area.height; y++) { + for(int x = 0; x < self_area.width; x++) { + auto& this_val = data[(self_area.x + x) + (self_area.y + y) * width]; + auto& other_val = other.data[ + other_area.x + (flip_h ? other_area.width - x - 1 : x) + + (other_area.y + (flip_v ? other_area.height - y - 1 : y)) * other.width + ]; + this_val = this_val.blended(other_val); + } + } +======= +inline int math_mod(int a, int b) { + return (a % b + b) % b; +} + +void Framebuffer::blur(Gfx::Rect area, int radius) const { + int window_size = radius * 2 + 1; + + auto do_pass = [&]() { ; + // First, apply blur horizontally. + for(int y = area.y; y < area.y + area.height; y++) { + int window[3] = {0, 0, 0}; + Color window_preblur[window_size]; + int preblur_index = 0; + + // Populate window + for(int i = -radius; i <= radius; i++) { + auto color = data[(std::min(std::max(area.x + i, 0), width - 1)) + y * width]; + window_preblur[i + radius] = color; + window[0] += color.r; + window[1] += color.g; + window[2] += color.b; + } + + for(int x = area.x; x < area.x + area.width; x++) { + data[x + y * width] = { + (uint8_t) (window[0] / window_size), + (uint8_t) (window[1] / window_size), + (uint8_t) (window[2] / window_size), + }; + auto window_add = data[(std::min(x + 5, width - 1)) + y * width]; + auto window_sub = window_preblur[preblur_index]; + preblur_index++; + preblur_index %= window_size; + window_preblur[((preblur_index - 1) % window_size + window_size) % window_size] = window_add; + window[0] += (int) window_add.r - (int) window_sub.r; + window[1] += (int) window_add.g - (int) window_sub.g; + window[2] += (int) window_add.b - (int) window_sub.b; + } + } + + // Then, apply blur vertically. + for(int x = area.x; x < area.x + area.width; x++) { + int window[3] = {0, 0, 0}; + Color window_preblur[window_size]; + int preblur_index = 0; + + // Populate window + for(int i = -radius; i <= radius; i++) { + auto color = data[(x + std::min(std::max(area.y + i, 0), height - 1)) * width]; + window_preblur[i + radius] = color; + window[0] += color.r; + window[1] += color.g; + window[2] += color.b; + } + + for(int y = area.y; y < area.y + area.height; y++) { + data[x + y * width] = { + (uint8_t) (window[0] / window_size), + (uint8_t) (window[1] / window_size), + (uint8_t) (window[2] / window_size), + }; + auto window_add = data[x + (std::min(y + 5, height - 1)) * width]; + auto window_sub = window_preblur[preblur_index]; + preblur_index++; + preblur_index %= window_size; + window_preblur[((preblur_index - 1) % window_size + window_size) % window_size] = window_add; + window[0] += (int) window_add.r - (int) window_sub.r; + window[1] += (int) window_add.g - (int) window_sub.g; + window[2] += (int) window_add.b - (int) window_sub.b; + } + } + }; + + for(int i = 0; i < 3; i++) + do_pass(); +>>>>>>> fb5c657 (Pond: Allow windows to blur what's behind them) +} + +void Framebuffer::copy_tiled(const Framebuffer& other, Rect other_area, const Point& pos) const { + //Make sure self_area is in bounds of the framebuffer + Rect self_area = {pos.x, pos.y, other_area.width, other_area.height}; + self_area = self_area.overlapping_area({0, 0, width, height}); + if(self_area.empty()) + return; + + //Update other area with the changes made to self_area + other_area.x += self_area.x - pos.x; + other_area.y += self_area.y - pos.y; + other_area.width = self_area.width; + other_area.height = self_area.height; + + for(int y = 0; y < self_area.height; y++) { + for(int x = 0; x < self_area.width; x++) { + data[(self_area.x + x) + (self_area.y + y) * width] = other.data[(((other_area.x + x) % other.width) + ((other_area.y + y) % other.height) * other.width) % (other.width * other.height)]; + } + } +} + +void Framebuffer::draw_image(const Framebuffer& other, Rect other_area, const Point& pos) const { + //Make sure self_area is in bounds of the framebuffer + Rect self_area = {pos.x, pos.y, other_area.width, other_area.height}; + self_area = self_area.overlapping_area({0, 0, width, height}); + if(self_area.empty()) + return; + + //Update other area with the changes made to self_area + other_area.x += self_area.x - pos.x; + other_area.y += self_area.y - pos.y; + other_area.width = self_area.width; + other_area.height = self_area.height; + + for(int y = 0; y < self_area.height; y++) { + for(int x = 0; x < self_area.width; x++) { + auto& this_val = data[(self_area.x + x) + (self_area.y + y) * width]; + auto& other_val = other.data[(other_area.x + x) + (other_area.y + y) * other.width]; + this_val = this_val.blended(other_val); + } + } +} + +void Framebuffer::draw_image(const Framebuffer& other, const Point& pos) const { + draw_image(other, {0, 0, other.width, other.height}, pos); +} + +void Framebuffer::draw_image_scaled(const Framebuffer& other, const Rect& rect) const { + if(rect.width == other.width && rect.height == other.height) { + draw_image(other, rect.position()); + return; + } + + double scale_x = (double) rect.width / (double) other.width; + double scale_y = (double) rect.height / (double) other.height; + + //Make sure self_area is in bounds of the framebuffer + Rect self_area = rect; + self_area = self_area.overlapping_area({0, 0, width, height}); + if(self_area.empty()) + return; + + //Update other area with the changes made to self_area + DoubleRect other_area = {0, 0, (float) other.width, (float) other.height}; + other_area.x += (self_area.x - rect.x) / scale_x; + other_area.y += (self_area.y - rect.y) / scale_y; + other_area.width = self_area.width / scale_x; + other_area.height = self_area.height / scale_y; + + for(int y = 0; y < self_area.height; y++) { + for(int x = 0; x < self_area.width; x++) { + auto& this_val = data[(self_area.x + x) + (self_area.y + y) * width]; + auto& other_val = other.data[(int) (other_area.x + x / scale_x) + (int) (other_area.y + y / scale_y) * other.width]; + this_val = this_val.blended(other_val); + } + } +} + +void Framebuffer::fill(Rect area, Color color) const { + //Make sure area is in the bounds of the framebuffer + area = area.overlapping_area({0, 0, width, height}); + if(area.empty()) + return; + + for(int y = 0; y < area.height; y++) { + for(int x = 0; x < area.width; x++) { + data[x + area.x + (area.y + y) * width] = color; + } + } +} + +void Framebuffer::fill_blitting(Rect area, Color color) const { + //Make sure area is in the bounds of the framebuffer + area = area.overlapping_area({0, 0, width, height}); + if(area.empty()) + return; + + unsigned int alpha = COLOR_A(color) + 1; + unsigned int inv_alpha = 256 - COLOR_A(color); + unsigned int premultiplied_r = alpha * COLOR_R(color); + unsigned int premultiplied_g = alpha * COLOR_G(color); + unsigned int premultiplied_b = alpha * COLOR_B(color); + unsigned int premultiplied_a = alpha * COLOR_A(color); + + for(int y = 0; y < area.height; y++) { + for(int x = 0; x < area.width; x++) { + auto this_val = data[(area.x + x) + (area.y + y) * width]; + data[(area.x + x) + (area.y + y) * width] = RGBA( + (uint8_t)((premultiplied_r + inv_alpha * COLOR_R(this_val)) >> 8), + (uint8_t)((premultiplied_g + inv_alpha * COLOR_G(this_val)) >> 8), + (uint8_t)((premultiplied_b + inv_alpha * COLOR_B(this_val)) >> 8), + (uint8_t)((premultiplied_a + inv_alpha * COLOR_A(this_val)) >> 8)); + } + } +} + +void Framebuffer::fill_gradient_h(Rect area, Color color_a, Color color_b) const { + if(color_a == color_b) + fill(area, color_a); + for(int x = 0; x < area.width; x++) + fill({area.x + x, area.y, 1, area.height}, color_a.mixed(color_b, (float) x / area.width)); +} + +void Framebuffer::fill_gradient_v(Rect area, Color color_a, Color color_b) const { + if(color_a == color_b) + fill(area, color_a); + for(int y = 0; y < area.height; y++) + fill({area.x, area.y + y, area.width, 1}, color_a.mixed(color_b, (float) y / area.height)); +} + +void Framebuffer::outline(Rect area, Color color) const { + fill({area.x + 1, area.y, area.width - 2, 1}, color); + fill({area.x + 1, area.y + area.height - 1, area.width - 2, 1}, color); + fill({area.x, area.y, 1, area.height}, color); + fill({area.x + area.width - 1, area.y, 1, area.height}, color); +} + +void Framebuffer::outline_blitting(Rect area, Color color) const { + fill_blitting({area.x + 1, area.y, area.width - 2, 1}, color); + fill_blitting({area.x + 1, area.y + area.height - 1, area.width - 2, 1}, color); + fill_blitting({area.x, area.y, 1, area.height}, color); + fill_blitting({area.x + area.width - 1, area.y, 1, area.height}, color); +} + +void Framebuffer::draw_text(const char* str, const Point& pos, Font* font, Color color) const { + Point current_pos = pos; + while(*str) { + current_pos = draw_glyph(font, *str, current_pos, color); + str++; + } +} + +Point Framebuffer::draw_glyph(Font* font, uint32_t codepoint, const Point& glyph_pos, Color color) const { + auto* glyph = font->glyph(codepoint); + int y_offset = (font->bounding_box().base_y - glyph->base_y) + (font->size() - glyph->height); + int x_offset = glyph->base_x - font->bounding_box().base_x; + Point pos = {glyph_pos.x + x_offset, glyph_pos.y + y_offset}; + Rect glyph_area = {0, 0, glyph->width, glyph->height}; + + //Calculate the color multipliers + double r_mult = COLOR_R(color) / 255.0; + double g_mult = COLOR_G(color) / 255.0; + double b_mult = COLOR_B(color) / 255.0; + double alpha_mult = COLOR_A(color) / 255.0; + + //Make sure self_area is in bounds of the framebuffer + Rect self_area = {pos.x, pos.y, glyph_area.width, glyph_area.height}; + self_area = self_area.overlapping_area({0, 0, width, height}); + if(self_area.empty()) + return glyph_pos + Point {glyph->next_offset.x, glyph->next_offset.y}; + + //Update glyph_area with the changes made to self_area + glyph_area.x += self_area.x - pos.x; + glyph_area.y += self_area.y - pos.y; + glyph_area.width = self_area.width; + glyph_area.height = self_area.height; + + for(int y = 0; y < self_area.height; y++) { + for(int x = 0; x < self_area.width; x++) { + auto& this_val = data[(self_area.x + x) + (self_area.y + y) * width]; + auto& other_val = glyph->bitmap[(glyph_area.x + x) + (glyph_area.y + y) * glyph->width]; + double alpha = (COLOR_A(other_val) / 255.00) * alpha_mult; + if(alpha == 0) + continue; + double oneminusalpha = 1.00 - alpha; + this_val = RGB( + (uint8_t) (COLOR_R(this_val) * oneminusalpha + COLOR_R(other_val) * alpha * r_mult), + (uint8_t) (COLOR_G(this_val) * oneminusalpha + COLOR_G(other_val) * alpha * g_mult), + (uint8_t) (COLOR_B(this_val) * oneminusalpha + COLOR_B(other_val) * alpha * b_mult)); + } + } + + return glyph_pos + Point {glyph->next_offset.x, glyph->next_offset.y}; +} + +void Framebuffer::multiply(Color color) { + for(int y = 0; y < height; y++) { + for(int x = 0; x < width; x++) { + data[x + y * width] *= color; + } + } +} + +Color* Framebuffer::at(const Point& position) const { + if(position.x < 0 || position.y < 0 || position.y >= height || position.x >= width) + return NULL; + + return &data[position.x + position.y * width]; +} + +struct FramebufferSerialization { + int width; + int height; + uint32_t data[]; +}; + +size_t Framebuffer::serialized_size() const { + return sizeof(FramebufferSerialization) + width * height * sizeof(uint32_t); +} + +void Framebuffer::serialize(uint8_t*& buf) const { + auto* serialization = (FramebufferSerialization*) buf; + serialization->width = data ? width : 0; + serialization->height = data ? height : 0; + if(data && width && height) + memcpy_uint32(serialization->data, (uint32_t*) data, width * height); + buf += serialized_size(); +} + +void Framebuffer::deserialize(const uint8_t*& buf) { + delete data; + auto* serialization = (FramebufferSerialization*) buf; + width = serialization->width; + height = serialization->height; + if(width && height) { + data = (Color*) malloc(sizeof(Color) * width * height); + memcpy_uint32((uint32_t*) data, serialization->data, width * height); + } + should_free = true; + buf += serialized_size(); +} diff --git a/libraries/libgraphics/Framebuffer.h b/libraries/libgraphics/Framebuffer.h index ab5b52dd..8438b680 100644 --- a/libraries/libgraphics/Framebuffer.h +++ b/libraries/libgraphics/Framebuffer.h @@ -86,6 +86,13 @@ namespace Gfx { */ void copy_blitting_flipped(const Framebuffer& other, Rect other_area, const Point& pos, bool flip_h, bool flip_v) const; + /* + * Blurs an area of this framebuffer with an approximated gaussian blur. + * @param area The area to blur. + * @param radius The blur radius. + */ + void blur(Rect area, int radius = 4) const; + /** * Identical to ::copy(), but will tile the Image. */ diff --git a/libraries/libgraphics/Framebuffer_BACKUP_140866.h b/libraries/libgraphics/Framebuffer_BACKUP_140866.h new file mode 100644 index 00000000..edcf2e7b --- /dev/null +++ b/libraries/libgraphics/Framebuffer_BACKUP_140866.h @@ -0,0 +1,206 @@ +/* + This file is part of duckOS. + + duckOS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + duckOS 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with duckOS. If not, see . + + Copyright (c) Byteduck 2016-2021. All rights reserved. +*/ + +#pragma once + +#include +#include "Geometry.h" +#include "Color.h" +#include + +#define IMGSIZE(width, height) (sizeof(uint32_t) * (width) * (height)) +#define IMGPIXEL(img, x, y) (img).data[(x) + (y) * (img).width] +#define IMGPTRPIXEL(img, x, y) (img)->data[(x) + (y) * (img)->width] + +namespace Gfx { + class Font; + class Framebuffer: public Duck::Serializable { + public: + Framebuffer(); + Framebuffer(Color* buffer, int width, int height); + Framebuffer(int width, int height); + Framebuffer(Framebuffer&& other) noexcept; + Framebuffer(Framebuffer& other) noexcept; + ~Framebuffer() noexcept; + + Framebuffer& operator=(const Framebuffer& other); + Framebuffer& operator=(Framebuffer&& other) noexcept; + + Color* data = nullptr; + int width = 0; + int height = 0; + bool should_free = false; + + /** + * Frees the data associated with the Image. + */ + void free(); + + /** + * Copies a part of another Image to this one. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Copies a part of another Image to this one, ignoring alpha. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy_noalpha(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Copies a part of another Image to this one, with alpha blending. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy_blitting(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** +<<<<<<< HEAD + * Copies a part of another Image to this one, with alpha blending, flipped horizontally. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + * @param flip_h Whether to flip vertically. + * @param flip_v Whether to flip horizontally. + */ + void copy_blitting_flipped(const Framebuffer& other, Rect other_area, const Point& pos, bool flip_h, bool flip_v) const; +======= + * Blurs an area of this framebuffer with an approximated gaussian blur. + * @param area The area to blur. + * @param radius The blur radius. + */ + void blur(Rect area, int radius = 4) const; +>>>>>>> fb5c657 (Pond: Allow windows to blur what's behind them) + + /** + * Identical to ::copy(), but will tile the Image. + */ + void copy_tiled(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending. + * @param other The Image to draw. + * @param other_area The area of the other Image to draw. + * @param pos The position on this Image to draw on. + */ + void draw_image(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending. + * @param other The Image to draw. + * @param pos The position on this Image to draw on. + */ + void draw_image(const Framebuffer& other, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending, scaled to + * fit inside of the specified rect. + * @param other The Image to draw. + * @param size The rect on this Image to scale the image to and draw on. + */ + void draw_image_scaled(const Framebuffer& other, const Rect& rect) const; + + /** + * Fills an area of the Image with a color. + * @param area The area to fill. + * @param color The color to fill the area with. + */ + void fill(Rect area, Color color) const; + + /** + * Fills an area of the Image with a color, calculating transparency. + * @param area The area to fill. + * @param color The color to fill the area with. + */ + void fill_blitting(Rect area, Color color) const; + + /** + * Fills an area of the Image with a horizontal gradient (left to right). + * @param area The area to fill. + * @param color_a The start color. + * @param color_b The end color. + */ + void fill_gradient_h(Rect area, Color color_a, Color color_b) const; + + /** + * Fills an area of the Image with a vertical gradient (top to bottom). + * @param area The area to fill. + * @param color_a The start color. + * @param color_b The end color. + */ + void fill_gradient_v(Rect area, Color color_a, Color color_b) const; + + /** + * Draws the outline of an area on the Image. + * @param area The rect of the area to outline. + * @param color The color to draw the outline in. + */ + void outline(Rect area, Color color) const; + + /** + * Draws the outline of an area on the Image, calculating transparency. + * @param area The rect of the area to outline. + * @param color The color to draw the outline in. + */ + void outline_blitting(Rect area, Color color) const; + + /** + * Draws text on the Image with a certain color. + * @param str The string to draw. + * @param pos The top-left position of where to draw. + * @param font The font to use. + * @param color The color to draw in. + */ + void draw_text(const char* str, const Point& pos, Font* font, Color color) const; + + /** + * Draws a glyph on the Image with a certain color. + * @param font The font to use. + * @param codepoint The codepoint of the character. + * @param pos The position to draw the glyph at. + * @param color The color to draw the glyph in. + * @return The position where the next character should be drawn. + */ + Point draw_glyph(Font* font, uint32_t codepoint, const Point& pos, Color color) const; + + /** + * Multiplies the image with a certain color. + * @param color The color to multiply by. + */ + void multiply(Color color); + + /** + * Returns a pointer to the Image buffer at a certain position. Returns NULL if outside the constraints. + */ + Color* at(const Point& position) const; + + /// Serializable + size_t serialized_size() const override; + void serialize(uint8_t*& buf) const override; + void deserialize(const uint8_t*& buf) override; + }; +} + + diff --git a/libraries/libgraphics/Framebuffer_BASE_140866.h b/libraries/libgraphics/Framebuffer_BASE_140866.h new file mode 100644 index 00000000..405004bd --- /dev/null +++ b/libraries/libgraphics/Framebuffer_BASE_140866.h @@ -0,0 +1,188 @@ +/* + This file is part of duckOS. + + duckOS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + duckOS 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with duckOS. If not, see . + + Copyright (c) Byteduck 2016-2021. All rights reserved. +*/ + +#pragma once + +#include +#include "Geometry.h" +#include "Color.h" +#include + +#define IMGSIZE(width, height) (sizeof(uint32_t) * (width) * (height)) +#define IMGPIXEL(img, x, y) (img).data[(x) + (y) * (img).width] +#define IMGPTRPIXEL(img, x, y) (img)->data[(x) + (y) * (img)->width] + +namespace Gfx { + class Font; + class Framebuffer: public Duck::Serializable { + public: + Framebuffer(); + Framebuffer(Color* buffer, int width, int height); + Framebuffer(int width, int height); + Framebuffer(Framebuffer&& other) noexcept; + Framebuffer(Framebuffer& other) noexcept; + ~Framebuffer() noexcept; + + Framebuffer& operator=(const Framebuffer& other); + Framebuffer& operator=(Framebuffer&& other) noexcept; + + Color* data = nullptr; + int width = 0; + int height = 0; + bool should_free = false; + + /** + * Frees the data associated with the Image. + */ + void free(); + + /** + * Copies a part of another Image to this one. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Copies a part of another Image to this one, ignoring alpha. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy_noalpha(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Copies a part of another Image to this one, with alpha blending. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy_blitting(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Identical to ::copy(), but will tile the Image. + */ + void copy_tiled(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending. + * @param other The Image to draw. + * @param other_area The area of the other Image to draw. + * @param pos The position on this Image to draw on. + */ + void draw_image(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending. + * @param other The Image to draw. + * @param pos The position on this Image to draw on. + */ + void draw_image(const Framebuffer& other, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending, scaled to + * fit inside of the specified rect. + * @param other The Image to draw. + * @param size The rect on this Image to scale the image to and draw on. + */ + void draw_image_scaled(const Framebuffer& other, const Rect& rect) const; + + /** + * Fills an area of the Image with a color. + * @param area The area to fill. + * @param color The color to fill the area with. + */ + void fill(Rect area, Color color) const; + + /** + * Fills an area of the Image with a color, calculating transparency. + * @param area The area to fill. + * @param color The color to fill the area with. + */ + void fill_blitting(Rect area, Color color) const; + + /** + * Fills an area of the Image with a horizontal gradient (left to right). + * @param area The area to fill. + * @param color_a The start color. + * @param color_b The end color. + */ + void fill_gradient_h(Rect area, Color color_a, Color color_b) const; + + /** + * Fills an area of the Image with a vertical gradient (top to bottom). + * @param area The area to fill. + * @param color_a The start color. + * @param color_b The end color. + */ + void fill_gradient_v(Rect area, Color color_a, Color color_b) const; + + /** + * Draws the outline of an area on the Image. + * @param area The rect of the area to outline. + * @param color The color to draw the outline in. + */ + void outline(Rect area, Color color) const; + + /** + * Draws the outline of an area on the Image, calculating transparency. + * @param area The rect of the area to outline. + * @param color The color to draw the outline in. + */ + void outline_blitting(Rect area, Color color) const; + + /** + * Draws text on the Image with a certain color. + * @param str The string to draw. + * @param pos The top-left position of where to draw. + * @param font The font to use. + * @param color The color to draw in. + */ + void draw_text(const char* str, const Point& pos, Font* font, Color color) const; + + /** + * Draws a glyph on the Image with a certain color. + * @param font The font to use. + * @param codepoint The codepoint of the character. + * @param pos The position to draw the glyph at. + * @param color The color to draw the glyph in. + * @return The position where the next character should be drawn. + */ + Point draw_glyph(Font* font, uint32_t codepoint, const Point& pos, Color color) const; + + /** + * Multiplies the image with a certain color. + * @param color The color to multiply by. + */ + void multiply(Color color); + + /** + * Returns a pointer to the Image buffer at a certain position. Returns NULL if outside the constraints. + */ + Color* at(const Point& position) const; + + /// Serializable + size_t serialized_size() const override; + void serialize(uint8_t*& buf) const override; + void deserialize(const uint8_t*& buf) override; + }; +} + + diff --git a/libraries/libgraphics/Framebuffer_LOCAL_140866.h b/libraries/libgraphics/Framebuffer_LOCAL_140866.h new file mode 100644 index 00000000..ab5b52dd --- /dev/null +++ b/libraries/libgraphics/Framebuffer_LOCAL_140866.h @@ -0,0 +1,198 @@ +/* + This file is part of duckOS. + + duckOS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + duckOS 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with duckOS. If not, see . + + Copyright (c) Byteduck 2016-2021. All rights reserved. +*/ + +#pragma once + +#include +#include "Geometry.h" +#include "Color.h" +#include + +#define IMGSIZE(width, height) (sizeof(uint32_t) * (width) * (height)) +#define IMGPIXEL(img, x, y) (img).data[(x) + (y) * (img).width] +#define IMGPTRPIXEL(img, x, y) (img)->data[(x) + (y) * (img)->width] + +namespace Gfx { + class Font; + class Framebuffer: public Duck::Serializable { + public: + Framebuffer(); + Framebuffer(Color* buffer, int width, int height); + Framebuffer(int width, int height); + Framebuffer(Framebuffer&& other) noexcept; + Framebuffer(Framebuffer& other) noexcept; + ~Framebuffer() noexcept; + + Framebuffer& operator=(const Framebuffer& other); + Framebuffer& operator=(Framebuffer&& other) noexcept; + + Color* data = nullptr; + int width = 0; + int height = 0; + bool should_free = false; + + /** + * Frees the data associated with the Image. + */ + void free(); + + /** + * Copies a part of another Image to this one. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Copies a part of another Image to this one, ignoring alpha. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy_noalpha(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Copies a part of another Image to this one, with alpha blending. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy_blitting(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Copies a part of another Image to this one, with alpha blending, flipped horizontally. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + * @param flip_h Whether to flip vertically. + * @param flip_v Whether to flip horizontally. + */ + void copy_blitting_flipped(const Framebuffer& other, Rect other_area, const Point& pos, bool flip_h, bool flip_v) const; + + /** + * Identical to ::copy(), but will tile the Image. + */ + void copy_tiled(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending. + * @param other The Image to draw. + * @param other_area The area of the other Image to draw. + * @param pos The position on this Image to draw on. + */ + void draw_image(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending. + * @param other The Image to draw. + * @param pos The position on this Image to draw on. + */ + void draw_image(const Framebuffer& other, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending, scaled to + * fit inside of the specified rect. + * @param other The Image to draw. + * @param size The rect on this Image to scale the image to and draw on. + */ + void draw_image_scaled(const Framebuffer& other, const Rect& rect) const; + + /** + * Fills an area of the Image with a color. + * @param area The area to fill. + * @param color The color to fill the area with. + */ + void fill(Rect area, Color color) const; + + /** + * Fills an area of the Image with a color, calculating transparency. + * @param area The area to fill. + * @param color The color to fill the area with. + */ + void fill_blitting(Rect area, Color color) const; + + /** + * Fills an area of the Image with a horizontal gradient (left to right). + * @param area The area to fill. + * @param color_a The start color. + * @param color_b The end color. + */ + void fill_gradient_h(Rect area, Color color_a, Color color_b) const; + + /** + * Fills an area of the Image with a vertical gradient (top to bottom). + * @param area The area to fill. + * @param color_a The start color. + * @param color_b The end color. + */ + void fill_gradient_v(Rect area, Color color_a, Color color_b) const; + + /** + * Draws the outline of an area on the Image. + * @param area The rect of the area to outline. + * @param color The color to draw the outline in. + */ + void outline(Rect area, Color color) const; + + /** + * Draws the outline of an area on the Image, calculating transparency. + * @param area The rect of the area to outline. + * @param color The color to draw the outline in. + */ + void outline_blitting(Rect area, Color color) const; + + /** + * Draws text on the Image with a certain color. + * @param str The string to draw. + * @param pos The top-left position of where to draw. + * @param font The font to use. + * @param color The color to draw in. + */ + void draw_text(const char* str, const Point& pos, Font* font, Color color) const; + + /** + * Draws a glyph on the Image with a certain color. + * @param font The font to use. + * @param codepoint The codepoint of the character. + * @param pos The position to draw the glyph at. + * @param color The color to draw the glyph in. + * @return The position where the next character should be drawn. + */ + Point draw_glyph(Font* font, uint32_t codepoint, const Point& pos, Color color) const; + + /** + * Multiplies the image with a certain color. + * @param color The color to multiply by. + */ + void multiply(Color color); + + /** + * Returns a pointer to the Image buffer at a certain position. Returns NULL if outside the constraints. + */ + Color* at(const Point& position) const; + + /// Serializable + size_t serialized_size() const override; + void serialize(uint8_t*& buf) const override; + void deserialize(const uint8_t*& buf) override; + }; +} + + diff --git a/libraries/libgraphics/Framebuffer_REMOTE_140866.h b/libraries/libgraphics/Framebuffer_REMOTE_140866.h new file mode 100644 index 00000000..41a2c28c --- /dev/null +++ b/libraries/libgraphics/Framebuffer_REMOTE_140866.h @@ -0,0 +1,195 @@ +/* + This file is part of duckOS. + + duckOS is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + duckOS 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with duckOS. If not, see . + + Copyright (c) Byteduck 2016-2021. All rights reserved. +*/ + +#pragma once + +#include +#include "Geometry.h" +#include "Color.h" +#include + +#define IMGSIZE(width, height) (sizeof(uint32_t) * (width) * (height)) +#define IMGPIXEL(img, x, y) (img).data[(x) + (y) * (img).width] +#define IMGPTRPIXEL(img, x, y) (img)->data[(x) + (y) * (img)->width] + +namespace Gfx { + class Font; + class Framebuffer: public Duck::Serializable { + public: + Framebuffer(); + Framebuffer(Color* buffer, int width, int height); + Framebuffer(int width, int height); + Framebuffer(Framebuffer&& other) noexcept; + Framebuffer(Framebuffer& other) noexcept; + ~Framebuffer() noexcept; + + Framebuffer& operator=(const Framebuffer& other); + Framebuffer& operator=(Framebuffer&& other) noexcept; + + Color* data = nullptr; + int width = 0; + int height = 0; + bool should_free = false; + + /** + * Frees the data associated with the Image. + */ + void free(); + + /** + * Copies a part of another Image to this one. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Copies a part of another Image to this one, ignoring alpha. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy_noalpha(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Copies a part of another Image to this one, with alpha blending. + * @param other The other Image to copy from. + * @param other_area The area of the other Image to copy. + * @param pos The position of this Image to copy to. + */ + void copy_blitting(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Blurs an area of this framebuffer with an approximated gaussian blur. + * @param area The area to blur. + * @param radius The blur radius. + */ + void blur(Rect area, int radius = 4) const; + + /** + * Identical to ::copy(), but will tile the Image. + */ + void copy_tiled(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending. + * @param other The Image to draw. + * @param other_area The area of the other Image to draw. + * @param pos The position on this Image to draw on. + */ + void draw_image(const Framebuffer& other, Rect other_area, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending. + * @param other The Image to draw. + * @param pos The position on this Image to draw on. + */ + void draw_image(const Framebuffer& other, const Point& pos) const; + + /** + * Draws another Image on top of this one with alpha blending, scaled to + * fit inside of the specified rect. + * @param other The Image to draw. + * @param size The rect on this Image to scale the image to and draw on. + */ + void draw_image_scaled(const Framebuffer& other, const Rect& rect) const; + + /** + * Fills an area of the Image with a color. + * @param area The area to fill. + * @param color The color to fill the area with. + */ + void fill(Rect area, Color color) const; + + /** + * Fills an area of the Image with a color, calculating transparency. + * @param area The area to fill. + * @param color The color to fill the area with. + */ + void fill_blitting(Rect area, Color color) const; + + /** + * Fills an area of the Image with a horizontal gradient (left to right). + * @param area The area to fill. + * @param color_a The start color. + * @param color_b The end color. + */ + void fill_gradient_h(Rect area, Color color_a, Color color_b) const; + + /** + * Fills an area of the Image with a vertical gradient (top to bottom). + * @param area The area to fill. + * @param color_a The start color. + * @param color_b The end color. + */ + void fill_gradient_v(Rect area, Color color_a, Color color_b) const; + + /** + * Draws the outline of an area on the Image. + * @param area The rect of the area to outline. + * @param color The color to draw the outline in. + */ + void outline(Rect area, Color color) const; + + /** + * Draws the outline of an area on the Image, calculating transparency. + * @param area The rect of the area to outline. + * @param color The color to draw the outline in. + */ + void outline_blitting(Rect area, Color color) const; + + /** + * Draws text on the Image with a certain color. + * @param str The string to draw. + * @param pos The top-left position of where to draw. + * @param font The font to use. + * @param color The color to draw in. + */ + void draw_text(const char* str, const Point& pos, Font* font, Color color) const; + + /** + * Draws a glyph on the Image with a certain color. + * @param font The font to use. + * @param codepoint The codepoint of the character. + * @param pos The position to draw the glyph at. + * @param color The color to draw the glyph in. + * @return The position where the next character should be drawn. + */ + Point draw_glyph(Font* font, uint32_t codepoint, const Point& pos, Color color) const; + + /** + * Multiplies the image with a certain color. + * @param color The color to multiply by. + */ + void multiply(Color color); + + /** + * Returns a pointer to the Image buffer at a certain position. Returns NULL if outside the constraints. + */ + Color* at(const Point& position) const; + + /// Serializable + size_t serialized_size() const override; + void serialize(uint8_t*& buf) const override; + void deserialize(const uint8_t*& buf) override; + }; +} + + diff --git a/libraries/libpond/Window.cpp b/libraries/libpond/Window.cpp index 98f33465..340d6a03 100644 --- a/libraries/libpond/Window.cpp +++ b/libraries/libpond/Window.cpp @@ -147,3 +147,7 @@ void Window::set_has_shadow(bool shadow) { void Window::set_minimum_size(Gfx::Dimensions dimensions) { _context->__river_set_minimum_size({_id, dimensions}); } + +void Window::set_blur_behind(bool blur) { + _context->__river_set_hint({_id, PWINDOW_HINT_BLURBEHIND, (int) blur}); +} diff --git a/libraries/libpond/Window.h b/libraries/libpond/Window.h index 821c1f91..5a4d976d 100644 --- a/libraries/libpond/Window.h +++ b/libraries/libpond/Window.h @@ -33,6 +33,7 @@ #define PWINDOW_HINT_RESIZABLE 0x5 #define PWINDOW_HINT_WINDOWTYPE 0x6 #define PWINDOW_HINT_SHADOW 0x7 +#define PWINDOW_HINT_BLURBEHIND 0x8 /** * A window Object representing a window in the Pond window system. @@ -201,6 +202,9 @@ namespace Pond { /** Sets the minimum size of the window. */ void set_minimum_size(Gfx::Dimensions dimensions); + /** Sets whether the window should blur screen contents behind it. */ + void set_blur_behind(bool blur); + private: friend class Context; diff --git a/libraries/libui/Window.cpp b/libraries/libui/Window.cpp index 35a8d38a..1b14ffc9 100644 --- a/libraries/libui/Window.cpp +++ b/libraries/libui/Window.cpp @@ -159,10 +159,11 @@ void Window::repaint_now() { auto framebuffer = _window->framebuffer(); auto ctx = DrawContext(framebuffer); if(_decorated) { - Gfx::Color color = Theme::window(); - //Window background - ctx.fill({0, 0, ctx.width(), ctx.height()}, color); + if(_uses_alpha) + ctx.fill({0, 0, ctx.width(), ctx.height()}, Gfx::Color(0, 0, 0, 0)); + else + ctx.fill({0, 0, ctx.width(), ctx.height()}, Theme::window()); //Title bar Gfx::Rect titlebar_rect = {0, 0, ctx.width(), UI_TITLEBAR_HEIGHT}; diff --git a/services/pond/Display.cpp b/services/pond/Display.cpp index 8de4995d..40cf4b14 100644 --- a/services/pond/Display.cpp +++ b/services/pond/Display.cpp @@ -225,10 +225,13 @@ void Display::repaint() { Gfx::Rect window_abs = window->absolute_rect(); Gfx::Rect overlap_abs = area.overlapping_area(window_abs); auto transformed_overlap = overlap_abs.transform({-window_abs.x, -window_abs.y}); - if(window->uses_alpha()) + if(window->uses_alpha()) { + if(window->blurs_behind()) + fb.blur(overlap_abs); fb.copy_blitting(window->framebuffer(), transformed_overlap, overlap_abs.position()); - else + } else { fb.copy(window->framebuffer(), transformed_overlap, overlap_abs.position()); + } // Draw the shadow if(window->has_shadow()) { diff --git a/services/pond/Window.cpp b/services/pond/Window.cpp index 0cf15b58..a5f263ec 100644 --- a/services/pond/Window.cpp +++ b/services/pond/Window.cpp @@ -391,6 +391,9 @@ void Window::set_hint(int hint, int value) { case PWINDOW_HINT_SHADOW: set_has_shadow(value); break; + case PWINDOW_HINT_BLURBEHIND: + set_blur_behind(value); + break; default: Duck::Log::warn("Unknown window hint ", hint); } @@ -419,6 +422,15 @@ void Window::set_has_shadow(bool shadow) { invalidate(); } +void Window::set_blur_behind(bool blur) { + _blur_behind = blur; + invalidate(); +} + +bool Window::blurs_behind() const { + return _blur_behind; +} + void Window::set_minimum_size(Gfx::Dimensions minimum) { _minimum_size = { std::max(minimum.width, WINDOW_RESIZE_BORDER * 2), diff --git a/services/pond/Window.h b/services/pond/Window.h index cc9fc8dd..25225db1 100644 --- a/services/pond/Window.h +++ b/services/pond/Window.h @@ -260,7 +260,17 @@ class Window { void set_has_shadow(bool shadow); /** - * Gets the shadow framebuffers for drawing shadows. + * Sets whether the window should blur contents behind it. + */ + void set_blur_behind(bool blur); + + /** + * Returns whether the window blurs contents behind it. + */ + bool blurs_behind() const; + + /** + * Gets the shadow framebuffer for drawing shadows. */ Gfx::Framebuffer* shadow_buffers() { return _shadow_buffers; } @@ -296,6 +306,7 @@ class Window { bool _uses_alpha = false; bool _destructing = false; bool _draws_shadow = true; + bool _blur_behind = false; Pond::WindowType _type = Pond::DEFAULT; Gfx::Framebuffer _shadow_buffers[4]; Gfx::Dimensions _minimum_size = {WINDOW_RESIZE_BORDER * 2, WINDOW_RESIZE_BORDER * 2}; From e4115955f7eb951d060fdea4aaa78e9dc2dab77a Mon Sep 17 00:00:00 2001 From: Aaron <10217842+byteduck@users.noreply.github.com> Date: Thu, 23 Feb 2023 15:14:25 -0800 Subject: [PATCH 2/4] Terminal: Blur background --- programs/applications/terminal/TerminalWidget.cpp | 3 ++- programs/applications/terminal/main.cpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/programs/applications/terminal/TerminalWidget.cpp b/programs/applications/terminal/TerminalWidget.cpp index 968d78b7..c4eaef41 100644 --- a/programs/applications/terminal/TerminalWidget.cpp +++ b/programs/applications/terminal/TerminalWidget.cpp @@ -26,7 +26,7 @@ #include static const uint32_t color_palette[] = { - 0xFF000000, + 0x99000000, 0xFFAA0000, 0xFF00AA00, 0xFFAA5500, @@ -47,6 +47,7 @@ static const uint32_t color_palette[] = { TerminalWidget::TerminalWidget() { font = UI::Theme::font_mono(); term = new Term::Terminal({1, 1}, *this); + set_uses_alpha(true); //Setup PTY pty_fd = posix_openpt(O_RDWR | O_CLOEXEC); diff --git a/programs/applications/terminal/main.cpp b/programs/applications/terminal/main.cpp index eebdb18d..e262e2f7 100644 --- a/programs/applications/terminal/main.cpp +++ b/programs/applications/terminal/main.cpp @@ -28,6 +28,8 @@ int main(int argc, char** argv, char** envp) { //Make window auto window = UI::Window::make(); window->set_title("Terminal"); + window->set_uses_alpha(true); + window->pond_window()->set_blur_behind(true); //Create terminal widget auto termwidget = TerminalWidget::make(); From d876f1f646d9a67413ab550e0dfa745dbcf11574 Mon Sep 17 00:00:00 2001 From: Aaron <10217842+byteduck@users.noreply.github.com> Date: Thu, 23 Feb 2023 20:03:15 -0800 Subject: [PATCH 3/4] libgraphics: Fix blur algorithm The blur algorithm had an error in the indexing for the vertical component of the blur and an error in the sliding window logic. --- libraries/libgraphics/Framebuffer.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/libraries/libgraphics/Framebuffer.cpp b/libraries/libgraphics/Framebuffer.cpp index 60ac3a33..c050f4f5 100644 --- a/libraries/libgraphics/Framebuffer.cpp +++ b/libraries/libgraphics/Framebuffer.cpp @@ -126,7 +126,6 @@ void Framebuffer::copy_blitting(const Framebuffer& other, Rect other_area, const } } -<<<<<<< HEAD void Framebuffer::copy_blitting_flipped(const Framebuffer& other, Rect other_area, const Point& pos, bool flip_h, bool flip_v) const { //Make sure self_area is in bounds of the framebuffer Rect self_area = {pos.x, pos.y, other_area.width, other_area.height}; @@ -150,15 +149,13 @@ void Framebuffer::copy_blitting_flipped(const Framebuffer& other, Rect other_are this_val = this_val.blended(other_val); } } -======= -inline int math_mod(int a, int b) { - return (a % b + b) % b; } void Framebuffer::blur(Gfx::Rect area, int radius) const { int window_size = radius * 2 + 1; + area = area.overlapping_area(Rect {0, 0, width, height}); - auto do_pass = [&]() { ; + auto do_pass = [&]() { // First, apply blur horizontally. for(int y = area.y; y < area.y + area.height; y++) { int window[3] = {0, 0, 0}; @@ -180,11 +177,11 @@ void Framebuffer::blur(Gfx::Rect area, int radius) const { (uint8_t) (window[1] / window_size), (uint8_t) (window[2] / window_size), }; - auto window_add = data[(std::min(x + 5, width - 1)) + y * width]; + auto window_add = data[(std::min(x + radius + 1, width - 1)) + y * width]; auto window_sub = window_preblur[preblur_index]; + window_preblur[preblur_index] = window_add; preblur_index++; preblur_index %= window_size; - window_preblur[((preblur_index - 1) % window_size + window_size) % window_size] = window_add; window[0] += (int) window_add.r - (int) window_sub.r; window[1] += (int) window_add.g - (int) window_sub.g; window[2] += (int) window_add.b - (int) window_sub.b; @@ -199,7 +196,7 @@ void Framebuffer::blur(Gfx::Rect area, int radius) const { // Populate window for(int i = -radius; i <= radius; i++) { - auto color = data[(x + std::min(std::max(area.y + i, 0), height - 1)) * width]; + auto color = data[x + (std::min(std::max(area.y + i, 0), height - 1)) * width]; window_preblur[i + radius] = color; window[0] += color.r; window[1] += color.g; @@ -212,11 +209,11 @@ void Framebuffer::blur(Gfx::Rect area, int radius) const { (uint8_t) (window[1] / window_size), (uint8_t) (window[2] / window_size), }; - auto window_add = data[x + (std::min(y + 5, height - 1)) * width]; + auto window_add = data[x + (std::min(y + radius + 1, height - 1)) * width]; auto window_sub = window_preblur[preblur_index]; + window_preblur[preblur_index] = window_add; preblur_index++; preblur_index %= window_size; - window_preblur[((preblur_index - 1) % window_size + window_size) % window_size] = window_add; window[0] += (int) window_add.r - (int) window_sub.r; window[1] += (int) window_add.g - (int) window_sub.g; window[2] += (int) window_add.b - (int) window_sub.b; @@ -226,7 +223,6 @@ void Framebuffer::blur(Gfx::Rect area, int radius) const { for(int i = 0; i < 3; i++) do_pass(); ->>>>>>> fb5c657 (Pond: Allow windows to blur what's behind them) } void Framebuffer::copy_tiled(const Framebuffer& other, Rect other_area, const Point& pos) const { From b646857ac1f8b41578db809f39e4bef4ea504886 Mon Sep 17 00:00:00 2001 From: Aaron <10217842+byteduck@users.noreply.github.com> Date: Thu, 23 Feb 2023 21:06:34 -0800 Subject: [PATCH 4/4] Pond: Redraw entire blurred window if something touching it is invalidated --- services/pond/Display.cpp | 14 +++++++++++--- services/pond/Display.h | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/services/pond/Display.cpp b/services/pond/Display.cpp index 40cf4b14..a9694cfd 100644 --- a/services/pond/Display.cpp +++ b/services/pond/Display.cpp @@ -34,6 +34,8 @@ using namespace Gfx; using Duck::Log, Duck::Config, Duck::ResultRet; +constexpr int BLUR_RADIUS = 4; + Display* Display::_inst = nullptr; Display::Display(): _dimensions({0, 0, 0, 0}) { @@ -159,7 +161,7 @@ void Display::remove_window(Window* window) { } } -void Display::invalidate(const Gfx::Rect& rect) { +void Display::invalidate(Gfx::Rect rect) { if(!rect.empty()) invalid_areas.push_back(rect); } @@ -183,9 +185,15 @@ void Display::repaint() { auto& fb = _buffer_mode == BufferMode::Single ? _framebuffer : _root_window->framebuffer(); - //Combine areas that overlap + // Combine areas that overlap auto it = invalid_areas.begin(); while(it != invalid_areas.end()) { + // If the area collides with a window that blurs behind it, we need to redraw that entire window's area + for(auto& window : _windows) { + if(window->blurs_behind() && it->collides(window->absolute_shadow_rect())) + *it = it->combine(window->absolute_shadow_rect()); + } + bool remove_area = false; for(auto & other_area : invalid_areas) { if(&*it != &other_area && it->collides(other_area)) { @@ -227,7 +235,7 @@ void Display::repaint() { auto transformed_overlap = overlap_abs.transform({-window_abs.x, -window_abs.y}); if(window->uses_alpha()) { if(window->blurs_behind()) - fb.blur(overlap_abs); + fb.blur(overlap_abs, BLUR_RADIUS); fb.copy_blitting(window->framebuffer(), transformed_overlap, overlap_abs.position()); } else { fb.copy(window->framebuffer(), transformed_overlap, overlap_abs.position()); diff --git a/services/pond/Display.h b/services/pond/Display.h index 31cfcfca..d4355bff 100644 --- a/services/pond/Display.h +++ b/services/pond/Display.h @@ -74,9 +74,9 @@ class Display { /** * Marks a portion of the display to be redrawn - * @param Gfx::Rect the absolute rect to be redrawn + * @param rect the absolute rect to be redrawn */ - void invalidate(const Gfx::Rect& rect); + void invalidate(Gfx::Rect rect); /** * Repaints the needed areas of the screen to the hidden screen buffer.