mirror of
https://github.com/SerenityOS/serenity
synced 2024-10-15 20:33:10 +00:00
PixelPaint: BrushTool performance optimization
This patch optimizes how the Brush-Tool modifies the pixels. The new logic generates a "reference brush" with the required size, falloff and color only once and uses that for the rawing operations. If no editing mask is used the reference brush is writen via a blit operation to the content or mask image. This increases the drawing speed and therefore also allows bigger brush sizes.
This commit is contained in:
parent
31ee20e179
commit
b9b4ca064f
|
@ -12,6 +12,7 @@
|
|||
#include <LibGUI/Action.h>
|
||||
#include <LibGUI/BoxLayout.h>
|
||||
#include <LibGUI/Label.h>
|
||||
#include <LibGUI/MessageBox.h>
|
||||
#include <LibGUI/Painter.h>
|
||||
#include <LibGUI/ValueSlider.h>
|
||||
#include <LibGfx/AntiAliasingPainter.h>
|
||||
|
@ -26,6 +27,9 @@ void BrushTool::set_size(int size)
|
|||
return;
|
||||
m_size = size;
|
||||
refresh_editor_cursor();
|
||||
auto may_have_failed = ensure_brush_reference_bitmap(m_ensured_color);
|
||||
if (may_have_failed.is_error())
|
||||
GUI::MessageBox::show_error(nullptr, MUST(String::formatted("Failed to create the brush. error: {}", may_have_failed.release_error())));
|
||||
}
|
||||
|
||||
void BrushTool::on_mousedown(Layer* layer, MouseEvent& event)
|
||||
|
@ -87,18 +91,28 @@ Color BrushTool::color_for(GUI::MouseEvent const& event)
|
|||
|
||||
void BrushTool::draw_point(Gfx::Bitmap& bitmap, Gfx::Color color, Gfx::IntPoint point)
|
||||
{
|
||||
constexpr auto flow_scale = 10;
|
||||
if (ensure_brush_reference_bitmap(color).is_error())
|
||||
return;
|
||||
|
||||
if (m_editor->active_layer()->mask_type() != Layer::MaskType::EditingMask || m_editor->active_layer()->edit_mode() == Layer::EditMode::Mask) {
|
||||
Gfx::Painter painter = Gfx::Painter(bitmap);
|
||||
painter.blit(point.translated(-size()), *m_brush_reference, m_brush_reference->rect());
|
||||
return;
|
||||
}
|
||||
|
||||
// if we have to deal with an EditingMask we need to set the pixel individually
|
||||
int ref_x, ref_y;
|
||||
for (int y = point.y() - size(); y < point.y() + size(); y++) {
|
||||
for (int x = point.x() - size(); x < point.x() + size(); x++) {
|
||||
auto distance = point.distance_from({ x, y });
|
||||
ref_x = x + size() - point.x();
|
||||
ref_y = y + size() - point.y();
|
||||
if (x < 0 || x >= bitmap.width() || y < 0 || y >= bitmap.height())
|
||||
continue;
|
||||
if (distance >= size())
|
||||
|
||||
auto pixel_color = m_brush_reference->get_pixel<Gfx::StorageFormat::BGRA8888>(ref_x, ref_y);
|
||||
if (!pixel_color.alpha())
|
||||
continue;
|
||||
|
||||
auto falloff = get_falloff(distance) * flow_scale;
|
||||
auto pixel_color = color;
|
||||
pixel_color.set_alpha(AK::min(falloff * 255, 255));
|
||||
set_pixel_with_possible_mask(x, y, bitmap.get_pixel(x, y).blend(pixel_color), bitmap);
|
||||
}
|
||||
}
|
||||
|
@ -215,6 +229,36 @@ void BrushTool::refresh_editor_cursor()
|
|||
m_editor->update_tool_cursor();
|
||||
}
|
||||
|
||||
ErrorOr<void> BrushTool::ensure_brush_reference_bitmap(Gfx::Color color)
|
||||
{
|
||||
Gfx::IntSize brush_size = Gfx::IntSize(size() * 2, size() * 2);
|
||||
|
||||
if (m_brush_reference.is_null() || m_brush_reference->size() != brush_size)
|
||||
m_brush_reference = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, brush_size));
|
||||
else if (m_ensured_color != color || m_ensured_hardness != hardness())
|
||||
m_brush_reference->fill(Color::Transparent);
|
||||
else
|
||||
return {};
|
||||
|
||||
m_ensured_color = color;
|
||||
m_ensured_hardness = hardness();
|
||||
constexpr auto flow_scale = 10;
|
||||
Gfx::IntPoint center_point = { size(), size() };
|
||||
for (int y = 0; y < m_brush_reference->height(); y++) {
|
||||
for (int x = 0; x < m_brush_reference->width(); x++) {
|
||||
auto distance = center_point.distance_from({ x, y });
|
||||
if (distance >= size())
|
||||
continue;
|
||||
|
||||
auto falloff = get_falloff(distance) * flow_scale;
|
||||
auto pixel_color = color;
|
||||
pixel_color.set_alpha(AK::min(falloff * 255, 255));
|
||||
m_brush_reference->set_pixel(x, y, pixel_color);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
float BrushTool::preferred_cursor_size()
|
||||
{
|
||||
return 2 * size() * (m_editor ? m_editor->scale() : 1);
|
||||
|
|
|
@ -62,6 +62,10 @@ private:
|
|||
bool m_has_clicked { false };
|
||||
Gfx::IntPoint m_last_position;
|
||||
NonnullRefPtr<Gfx::Bitmap const> m_cursor = build_cursor();
|
||||
RefPtr<Gfx::Bitmap> m_brush_reference = nullptr;
|
||||
Gfx::Color m_ensured_color {};
|
||||
int m_ensured_hardness = 0;
|
||||
ErrorOr<void> ensure_brush_reference_bitmap(Gfx::Color);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -91,7 +91,10 @@ void Tool::set_pixel_with_possible_mask<Gfx::StorageFormat::BGRA8888>(int x, int
|
|||
|
||||
switch (m_editor->active_layer()->edit_mode()) {
|
||||
case Layer::EditMode::Content:
|
||||
bitmap.set_pixel<Gfx::StorageFormat::BGRA8888>(x, y, m_editor->active_layer()->modify_pixel_with_editing_mask(x, y, color, bitmap.get_pixel(x, y)));
|
||||
if (m_editor->active_layer()->mask_type() == Layer::MaskType::EditingMask)
|
||||
bitmap.set_pixel<Gfx::StorageFormat::BGRA8888>(x, y, m_editor->active_layer()->modify_pixel_with_editing_mask(x, y, color, bitmap.get_pixel(x, y)));
|
||||
else
|
||||
bitmap.set_pixel(x, y, color);
|
||||
break;
|
||||
case Layer::EditMode::Mask:
|
||||
bitmap.set_pixel<Gfx::StorageFormat::BGRA8888>(x, y, color);
|
||||
|
@ -106,7 +109,10 @@ void Tool::set_pixel_with_possible_mask(int x, int y, Gfx::Color color, Gfx::Bit
|
|||
|
||||
switch (m_editor->active_layer()->edit_mode()) {
|
||||
case Layer::EditMode::Content:
|
||||
bitmap.set_pixel(x, y, m_editor->active_layer()->modify_pixel_with_editing_mask(x, y, color, bitmap.get_pixel(x, y)));
|
||||
if (m_editor->active_layer()->mask_type() == Layer::MaskType::EditingMask)
|
||||
bitmap.set_pixel(x, y, m_editor->active_layer()->modify_pixel_with_editing_mask(x, y, color, bitmap.get_pixel(x, y)));
|
||||
else
|
||||
bitmap.set_pixel(x, y, color);
|
||||
break;
|
||||
case Layer::EditMode::Mask:
|
||||
bitmap.set_pixel(x, y, color);
|
||||
|
|
Loading…
Reference in a new issue