mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-28 13:43:45 +03:00
LibGUI: Reimplement Painter::draw_triangle to be more symmetrical
This is a reimplementation of draw_triangle that manages without floating point arithmetic. It's most important property, compared to the previous implementation is that rotating the same triangle 90 degrees won't drastically change the appearance of that triangle. (it did before)
This commit is contained in:
parent
586a94818d
commit
565f68f8bb
Notes:
sideshowbarker
2024-07-17 10:04:11 +09:00
Author: https://github.com/frhun Commit: https://github.com/SerenityOS/serenity/commit/565f68f8bb Pull-request: https://github.com/SerenityOS/serenity/pull/14282 Reviewed-by: https://github.com/AtkinsSJ ✅ Reviewed-by: https://github.com/MacDue
@ -695,6 +695,10 @@ void Painter::draw_triangle(IntPoint const& a, IntPoint const& b, IntPoint const
|
||||
if (p0.y() == p2.y())
|
||||
return;
|
||||
|
||||
// return if all points are on the same line vertically
|
||||
if (p0.x() == p1.x() && p1.x() == p2.x())
|
||||
return;
|
||||
|
||||
// return if top is below clip rect or bottom is above clip rect
|
||||
auto clip = clip_rect();
|
||||
if (p0.y() >= clip.bottom())
|
||||
@ -702,56 +706,78 @@ void Painter::draw_triangle(IntPoint const& a, IntPoint const& b, IntPoint const
|
||||
if (p2.y() < clip.top())
|
||||
return;
|
||||
|
||||
class BoundaryLine {
|
||||
private:
|
||||
IntPoint m_base {};
|
||||
IntPoint m_path {};
|
||||
|
||||
public:
|
||||
BoundaryLine(IntPoint a, IntPoint b)
|
||||
{
|
||||
VERIFY(a.y() <= b.y());
|
||||
m_base = a;
|
||||
m_path = b - a;
|
||||
}
|
||||
|
||||
int top_y() const { return m_base.y(); }
|
||||
|
||||
int bottom_y() const { return m_base.y() + m_path.y(); }
|
||||
|
||||
bool is_vertical() const { return m_path.x() == 0; }
|
||||
|
||||
bool is_horizontal() const { return m_path.y() == 0; }
|
||||
|
||||
bool in_y_range(int y) const { return y >= top_y() && y <= bottom_y(); }
|
||||
|
||||
Optional<int> intersection_on_x(int y) const
|
||||
{
|
||||
if (!in_y_range(y))
|
||||
return {};
|
||||
if (is_horizontal())
|
||||
return {};
|
||||
if (is_vertical())
|
||||
return m_base.x();
|
||||
|
||||
int y_diff = y - top_y();
|
||||
int x_d = m_path.x() * y_diff, y_d = m_path.y();
|
||||
|
||||
return (x_d / y_d) + m_base.x();
|
||||
}
|
||||
};
|
||||
|
||||
BoundaryLine l0(p0, p1), l1(p0, p2), l2(p1, p2);
|
||||
|
||||
int rgba = color.value();
|
||||
|
||||
float dx02 = (float)(p2.x() - p0.x()) / (p2.y() - p0.y());
|
||||
float x01 = p0.x();
|
||||
float x02 = p0.x();
|
||||
for (int y = max(p0.y(), clip.top()); y <= min(p2.y(), clip.bottom()); y++) {
|
||||
Optional<int>
|
||||
x0 = l0.intersection_on_x(y),
|
||||
x1 = l1.intersection_on_x(y),
|
||||
x2 = l2.intersection_on_x(y);
|
||||
|
||||
if (p0.y() != p1.y()) { // p0 and p1 are on different lines
|
||||
float dx01 = (float)(p1.x() - p0.x()) / (p1.y() - p0.y());
|
||||
int result_a = 0, result_b = 0;
|
||||
|
||||
int top = p0.y();
|
||||
if (top < clip.top()) {
|
||||
x01 += dx01 * (clip.top() - top);
|
||||
x02 += dx02 * (clip.top() - top);
|
||||
top = clip.top();
|
||||
}
|
||||
|
||||
for (int y = top; y < p1.y() && y < clip.bottom(); ++y) { // XXX <=?
|
||||
int start = x01 > x02 ? max((int)x02, clip.left()) : max((int)x01, clip.left());
|
||||
int end = x01 > x02 ? min((int)x01, clip.right()) : min((int)x02, clip.right());
|
||||
auto* scanline = m_target->scanline(y);
|
||||
for (int x = start; x < end; x++) {
|
||||
scanline[x] = rgba;
|
||||
if (x0.has_value()) {
|
||||
result_a = x0.value();
|
||||
if (x1.has_value() && ((!x2.has_value()) || (result_a != x1.value()))) {
|
||||
result_b = x1.value();
|
||||
} else {
|
||||
result_b = x2.value();
|
||||
}
|
||||
x01 += dx01;
|
||||
x02 += dx02;
|
||||
} else if (x1.has_value()) {
|
||||
result_a = x1.value();
|
||||
result_b = x2.value();
|
||||
}
|
||||
}
|
||||
|
||||
// return if middle point and bottom point are on same line
|
||||
if (p1.y() == p2.y())
|
||||
return;
|
||||
if (result_a > result_b)
|
||||
swap(result_a, result_b);
|
||||
|
||||
float x12 = p1.x();
|
||||
float dx12 = (float)(p2.x() - p1.x()) / (p2.y() - p1.y());
|
||||
int top = p1.y();
|
||||
if (top < clip.top()) {
|
||||
x02 += dx02 * (clip.top() - top);
|
||||
x12 += dx12 * (clip.top() - top);
|
||||
top = clip.top();
|
||||
}
|
||||
int left_bound = result_a, right_bound = result_b;
|
||||
|
||||
for (int y = top; y < p2.y() && y < clip.bottom(); ++y) { // XXX <=?
|
||||
int start = x12 > x02 ? max((int)x02, clip.left()) : max((int)x12, clip.left());
|
||||
int end = x12 > x02 ? min((int)x12, clip.right()) : min((int)x02, clip.right());
|
||||
auto* scanline = m_target->scanline(y);
|
||||
for (int x = start; x < end; x++) {
|
||||
ARGB32* scanline = m_target->scanline(y);
|
||||
for (int x = max(left_bound, clip.left()); x <= min(right_bound, clip.right()); x++) {
|
||||
scanline[x] = rgba;
|
||||
}
|
||||
x02 += dx02;
|
||||
x12 += dx12;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user