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.