LibGUI: Add support for clip area to texture

This commit is contained in:
Bananymous 2025-06-10 21:42:55 +03:00
parent ac22e006a4
commit 8a73414e3e
2 changed files with 118 additions and 15 deletions

View File

@ -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<int32_t>(signed_x, 0);
const int32_t min_y = BAN::Math::max<int32_t>(signed_y, 0);
const int32_t max_x = BAN::Math::min<int32_t>(this->width(), signed_x + (int32_t)width);
const int32_t max_y = BAN::Math::min<int32_t>(this->height(), signed_y + (int32_t)height);
const int32_t min_x = BAN::Math::max<int32_t>(signed_x, m_clip_x);
const int32_t min_y = BAN::Math::max<int32_t>(signed_y, m_clip_y);
const int32_t max_x = BAN::Math::min<int32_t>(signed_x + (int32_t)width, m_clip_x + m_clip_w);
const int32_t max_y = BAN::Math::min<int32_t>(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<int32_t>(m_clip_x + m_clip_w))
return false;
if (dst_y >= static_cast<int32_t>(m_clip_y + m_clip_h))
return false;
if (src_x >= static_cast<int32_t>(texture.width()))
return false;
if (src_y >= static_cast<int32_t>(texture.height()))
return false;
if (dst_x + static_cast<int32_t>(width) > static_cast<int32_t>(m_clip_x + m_clip_w))
width = m_clip_x + m_clip_w - dst_x;
if (src_x + static_cast<int32_t>(width) > static_cast<int32_t>(texture.width()))
width = texture.width() - src_x;
if (dst_y + static_cast<int32_t>(height) > static_cast<int32_t>(m_clip_y + m_clip_h))
height = m_clip_y + m_clip_h - dst_y;
if (src_y + static_cast<int32_t>(height) > static_cast<int32_t>(texture.height()))
height = texture.height() - src_y;
int32_t off_x = 0;
if (dst_x < static_cast<int32_t>(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<int32_t>(width))
return false;
int32_t off_y = 0;
if (dst_y < static_cast<int32_t>(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<int32_t>(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;
}
}

View File

@ -13,6 +13,7 @@ namespace LibGUI
{
public:
static BAN::ErrorOr<Texture> create(uint32_t width, uint32_t height, uint32_t color);
Texture() = default;
BAN::ErrorOr<void> 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<uint32_t> 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<uint32_t>&& 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<uint32_t> 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;
};