summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGfx/Painter.cpp
diff options
context:
space:
mode:
authorStephan Unverwerth <s.unverwerth@gmx.de>2021-03-05 23:29:58 +0100
committerAndreas Kling <kling@serenityos.org>2021-03-06 15:03:44 +0100
commit87d19273bc258665ebdddeba471c960a25005966 (patch)
tree958bdf5cfc9b4de717c49b189f426d18c855deaa /Userland/Libraries/LibGfx/Painter.cpp
parent25e4a3467d443f38bf5dd89152b1853a30809a21 (diff)
downloadserenity-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.cpp54
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);