diff options
Diffstat (limited to 'thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp')
-rw-r--r-- | thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp | 272 |
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; } |