diff --git a/userspace/libraries/LibGUI/Texture.cpp b/userspace/libraries/LibGUI/Texture.cpp index a170a2c4..392d1c88 100644 --- a/userspace/libraries/LibGUI/Texture.cpp +++ b/userspace/libraries/LibGUI/Texture.cpp @@ -32,9 +32,41 @@ namespace LibGUI m_height = new_height; m_pixels = BAN::move(pixels); + if (m_has_set_clip) + set_clip_area(m_clip_x, m_clip_y, m_clip_w, m_clip_h); + else + { + m_clip_w = new_width; + m_clip_h = new_height; + } + return {}; } + void Texture::set_clip_area(int32_t x, int32_t y, uint32_t width, uint32_t height) + { + m_clip_x = 0; + m_clip_y = 0; + m_clip_w = this->width(); + m_clip_h = this->height(); + + + if (!clamp_to_texture(x, y, width, height)) + { + m_clip_h = 0; + m_clip_w = 0; + } + else + { + m_clip_x = x; + m_clip_y = y; + m_clip_w = width; + m_clip_h = height; + } + + m_has_set_clip = true; + } + void Texture::fill_rect(int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t color) { if (!clamp_to_texture(x, y, width, height)) @@ -44,15 +76,17 @@ namespace LibGUI set_pixel(x + x_off, y + y_off, color); } - void Texture::copy_texture(const Texture& texture, int32_t x, int32_t y) + void Texture::copy_texture(const Texture& texture, int32_t x, int32_t y, uint32_t sub_x, uint32_t sub_y, uint32_t width, uint32_t height) { - uint32_t width = texture.width(); - uint32_t height = texture.height(); - if (!clamp_to_texture(x, y, width, height)) + int32_t src_x = sub_x, src_y = sub_y; + if (!clamp_to_texture(x, y, src_x, src_y, width, height, texture)) return; + sub_x = src_x; + sub_y = src_y; + for (uint32_t y_off = 0; y_off < height; y_off++) for (uint32_t x_off = 0; x_off < width; x_off++) - set_pixel(x + x_off, y + y_off, texture.get_pixel(x_off, y_off)); + set_pixel(x + x_off, y + y_off, texture.get_pixel(sub_x + x_off, sub_y + y_off)); } void Texture::draw_character(uint32_t codepoint, const LibFont::Font& font, int32_t tl_x, int32_t tl_y, uint32_t color) @@ -132,9 +166,7 @@ namespace LibGUI void Texture::copy_rect(int32_t dst_x, int32_t dst_y, int32_t src_x, int32_t src_y, uint32_t width, uint32_t height) { - if (!clamp_to_texture(dst_x, dst_y, width, height)) - return; - if (!clamp_to_texture(src_x, src_y, width, height)) + if (!clamp_to_texture(dst_x, dst_y, src_x, src_y, width, height, *this)) return; const bool copy_dir = dst_y < src_y; @@ -151,10 +183,10 @@ namespace LibGUI bool Texture::clamp_to_texture(int32_t& signed_x, int32_t& signed_y, uint32_t& width, uint32_t& height) const { - const int32_t min_x = BAN::Math::max(signed_x, 0); - const int32_t min_y = BAN::Math::max(signed_y, 0); - const int32_t max_x = BAN::Math::min(this->width(), signed_x + (int32_t)width); - const int32_t max_y = BAN::Math::min(this->height(), signed_y + (int32_t)height); + const int32_t min_x = BAN::Math::max(signed_x, m_clip_x); + const int32_t min_y = BAN::Math::max(signed_y, m_clip_y); + const int32_t max_x = BAN::Math::min(signed_x + (int32_t)width, m_clip_x + m_clip_w); + const int32_t max_y = BAN::Math::min(signed_y + (int32_t)height, m_clip_y + m_clip_h); if (min_x >= max_x) return false; @@ -163,9 +195,63 @@ namespace LibGUI signed_x = min_x; signed_y = min_y; - width = max_x - min_x; + width = max_x - min_x; height = max_y - min_y; return true; } + bool Texture::clamp_to_texture(int32_t& dst_x, int32_t& dst_y, int32_t& src_x, int32_t& src_y, uint32_t& width, uint32_t& height, const Texture& texture) const + { + if (width > texture.width()) + width = texture.width(); + if (height > texture.height()) + height = texture.height(); + + if (dst_x >= static_cast(m_clip_x + m_clip_w)) + return false; + if (dst_y >= static_cast(m_clip_y + m_clip_h)) + return false; + + if (src_x >= static_cast(texture.width())) + return false; + if (src_y >= static_cast(texture.height())) + return false; + + if (dst_x + static_cast(width) > static_cast(m_clip_x + m_clip_w)) + width = m_clip_x + m_clip_w - dst_x; + if (src_x + static_cast(width) > static_cast(texture.width())) + width = texture.width() - src_x; + + if (dst_y + static_cast(height) > static_cast(m_clip_y + m_clip_h)) + height = m_clip_y + m_clip_h - dst_y; + if (src_y + static_cast(height) > static_cast(texture.height())) + height = texture.height() - src_y; + + int32_t off_x = 0; + if (dst_x < static_cast(m_clip_x)) + off_x = m_clip_x - dst_x; + if (src_x + off_x < 0) + off_x = -src_x; + if (off_x >= static_cast(width)) + return false; + + int32_t off_y = 0; + if (dst_y < static_cast(m_clip_y)) + off_y = m_clip_y - dst_y; + if (src_y + off_y < 0) + off_y = -src_y; + if (off_y >= static_cast(height)) + return false; + + dst_x += off_x; + src_x += off_x; + dst_y += off_y; + src_y += off_y; + + width -= off_x; + height -= off_y; + + return true; + } + } diff --git a/userspace/libraries/LibGUI/include/LibGUI/Texture.h b/userspace/libraries/LibGUI/include/LibGUI/Texture.h index 8f538a44..cde48056 100644 --- a/userspace/libraries/LibGUI/include/LibGUI/Texture.h +++ b/userspace/libraries/LibGUI/include/LibGUI/Texture.h @@ -13,6 +13,7 @@ namespace LibGUI { public: static BAN::ErrorOr create(uint32_t width, uint32_t height, uint32_t color); + Texture() = default; BAN::ErrorOr resize(uint32_t width, uint32_t height); @@ -20,6 +21,10 @@ namespace LibGUI { ASSERT(x < m_width); ASSERT(y < m_height); + if (x < m_clip_x || x >= m_clip_x + m_clip_w) + return; + if (y < m_clip_y || y >= m_clip_y + m_clip_h) + return; m_pixels[y * m_width + x] = color; } @@ -32,10 +37,12 @@ namespace LibGUI BAN::Span pixels() { return m_pixels.span(); } + void set_clip_area(int32_t x, int32_t y, uint32_t width, uint32_t height); + void fill_rect(int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t color); void fill(uint32_t color) { return fill_rect(0, 0, width(), height(), color); } - void copy_texture(const Texture& texture, int32_t x, int32_t y); + void copy_texture(const Texture& texture, int32_t x, int32_t y, uint32_t sub_x = 0, uint32_t sub_y = 0, uint32_t width = -1, uint32_t height = -1); void draw_character(uint32_t codepoint, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color); void draw_text(BAN::StringView text, const LibFont::Font& font, int32_t x, int32_t y, uint32_t color); @@ -59,15 +66,19 @@ namespace LibGUI void set_bg_color(uint32_t bg_color) { m_bg_color = bg_color; } private: - Texture() = default; Texture(BAN::Vector&& pixels, uint32_t width, uint32_t height, uint32_t color) : m_pixels(BAN::move(pixels)) , m_width(width) , m_height(height) , m_bg_color(color) + , m_clip_x(0) + , m_clip_y(0) + , m_clip_w(width) + , m_clip_h(height) {} bool clamp_to_texture(int32_t& x, int32_t& y, uint32_t& width, uint32_t& height) const; + bool clamp_to_texture(int32_t& dst_x, int32_t& dst_y, int32_t& src_x, int32_t& src_y, uint32_t& width, uint32_t& height, const Texture&) const; private: BAN::Vector m_pixels; @@ -75,6 +86,12 @@ namespace LibGUI uint32_t m_height { 0 }; uint32_t m_bg_color { 0xFFFFFFFF }; + uint32_t m_clip_x { 0 }; + uint32_t m_clip_y { 0 }; + uint32_t m_clip_w { 0 }; + uint32_t m_clip_h { 0 }; + bool m_has_set_clip { false }; + friend class Window; };