From ac7d208ed8e4651c93ce1b2384070fccac9b6cb6 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Sun, 1 Sep 2024 22:36:18 +0200 Subject: [PATCH] sw_engine: handle small cubics During the stroke's outline calculation, the function handling small cubics set all angles to zero. Such cases should be ignored, as further processing caused errors - when the cubic was small but not zero, setting the angles to zero resulted in incorrect outlines. @Issue: https://github.com/godotengine/godot/issues/96262 --- src/renderer/sw_engine/tvgSwCommon.h | 3 ++- src/renderer/sw_engine/tvgSwMath.cpp | 19 ++++++++++++------- src/renderer/sw_engine/tvgSwStroke.cpp | 16 +++++++++++----- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/renderer/sw_engine/tvgSwCommon.h b/src/renderer/sw_engine/tvgSwCommon.h index 893e9beca..158fe8ecd 100644 --- a/src/renderer/sw_engine/tvgSwCommon.h +++ b/src/renderer/sw_engine/tvgSwCommon.h @@ -491,7 +491,8 @@ SwFixed mathSin(SwFixed angle); void mathSplitCubic(SwPoint* base); SwFixed mathDiff(SwFixed angle1, SwFixed angle2); SwFixed mathLength(const SwPoint& pt); -bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); +bool mathSmallCubic(const SwPoint* base); +bool mathFlatCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut); SwFixed mathMean(SwFixed angle1, SwFixed angle2); SwPoint mathTransform(const Point* to, const Matrix& transform); bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion, bool fastTrack); diff --git a/src/renderer/sw_engine/tvgSwMath.cpp b/src/renderer/sw_engine/tvgSwMath.cpp index 1093edd62..b311be05f 100644 --- a/src/renderer/sw_engine/tvgSwMath.cpp +++ b/src/renderer/sw_engine/tvgSwMath.cpp @@ -44,7 +44,17 @@ SwFixed mathMean(SwFixed angle1, SwFixed angle2) } -bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut) +bool mathSmallCubic(const SwPoint* base) +{ + auto d1 = base[2] - base[3]; + auto d2 = base[1] - base[2]; + auto d3 = base[0] - base[1]; + + return d1.small() && d2.small() && d3.small(); +} + + +bool mathFlatCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut) { auto d1 = base[2] - base[3]; auto d2 = base[1] - base[2]; @@ -52,12 +62,7 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw if (d1.small()) { if (d2.small()) { - if (d3.small()) { - angleIn = angleMid = angleOut = 0; - return true; - } else { - angleIn = angleMid = angleOut = mathAtan(d3); - } + angleIn = angleMid = angleOut = mathAtan(d3); } else { if (d3.small()) { angleIn = angleMid = angleOut = mathAtan(d2); diff --git a/src/renderer/sw_engine/tvgSwStroke.cpp b/src/renderer/sw_engine/tvgSwStroke.cpp index 575d12951..4679b72cc 100644 --- a/src/renderer/sw_engine/tvgSwStroke.cpp +++ b/src/renderer/sw_engine/tvgSwStroke.cpp @@ -441,11 +441,17 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl //initialize with current direction angleIn = angleOut = angleMid = stroke.angleIn; - if (arc < limit && !mathSmallCubic(arc, angleIn, angleMid, angleOut)) { - if (stroke.firstPt) stroke.angleIn = angleIn; - mathSplitCubic(arc); - arc += 3; - continue; + if (arc < limit) { + if (mathSmallCubic(arc)) { + arc -= 3; + continue; + } + if (!mathFlatCubic(arc, angleIn, angleMid, angleOut)) { + if (stroke.firstPt) stroke.angleIn = angleIn; + mathSplitCubic(arc); + arc += 3; + continue; + } } if (firstArc) {