summaryrefslogtreecommitdiffstats
path: root/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp')
-rw-r--r--thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp272
1 files changed, 50 insertions, 222 deletions
diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
index dbcfa754f3..d58dd9e3c5 100644
--- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
+++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-#include <math.h>
+#include "tvgMath.h"
#include "tvgSwCommon.h"
@@ -28,173 +28,9 @@
/* Internal Class Implementation */
/************************************************************************/
-//clz: count leading zero’s
-#if defined(_MSC_VER) && !defined(__clang__)
- #include <intrin.h>
- static uint32_t __inline _clz(uint32_t value)
- {
- unsigned long leadingZero = 0;
- if (_BitScanReverse(&leadingZero, value)) return 31 - leadingZero;
- else return 32;
- }
-#else
- #define _clz(x) __builtin_clz((x))
-#endif
-
-
-constexpr SwFixed CORDIC_FACTOR = 0xDBD95B16UL; //the Cordic shrink factor 0.858785336480436 * 2^32
-
-//this table was generated for SW_FT_PI = 180L << 16, i.e. degrees
-constexpr static auto ATAN_MAX = 23;
-constexpr static SwFixed ATAN_TBL[] = {
- 1740967L, 919879L, 466945L, 234379L, 117304L, 58666L, 29335L,
- 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L,
- 57L, 29L, 14L, 7L, 4L, 2L, 1L};
-
-static inline SwCoord SATURATE(const SwCoord x)
-{
- return (x >> (sizeof(SwCoord) * 8 - 1));
-}
-
-
-static inline SwFixed PAD_ROUND(const SwFixed x, int32_t n)
-{
- return (((x) + ((n)/2)) & ~((n)-1));
-}
-
-
-static SwCoord _downscale(SwFixed x)
+static float TO_RADIAN(SwFixed angle)
{
- //multiply a give value by the CORDIC shrink factor
- auto s = abs(x);
- int64_t t = (s * static_cast<int64_t>(CORDIC_FACTOR)) + 0x100000000UL;
- s = static_cast<SwFixed>(t >> 32);
- if (x < 0) s = -s;
- return s;
-}
-
-
-static int32_t _normalize(SwPoint& pt)
-{
- /* the highest bit in overflow-safe vector components
- MSB of 0.858785336480436 * sqrt(0.5) * 2^30 */
- constexpr auto SAFE_MSB = 29;
-
- auto v = pt;
-
- //High order bit(MSB)
- int32_t shift = 31 - _clz(abs(v.x) | abs(v.y));
-
- if (shift <= SAFE_MSB) {
- shift = SAFE_MSB - shift;
- pt.x = static_cast<SwCoord>((unsigned long)v.x << shift);
- pt.y = static_cast<SwCoord>((unsigned long)v.y << shift);
- } else {
- shift -= SAFE_MSB;
- pt.x = v.x >> shift;
- pt.y = v.y >> shift;
- shift = -shift;
- }
- return shift;
-}
-
-
-static void _polarize(SwPoint& pt)
-{
- auto v = pt;
- SwFixed theta;
-
- //Get the vector into [-PI/4, PI/4] sector
- if (v.y > v.x) {
- if (v.y > -v.x) {
- auto tmp = v.y;
- v.y = -v.x;
- v.x = tmp;
- theta = SW_ANGLE_PI2;
- } else {
- theta = v.y > 0 ? SW_ANGLE_PI : -SW_ANGLE_PI;
- v.x = -v.x;
- v.y = -v.y;
- }
- } else {
- if (v.y < -v.x) {
- theta = -SW_ANGLE_PI2;
- auto tmp = -v.y;
- v.y = v.x;
- v.x = tmp;
- } else {
- theta = 0;
- }
- }
-
- auto atan = ATAN_TBL;
- uint32_t i;
- SwFixed j;
-
- //Pseudorotations. with right shifts
- for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) {
- if (v.y > 0) {
- auto tmp = v.x + ((v.y + j) >> i);
- v.y = v.y - ((v.x + j) >> i);
- v.x = tmp;
- theta += *atan++;
- } else {
- auto tmp = v.x - ((v.y + j) >> i);
- v.y = v.y + ((v.x + j) >> i);
- v.x = tmp;
- theta -= *atan++;
- }
- }
-
- //round theta
- if (theta >= 0) theta = PAD_ROUND(theta, 32);
- else theta = -PAD_ROUND(-theta, 32);
-
- pt.x = v.x;
- pt.y = theta;
-}
-
-
-static void _rotate(SwPoint& pt, SwFixed theta)
-{
- SwFixed x = pt.x;
- SwFixed y = pt.y;
-
- //Rotate inside [-PI/4, PI/4] sector
- while (theta < -SW_ANGLE_PI4) {
- auto tmp = y;
- y = -x;
- x = tmp;
- theta += SW_ANGLE_PI2;
- }
-
- while (theta > SW_ANGLE_PI4) {
- auto tmp = -y;
- y = x;
- x = tmp;
- theta -= SW_ANGLE_PI2;
- }
-
- auto atan = ATAN_TBL;
- uint32_t i;
- SwFixed j;
-
- for (i = 1, j = 1; i < ATAN_MAX; j <<= 1, ++i) {
- if (theta < 0) {
- auto tmp = x + ((y + j) >> i);
- y = y - ((x + j) >> i);
- x = tmp;
- theta += *atan++;
- } else {
- auto tmp = x - ((y + j) >> i);
- y = y + ((x + j) >> i);
- x = tmp;
- theta -= *atan++;
- }
- }
-
- pt.x = static_cast<SwCoord>(x);
- pt.y = static_cast<SwCoord>(y);
+ return (float(angle) / 65536.0f) * (MATH_PI / 180.0f);
}
@@ -214,11 +50,17 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw
auto d2 = base[1] - base[2];
auto d3 = base[0] - base[1];
+ if (d1 == d2 || d2 == d3) {
+ if (d3.small()) angleIn = angleMid = angleOut = 0;
+ else angleIn = angleMid = angleOut = mathAtan(d3);
+ return true;
+ }
+
if (d1.small()) {
if (d2.small()) {
if (d3.small()) {
- //basically a point.
- //do nothing to retain original direction
+ angleIn = angleMid = angleOut = 0;
+ return true;
} else {
angleIn = angleMid = angleOut = mathAtan(d3);
}
@@ -320,77 +162,63 @@ int64_t mathMulDiv(int64_t a, int64_t b, int64_t c)
void mathRotate(SwPoint& pt, SwFixed angle)
{
- if (angle == 0 || (pt.x == 0 && pt.y == 0)) return;
-
- auto v = pt;
- auto shift = _normalize(v);
+ if (angle == 0 || pt.zero()) return;
- auto theta = angle;
- _rotate(v, theta);
+ Point v = pt.toPoint();
- v.x = _downscale(v.x);
- v.y = _downscale(v.y);
+ auto radian = TO_RADIAN(angle);
+ auto cosv = cosf(radian);
+ auto sinv = sinf(radian);
- if (shift > 0) {
- auto half = static_cast<int32_t>(1L << (shift - 1));
- pt.x = (v.x + half + SATURATE(v.x)) >> shift;
- pt.y = (v.y + half + SATURATE(v.y)) >> shift;
- } else {
- shift = -shift;
- pt.x = static_cast<SwCoord>((unsigned long)v.x << shift);
- pt.y = static_cast<SwCoord>((unsigned long)v.y << shift);
- }
+ pt.x = SwCoord(roundf((v.x * cosv - v.y * sinv) * 64.0f));
+ pt.y = SwCoord(roundf((v.x * sinv + v.y * cosv) * 64.0f));
}
+
SwFixed mathTan(SwFixed angle)
{
- SwPoint v = {CORDIC_FACTOR >> 8, 0};
- _rotate(v, angle);
- return mathDivide(v.y, v.x);
+ if (angle == 0) return 0;
+ return SwFixed(tanf(TO_RADIAN(angle)) * 65536.0f);
}
SwFixed mathAtan(const SwPoint& pt)
{
- if (pt.x == 0 && pt.y == 0) return 0;
-
- auto v = pt;
- _normalize(v);
- _polarize(v);
-
- return v.y;
+ if (pt.zero()) return 0;
+ return SwFixed(atan2f(TO_FLOAT(pt.y), TO_FLOAT(pt.x)) * (180.0f / MATH_PI) * 65536.0f);
}
SwFixed mathSin(SwFixed angle)
{
+ if (angle == 0) return 0;
return mathCos(SW_ANGLE_PI2 - angle);
}
SwFixed mathCos(SwFixed angle)
{
- SwPoint v = {CORDIC_FACTOR >> 8, 0};
- _rotate(v, angle);
- return (v.x + 0x80L) >> 8;
+ return SwFixed(cosf(TO_RADIAN(angle)) * 65536.0f);
}
SwFixed mathLength(const SwPoint& pt)
{
- auto v = pt;
+ if (pt.zero()) return 0;
//trivial case
- if (v.x == 0) return abs(v.y);
- if (v.y == 0) return abs(v.x);
-
- //general case
- auto shift = _normalize(v);
- _polarize(v);
- v.x = _downscale(v.x);
-
- if (shift > 0) return (v.x + (static_cast<SwFixed>(1) << (shift -1))) >> shift;
- return static_cast<SwFixed>((uint32_t)v.x << -shift);
+ if (pt.x == 0) return abs(pt.y);
+ if (pt.y == 0) return abs(pt.x);
+
+ auto v = pt.toPoint();
+ //return static_cast<SwFixed>(sqrtf(v.x * v.x + v.y * v.y) * 65536.0f);
+
+ /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm.
+ With alpha = 1, beta = 3/8, giving results with the largest error less
+ than 7% compared to the exact value. */
+ if (v.x < 0) v.x = -v.x;
+ if (v.y < 0) v.y = -v.y;
+ return static_cast<SwFixed>((v.x > v.y) ? (v.x + v.y * 0.375f) : (v.y + v.x * 0.375f));
}
@@ -401,22 +229,22 @@ void mathSplitCubic(SwPoint* base)
base[6].x = base[3].x;
c = base[1].x;
d = base[2].x;
- base[1].x = a = (base[0].x + c) / 2;
- base[5].x = b = (base[3].x + d) / 2;
- c = (c + d) / 2;
- base[2].x = a = (a + c) / 2;
- base[4].x = b = (b + c) / 2;
- base[3].x = (a + b) / 2;
+ base[1].x = a = (base[0].x + c) >> 1;
+ base[5].x = b = (base[3].x + d) >> 1;
+ c = (c + d) >> 1;
+ base[2].x = a = (a + c) >> 1;
+ base[4].x = b = (b + c) >> 1;
+ base[3].x = (a + b) >> 1;
base[6].y = base[3].y;
c = base[1].y;
d = base[2].y;
- base[1].y = a = (base[0].y + c) / 2;
- base[5].y = b = (base[3].y + d) / 2;
- c = (c + d) / 2;
- base[2].y = a = (a + c) / 2;
- base[4].y = b = (b + c) / 2;
- base[3].y = (a + b) / 2;
+ base[1].y = a = (base[0].y + c) >> 1;
+ base[5].y = b = (base[3].y + d) >> 1;
+ c = (c + d) >> 1;
+ base[2].y = a = (a + c) >> 1;
+ base[4].y = b = (b + c) >> 1;
+ base[3].y = (a + b) >> 1;
}