From 90ce9d81bcaa68195cddd7e57a48400ea84c23b0 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Tue, 16 Apr 2024 11:18:27 +0300 Subject: [PATCH] wg_engine: added math and polyline structures for geometry generating optimizations [issues 1479: lottie](#1479) --- src/renderer/wg_engine/tvgWgGeometry.cpp | 153 +++++++++++++++++++++++ src/renderer/wg_engine/tvgWgGeometry.h | 73 +++++++---- src/renderer/wg_engine/tvgWgRenderer.cpp | 4 + 3 files changed, 206 insertions(+), 24 deletions(-) diff --git a/src/renderer/wg_engine/tvgWgGeometry.cpp b/src/renderer/wg_engine/tvgWgGeometry.cpp index 9b80483f..77a2a2ad 100644 --- a/src/renderer/wg_engine/tvgWgGeometry.cpp +++ b/src/renderer/wg_engine/tvgWgGeometry.cpp @@ -22,6 +22,159 @@ #include "tvgWgGeometry.h" +//*********************************************************************** +// WgPolyline +//*********************************************************************** + +WgMath* WgGeometryData::gMath = nullptr; + +void WgMath::initialize() +{ + if (initialized) return; + initialized = true; + const uint32_t nPoints = 360; + sinus.reserve(360); + cosin.reserve(360); + for (uint32_t i = 0; i < nPoints; i++) { + float angle = i * (2 * M_PI) / nPoints; + sinus.push(sin(angle)); + cosin.push(cos(angle)); + } +}; + + +void WgMath::release() { + sinus.clear(); + cosin.clear(); +}; + +//*********************************************************************** +// WgPolyline +//*********************************************************************** + +WgPolyline::WgPolyline() +{ + pts.reserve(1024); + dist.reserve(1014); +} + + +void WgPolyline::appendPoint(WgPoint pt) +{ + if (pts.count > 0) { + float distance = pts.last().dist(pt); + if (distance > 0) { + // update min and max indexes + iminx = pts[iminx].x >= pt.x ? pts.count : iminx; + imaxx = pts[imaxx].x <= pt.x ? pts.count : imaxx; + iminy = pts[iminy].y >= pt.y ? pts.count : iminy; + imaxy = pts[imaxy].y <= pt.y ? pts.count : imaxy; + // update total length + len += distance; + // update points and distances + pts.push(pt); + dist.push(distance); + }; + } else { + // reset min and max indexes and total length + iminx = imaxx = iminy = imaxy = 0; + len = 0.0f; + // update points and distances + pts.push(pt); + dist.push(0.0f); + } +} + + +void WgPolyline::appendCubic(WgPoint p1, WgPoint p2, WgPoint p3) +{ + WgPoint p0 = pts.count > 0 ? pts.last() : WgPoint(0.0f, 0.0f); + size_t segs = ((uint32_t)(p0.dist(p3) / 8.0f)); + segs = segs == 0 ? 1 : segs; + for (size_t i = 1; i <= segs; i++) { + float t = i / (float)segs; + // get cubic spline interpolation coefficients + float t0 = 1.0f * (1.0f - t) * (1.0f - t) * (1.0f - t); + float t1 = 3.0f * (1.0f - t) * (1.0f - t) * t; + float t2 = 3.0f * (1.0f - t) * t * t; + float t3 = 1.0f * t * t * t; + appendPoint(p0 * t0 + p1 * t1 + p2 * t2 + p3 * t3); + } +} + + +void WgPolyline::trim(WgPolyline* polyline, float trimBegin, float trimEnd) const +{ + assert(polyline); + polyline->clear(); + float begLen = len * trimBegin; + float endLen = len * trimEnd; + float currentLength = 0.0f; + // find start point + uint32_t indexStart = 0; + WgPoint pointStart{}; + currentLength = 0.0f; + for (indexStart = 1; indexStart < pts.count; indexStart++) { + currentLength += dist[indexStart]; + if(currentLength >= begLen) { + float t = 1.0f - (currentLength - begLen) / dist[indexStart]; + pointStart = pts[indexStart-1] * (1.0f - t) + pts[indexStart] * t; + break; + } + } + if (indexStart >= pts.count) return; + // find end point + uint32_t indexEnd = 0; + WgPoint pointEnd{}; + currentLength = 0.0f; + for (indexEnd = 1; indexEnd < pts.count; indexEnd++) { + currentLength += dist[indexEnd]; + if(currentLength >= endLen) { + float t = 1.0f - (currentLength - endLen) / dist[indexEnd]; + pointEnd = pts[indexEnd-1] * (1.0f - t) + pts[indexEnd] * t; + break; + } + } + if (indexEnd >= pts.count) return; + // fill polyline + polyline->appendPoint(pointStart); + for (uint32_t i = indexStart; i <= indexEnd - 1; i++) + polyline->appendPoint(pts[i]); + polyline->appendPoint(pointEnd); +} + + +void WgPolyline::close() +{ + if (pts.count > 0) appendPoint(pts[0]); +} + + +bool WgPolyline::isClosed() const +{ + return (pts.count >= 2) && (pts[0].dist2(pts.last()) == 0.0f); +} + + +void WgPolyline::clear() +{ + // reset min and max indexes and total length + iminx = imaxx = iminy = imaxy = 0; + len = 0.0f; + // clear points and distances + pts.clear(); + dist.clear(); +} + + +void WgPolyline::getBBox(WgPoint& pmin, WgPoint& pmax) const +{ + pmin.x = pts[iminx].x; + pmin.y = pts[iminy].y; + pmax.x = pts[imaxx].x; + pmax.y = pts[imaxy].y; +} + //*********************************************************************** // WgGeometryData //*********************************************************************** diff --git a/src/renderer/wg_engine/tvgWgGeometry.h b/src/renderer/wg_engine/tvgWgGeometry.h index 21c061be..f7abe644 100644 --- a/src/renderer/wg_engine/tvgWgGeometry.h +++ b/src/renderer/wg_engine/tvgWgGeometry.h @@ -49,34 +49,59 @@ public: WgPoint operator / (const float c) const { return { x / c, y / c }; } WgPoint negative() const { return {-x, -y}; } - void negate() { x = -x; y = -y; } - float length() const { return sqrt(x*x + y*y); } - - float dot(const WgPoint& p) const { return x * p.x + y * p.y; } - float dist(const WgPoint& p) const - { - return sqrt( - (p.x - x)*(p.x - x) + - (p.y - y)*(p.y - y) - ); - } - - void normalize() - { - float rlen = 1.0f / length(); - x *= rlen; - y *= rlen; - } - - WgPoint normal() const - { - float rlen = 1.0f / length(); - return { x * rlen, y * rlen }; - } + inline void negate() { x = -x; y = -y; } + inline float length() const { return sqrt(x*x + y*y); } + inline float dot(const WgPoint& p) const { return x * p.x + y * p.y; } + inline float dist(const WgPoint& p) const { return sqrt(dist2(p)); } + inline float dist2(const WgPoint& p) const { return ((p.x - x)*(p.x - x) + (p.y - y)*(p.y - y)); } + inline void normalize() { float rlen = 1.0f / length(); x *= rlen; y *= rlen; } + inline WgPoint normal() const { float rlen = 1.0f / length(); return { x * rlen, y * rlen }; } + inline WgPoint lerp(const WgPoint& p, float t) const { return { x + (p.x - x) * t, y + (p.y - y) * t }; }; }; + +struct WgMath +{ + Array sinus; + Array cosin; + bool initialized{}; + + void initialize(); + void release(); +}; + + +struct WgPolyline +{ + Array pts; + Array dist; + // polyline bbox points indexes + uint32_t iminx{}; + uint32_t iminy{}; + uint32_t imaxx{}; + uint32_t imaxy{}; + // total polyline length + float len{}; + + WgPolyline(); + + void appendPoint(WgPoint pt); + void appendCubic(WgPoint p1, WgPoint p2, WgPoint p3); + + void trim(WgPolyline* polyline, float trimBegin, float trimEnd) const; + + void close(); + void clear(); + + bool isClosed() const; + void getBBox(WgPoint& pmin, WgPoint& pmax) const; +}; + + struct WgGeometryData { + static WgMath* gMath; + Array positions{}; Array texCoords{}; Array indexes{}; diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index 09bd893e..b960056a 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -49,11 +49,15 @@ void WgRenderer::initialize() mBlendMethodPool.initialize(mContext); mCompositeMethodPool.initialize(mContext); WgMeshDataGroup::MeshDataPool = new WgMeshDataPool(); + WgGeometryData::gMath = new WgMath(); + WgGeometryData::gMath->initialize(); } void WgRenderer::release() { + WgGeometryData::gMath->release(); + delete WgGeometryData::gMath; mRenderDataShapePool.release(mContext); WgMeshDataGroup::MeshDataPool->release(mContext); delete WgMeshDataGroup::MeshDataPool;