From d7be3faab5194c5b7e22a6c3c5757dbb0a0c9d70 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 23 Jul 2020 20:32:39 +0200 Subject: [PATCH] LibGfx: Add an "opacity" argument to Painter::draw_scaled_bitmap() This API is not super perfect as it merely overrides the source alpha on all source pixels instead of blending the alpha values. There is room for improvement here for sure. --- Libraries/LibGfx/Painter.cpp | 43 ++++++++++++++++++++---------------- Libraries/LibGfx/Painter.h | 2 +- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Libraries/LibGfx/Painter.cpp b/Libraries/LibGfx/Painter.cpp index 3d1fa05ab5..af82aa876f 100644 --- a/Libraries/LibGfx/Painter.cpp +++ b/Libraries/LibGfx/Painter.cpp @@ -690,12 +690,14 @@ void Painter::blit(const IntPoint& position, const Gfx::Bitmap& source, const In } template -ALWAYS_INLINE static void do_draw_integer_scaled_bitmap(Gfx::Bitmap& target, const IntRect& dst_rect, const Gfx::Bitmap& source, int hfactor, int vfactor, GetPixel get_pixel) +ALWAYS_INLINE static void do_draw_integer_scaled_bitmap(Gfx::Bitmap& target, const IntRect& dst_rect, const Gfx::Bitmap& source, int hfactor, int vfactor, GetPixel get_pixel, float opacity) { + u8 src_alpha = opacity * 255; for (int y = source.rect().top(); y <= source.rect().bottom(); ++y) { int dst_y = dst_rect.y() + y * vfactor; for (int x = source.rect().left(); x <= source.rect().right(); ++x) { auto src_pixel = get_pixel(source, x, y); + src_pixel.set_alpha(src_alpha); for (int yo = 0; yo < vfactor; ++yo) { auto* scanline = (Color*)target.scanline(dst_y + yo); int dst_x = dst_rect.x() + x * hfactor; @@ -711,26 +713,29 @@ ALWAYS_INLINE static void do_draw_integer_scaled_bitmap(Gfx::Bitmap& target, con } template -ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, const IntRect& dst_rect, const IntRect& clipped_rect, const Gfx::Bitmap& source, const IntRect& src_rect, int hscale, int vscale, GetPixel get_pixel) +ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, const IntRect& dst_rect, const IntRect& clipped_rect, const Gfx::Bitmap& source, const IntRect& src_rect, int hscale, int vscale, GetPixel get_pixel, float opacity) { if (dst_rect == clipped_rect && !(dst_rect.width() % src_rect.width()) && !(dst_rect.height() % src_rect.height())) { int hfactor = dst_rect.width() / src_rect.width(); int vfactor = dst_rect.height() / src_rect.height(); if (hfactor == 2 && vfactor == 2) - return do_draw_integer_scaled_bitmap(target, dst_rect, source, 2, 2, get_pixel); + return do_draw_integer_scaled_bitmap(target, dst_rect, source, 2, 2, get_pixel, opacity); if (hfactor == 3 && vfactor == 3) - return do_draw_integer_scaled_bitmap(target, dst_rect, source, 3, 3, get_pixel); + return do_draw_integer_scaled_bitmap(target, dst_rect, source, 3, 3, get_pixel, opacity); if (hfactor == 4 && vfactor == 4) - return do_draw_integer_scaled_bitmap(target, dst_rect, source, 4, 4, get_pixel); - return do_draw_integer_scaled_bitmap(target, dst_rect, source, hfactor, vfactor, get_pixel); + return do_draw_integer_scaled_bitmap(target, dst_rect, source, 4, 4, get_pixel, opacity); + return do_draw_integer_scaled_bitmap(target, dst_rect, source, hfactor, vfactor, get_pixel, opacity); } + u8 src_alpha = opacity * 255; + for (int y = clipped_rect.top(); y <= clipped_rect.bottom(); ++y) { auto* scanline = (Color*)target.scanline(y); for (int x = clipped_rect.left(); x <= clipped_rect.right(); ++x) { auto scaled_x = ((x - dst_rect.x()) * hscale) >> 16; auto scaled_y = ((y - dst_rect.y()) * vscale) >> 16; auto src_pixel = get_pixel(source, scaled_x, scaled_y); + src_pixel.set_alpha(src_alpha); if constexpr (has_alpha_channel) { scanline[x] = scanline[x].blend(src_pixel); @@ -740,11 +745,11 @@ ALWAYS_INLINE static void do_draw_scaled_bitmap(Gfx::Bitmap& target, const IntRe } } -void Painter::draw_scaled_bitmap(const IntRect& a_dst_rect, const Gfx::Bitmap& source, const IntRect& src_rect) +void Painter::draw_scaled_bitmap(const IntRect& a_dst_rect, const Gfx::Bitmap& source, const IntRect& src_rect, float opacity) { auto dst_rect = a_dst_rect; if (dst_rect.size() == src_rect.size()) - return blit(dst_rect.location(), source, src_rect); + return blit(dst_rect.location(), source, src_rect, opacity); auto safe_src_rect = src_rect.intersected(source.rect()); ASSERT(source.rect().contains(safe_src_rect)); @@ -759,40 +764,40 @@ void Painter::draw_scaled_bitmap(const IntRect& a_dst_rect, const Gfx::Bitmap& s if (source.has_alpha_channel()) { switch (source.format()) { case BitmapFormat::RGB32: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; case BitmapFormat::RGBA32: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; case BitmapFormat::Indexed8: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; case BitmapFormat::Indexed4: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; case BitmapFormat::Indexed2: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; case BitmapFormat::Indexed1: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; default: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; } } else { switch (source.format()) { case BitmapFormat::RGB32: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; case BitmapFormat::RGBA32: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; case BitmapFormat::Indexed8: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; default: - do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel); + do_draw_scaled_bitmap(*m_target, dst_rect, clipped_rect, source, src_rect, hscale, vscale, get_pixel, opacity); break; } } diff --git a/Libraries/LibGfx/Painter.h b/Libraries/LibGfx/Painter.h index 89172c1716..e9173d14b1 100644 --- a/Libraries/LibGfx/Painter.h +++ b/Libraries/LibGfx/Painter.h @@ -65,7 +65,7 @@ public: void set_pixel(const IntPoint&, Color); void draw_line(const IntPoint&, const IntPoint&, Color, int thickness = 1, LineStyle style = LineStyle::Solid); void draw_quadratic_bezier_curve(const IntPoint& control_point, const IntPoint&, const IntPoint&, Color, int thickness = 1, LineStyle style = LineStyle::Solid); - void draw_scaled_bitmap(const IntRect& dst_rect, const Gfx::Bitmap&, const IntRect& src_rect); + void draw_scaled_bitmap(const IntRect& dst_rect, const Gfx::Bitmap&, const IntRect& src_rect, float opacity = 1.0f); void blit(const IntPoint&, const Gfx::Bitmap&, const IntRect& src_rect, float opacity = 1.0f); void blit_dimmed(const IntPoint&, const Gfx::Bitmap&, const IntRect& src_rect); void blit_brightened(const IntPoint&, const Gfx::Bitmap&, const IntRect& src_rect);