diff options
author | Stephan Unverwerth <s.unverwerth@gmx.de> | 2021-03-05 23:29:58 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-03-06 15:03:44 +0100 |
commit | 87d19273bc258665ebdddeba471c960a25005966 (patch) | |
tree | 958bdf5cfc9b4de717c49b189f426d18c855deaa /Userland/Libraries/LibGfx/Painter.cpp | |
parent | 25e4a3467d443f38bf5dd89152b1853a30809a21 (diff) | |
download | serenity-87d19273bc258665ebdddeba471c960a25005966.zip |
LibGfx: Fix draw_triangle() precision issues
This fixes some precision issues in Painter::draw_triangle()
that caused the Cube demo to leave pixels empty between triangles
under certain angles.
Also adds some extra comments for clarity and early returns when
parts of the triangle do not need to be drawn.
Diffstat (limited to 'Userland/Libraries/LibGfx/Painter.cpp')
-rw-r--r-- | Userland/Libraries/LibGfx/Painter.cpp | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index 021648a1f2..383df0ca91 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -456,12 +456,11 @@ void Painter::draw_triangle(const IntPoint& a, const IntPoint& b, const IntPoint { VERIFY(scale() == 1); // FIXME: Add scaling support. - RGBA32 rgba = color.value(); - IntPoint p0(a); IntPoint p1(b); IntPoint p2(c); + // sort points from top to bottom if (p0.y() > p1.y()) swap(p0, p1); if (p0.y() > p2.y()) @@ -469,41 +468,52 @@ void Painter::draw_triangle(const IntPoint& a, const IntPoint& b, const IntPoint if (p1.y() > p2.y()) swap(p1, p2); + // return if top and bottom points are on same line + if (p0.y() == p2.y()) + return; + + // return if top is below clip rect or bottom is above clip rect auto clip = clip_rect(); if (p0.y() >= clip.bottom()) return; if (p2.y() < clip.top()) return; - float dx01 = (float)(p1.x() - p0.x()) / (p1.y() - p0.y()); - float dx02 = (float)(p2.x() - p0.x()) / (p2.y() - p0.y()); - float dx12 = (float)(p2.x() - p1.x()) / (p2.y() - p1.y()); + int rgba = color.value(); + float dx02 = (float)(p2.x() - p0.x()) / (p2.y() - p0.y()); float x01 = p0.x(); float x02 = p0.x(); - int top = p0.y(); - if (top < clip.top()) { - x01 += dx01 * (clip.top() - top); - x02 += dx02 * (clip.top() - top); - top = clip.top(); - } + if (p0.y() != p1.y()) { // p0 and p1 are on different lines + float dx01 = (float)(p1.x() - p0.x()) / (p1.y() - p0.y()); - 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; + 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; + } + x01 += dx01; + x02 += dx02; } - x01 += dx01; - x02 += dx02; } - x02 = p0.x() + dx02 * (p1.y() - p0.y()); - float x12 = p1.x(); + // return if middle point and bottom point are on same line + if (p1.y() == p2.y()) + return; - top = p1.y(); + 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); |