From 84c04119290d645e987928b7c0db8c27fff25162 Mon Sep 17 00:00:00 2001 From: subhransu mohanty Date: Mon, 23 Jul 2018 09:33:56 +0900 Subject: [PATCH] lottie/vector: refactor vpath class to use vcow_ptr Change-Id: Ib16da52a8a97bbee87766ee362e1d6e5678ac305 --- src/vector/vpath.cpp | 410 +++++++++++++++++---------------------------------- src/vector/vpath.h | 132 ++++++++++++++--- 2 files changed, 246 insertions(+), 296 deletions(-) diff --git a/src/vector/vpath.cpp b/src/vector/vpath.cpp index 697bd54..d8e2e13 100644 --- a/src/vector/vpath.cpp +++ b/src/vector/vpath.cpp @@ -7,56 +7,34 @@ V_BEGIN_NAMESPACE -struct VPathData -{ - VPathData():ref(-1), - m_points(), - m_elements(), - m_segments(0), - mStartPoint(), - mNewSegment(true){} - - void copy(VPathData *o); - void moveTo(const VPointF &pt); - void lineTo(const VPointF &pt); - void cubicTo(const VPointF &c1, const VPointF &c2, const VPointF &e); - void close(); - void reset(); - void checkNewSegment(); - int segments() const; - void transform(const VMatrix &m); - RefCount ref; - std::vector m_points; - std::vector m_elements; - int m_segments; - VPointF mStartPoint; - bool mNewSegment; -}; - - -void VPathData::transform(const VMatrix &m) +VPath::VPathData::VPathData():m_points(), + m_elements(), + m_segments(0), + mStartPoint(), + mNewSegment(true){} + +VPath::VPathData::VPathData(const VPathData &o):m_points(o.m_points), + m_elements(o.m_elements), + m_segments(o.m_segments), + mStartPoint(o.mStartPoint), + mNewSegment(o.mNewSegment){} + +void VPath::VPathData::transform(const VMatrix &m) { for(auto &i : m_points) { i = m.map(i); } } -void VPathData::checkNewSegment() +void VPath::VPathData::checkNewSegment() { if (mNewSegment) { moveTo(VPointF(0,0)); mNewSegment = false; } } -void VPathData::copy(VPathData *o) -{ - m_points = o->m_points; - m_elements = o->m_elements; - m_segments = o->m_segments; - mStartPoint = o->mStartPoint; -} -void VPathData::moveTo(const VPointF &p) +void VPath::VPathData::moveTo(const VPointF &p) { mStartPoint = p; mNewSegment = false; @@ -64,13 +42,13 @@ void VPathData::moveTo(const VPointF &p) m_points.push_back(p); m_segments++; } -void VPathData::lineTo(const VPointF &p) +void VPath::VPathData::lineTo(const VPointF &p) { checkNewSegment(); m_elements.push_back(VPath::Element::LineTo); m_points.push_back(p); } -void VPathData::cubicTo(const VPointF &c1, const VPointF &c2, const VPointF &e) +void VPath::VPathData::cubicTo(const VPointF &c1, const VPointF &c2, const VPointF &e) { checkNewSegment(); m_elements.push_back(VPath::Element::CubicTo); @@ -79,8 +57,10 @@ void VPathData::cubicTo(const VPointF &c1, const VPointF &c2, const VPointF &e) m_points.push_back(e); } -void VPathData::close() +void VPath::VPathData::close() { + if (isEmpty()) return; + const VPointF &lastPt = m_points.back(); if (!fuzzyCompare(mStartPoint, lastPt)) { lineTo(mStartPoint); @@ -89,144 +69,149 @@ void VPathData::close() mNewSegment = true; } -void VPathData::reset() +void VPath::VPathData::reset() { + if (isEmpty()) return; + m_elements.clear(); m_points.clear(); m_segments = 0; } -int VPathData::segments() const +int VPath::VPathData::segments() const { - return m_segments; + return m_segments + 1; } - -static const struct VPathData shared_empty; - -inline void VPath::cleanUp(VPathData *d) +void VPath::VPathData::reserve(int num_elm) { - delete d; + m_elements.reserve(num_elm); + m_points.reserve(2 * num_elm); } -void VPath::detach() -{ - if (d->ref.isShared()) - *this = copy(); -} +static VPointF curvesForArc(const VRectF &, float, float, VPointF *, int *); +static constexpr float PATH_KAPPA = 0.5522847498; -VPath VPath::copy() const +void VPath::VPathData::arcTo(const VRectF &rect, float startAngle, float sweepLength, bool forceMoveTo) { - VPath other; - - other.d = new VPathData; - other.d->m_points = d->m_points; - other.d->m_elements = d->m_elements; - other.d->m_segments = d->m_segments; - other.d->ref.setOwned(); - return other; -} - -VPath::~VPath() -{ - if (!d->ref.deref()) - cleanUp(d); -} + int point_count = 0; + VPointF pts[15]; + VPointF curve_start = curvesForArc(rect, startAngle, sweepLength, pts, &point_count); -VPath::VPath() - : d(const_cast(&shared_empty)) -{ + if (isEmpty() || forceMoveTo) { + moveTo(curve_start); + } else { + lineTo(curve_start); + } + for (int i=0; iref.ref(); + addOval(VRectF(cx-radius, cy-radius, 2*radius, 2*radius) , dir); } -VPath::VPath(VPath &&other): d(other.d) +void VPath::VPathData::addOval(const VRectF &rect, VPath::Direction dir) { - other.d = const_cast(&shared_empty); -} + if (rect.isNull()) return; -VPath &VPath::operator=(const VPath &other) -{ - other.d->ref.ref(); - if (!d->ref.deref()) - cleanUp(d); + float x = rect.x(); + float y = rect.y(); - d = other.d; - return *this; -} + float w = rect.width(); + float w2 = rect.width() / 2; + float w2k = w2 * PATH_KAPPA; -inline VPath &VPath::operator=(VPath &&other) -{ - if (!d->ref.deref()) - cleanUp(d); - d = other.d; - other.d = const_cast(&shared_empty); - return *this; -} + float h = rect.height(); + float h2 = rect.height() / 2; + float h2k = h2 * PATH_KAPPA; -bool VPath::isEmpty()const -{ - return d->m_elements.empty(); -} -void VPath::close() -{ - if (isEmpty()) return; - detach(); - d->close(); + if (dir == VPath::Direction::CW) { + // moveto 12 o'clock. + moveTo(VPointF(x+w2, y)); + // 12 -> 3 o'clock + cubicTo(VPointF(x + w2 + w2k, y), VPointF(x + w, y + h2 - h2k), VPointF(x + w, y + h2)); + // 3 -> 6 o'clock + cubicTo(VPointF(x + w, y + h2 + h2k), VPointF(x + w2 + w2k, y + h), VPointF(x + w2, y + h)); + // 6 -> 9 o'clock + cubicTo(VPointF(x + w2 - w2k, y + h), VPointF(x, y + h2 + h2k), VPointF(x , y + h2)); + // 9 -> 12 o'clock + cubicTo(VPointF(x, y + h2 - h2k), VPointF(x + w2 - w2k, y), VPointF(x + w2, y)); + } else { + // moveto 12 o'clock. + moveTo(VPointF(x+w2, y)); + // 12 -> 9 o'clock + cubicTo(VPointF(x + w2 - w2k, y), VPointF(x, y + h2 - h2k), VPointF(x , y + h2)); + // 9 -> 6 o'clock + cubicTo(VPointF(x, y + h2 + h2k), VPointF(x + w2 - w2k, y + h), VPointF(x + w2, y + h)); + // 6 -> 3 o'clock + cubicTo(VPointF(x + w2 + w2k, y + h), VPointF(x + w, y + h2 + h2k), VPointF(x + w, y + h2)); + // 3 -> 12 o'clock + cubicTo(VPointF(x + w, y + h2 - h2k), VPointF(x + w2 + w2k, y), VPointF(x+w2, y)); + } } -void VPath::reset() +void VPath::VPathData::addRect(const VRectF &rect, VPath::Direction dir) { - if (isEmpty()) return; - detach(); - d->reset(); -} + if (rect.isNull()) return; -void VPath::moveTo(const VPointF &p) -{ - detach(); - d->moveTo(p); -} + float x = rect.x(); + float y = rect.y(); + float w = rect.width(); + float h = rect.height(); -void VPath::lineTo(const VPointF &p) -{ - detach(); - d->lineTo(p); + if (dir == VPath::Direction::CW) { + moveTo(VPointF(x + w, y)); + lineTo(VPointF(x + w, y + h)); + lineTo(VPointF(x , y + h)); + lineTo(VPointF(x , y)); + close(); + } else { + moveTo(VPointF(x + w, y)); + lineTo(VPointF(x , y)); + lineTo(VPointF(x , y + h)); + lineTo(VPointF(x + w, y + h)); + close(); + } } -void VPath::cubicTo(const VPointF &c1, const VPointF &c2, const VPointF &e) +void VPath::VPathData::addRoundRect(const VRectF &rect, float rx, float ry, VPath::Direction dir) { - detach(); - d->cubicTo(c1, c2, e); -} + if (vCompare(rx, 0.f) || vCompare(ry, 0.f)) { + addRect(rect, dir); + return; + } -void VPath::reserve(int num_elm) -{ - detach(); - d->m_elements.reserve(num_elm); - d->m_points.reserve(num_elm); -} + float x = rect.x(); + float y = rect.y(); + float w = rect.width(); + float h = rect.height(); + // clamp the rx and ry radius value. + rx = 2*rx; + ry = 2*ry; + if (rx > w) rx = w; + if (ry > h) ry = h; -const std::vector &VPath::elements() const -{ - return d->m_elements; -} -const std::vector &VPath::points() const -{ - return d->m_points; -} -int VPath::segments() const -{ - return d->m_segments + 1; + if (dir == VPath::Direction::CW) { + moveTo(VPointF(x + w, y + ry/2.f)); + arcTo(VRectF(x + w - rx, y + h - ry, rx, ry), 0 , -90, false); + arcTo(VRectF(x, y + h - ry, rx, ry), -90 , -90, false); + arcTo(VRectF(x, y, rx, ry), -180 , -90, false); + arcTo(VRectF(x + w - rx, y, rx, ry), -270 , -90, false); + close(); + } else { + moveTo(VPointF(x + w, y + ry/2.f)); + arcTo(VRectF(x + w - rx, y , rx, ry), 0 , 90, false); + arcTo(VRectF(x, y, rx, ry), 90 , 90, false); + arcTo(VRectF(x, y + h - ry, rx, ry), 180 , 90, false); + arcTo(VRectF(x + w - rx, y + h - ry, rx, ry), 270 , 90, false); + close(); + } } -#define PATH_KAPPA 0.5522847498 - static float tForArcAngle(float angle); void findEllipseCoords(const VRectF &r, float angle, float length, VPointF* startPoint, VPointF *endPoint) @@ -454,132 +439,6 @@ curvesForArc(const VRectF &rect, float startAngle, float sweepLength, return startPoint; } -void VPath::arcTo(const VRectF &rect, float startAngle, float sweepLength, bool forceMoveTo) -{ - detach(); - - int point_count = 0; - VPointF pts[15]; - VPointF curve_start = curvesForArc(rect, startAngle, sweepLength, pts, &point_count); - - if (isEmpty() || forceMoveTo) { - d->moveTo(curve_start); - } else { - d->lineTo(curve_start); - } - for (int i=0; icubicTo(pts[i], pts[i+1], pts[i+2]); - } -} - -void VPath::addCircle(float cx, float cy, float radius, VPath::Direction dir) -{ - addOval(VRectF(cx-radius, cy-radius, 2*radius, 2*radius) , dir); -} - -void VPath::addOval(const VRectF &rect, VPath::Direction dir) -{ - if (rect.isNull()) return; - - detach(); - - float x = rect.x(); - float y = rect.y(); - - float w = rect.width(); - float w2 = rect.width() / 2; - float w2k = w2 * PATH_KAPPA; - - float h = rect.height(); - float h2 = rect.height() / 2; - float h2k = h2 * PATH_KAPPA; - - - if (dir == VPath::Direction::CW) { - // moveto 12 o'clock. - d->moveTo(VPointF(x+w2, y)); - // 12 -> 3 o'clock - d->cubicTo(VPointF(x + w2 + w2k, y), VPointF(x + w, y + h2 - h2k), VPointF(x + w, y + h2)); - // 3 -> 6 o'clock - d->cubicTo(VPointF(x + w, y + h2 + h2k), VPointF(x + w2 + w2k, y + h), VPointF(x + w2, y + h)); - // 6 -> 9 o'clock - d->cubicTo(VPointF(x + w2 - w2k, y + h), VPointF(x, y + h2 + h2k), VPointF(x , y + h2)); - // 9 -> 12 o'clock - d->cubicTo(VPointF(x, y + h2 - h2k), VPointF(x + w2 - w2k, y), VPointF(x + w2, y)); - } else { - // moveto 12 o'clock. - d->moveTo(VPointF(x+w2, y)); - // 12 -> 9 o'clock - d->cubicTo(VPointF(x + w2 - w2k, y), VPointF(x, y + h2 - h2k), VPointF(x , y + h2)); - // 9 -> 6 o'clock - d->cubicTo(VPointF(x, y + h2 + h2k), VPointF(x + w2 - w2k, y + h), VPointF(x + w2, y + h)); - // 6 -> 3 o'clock - d->cubicTo(VPointF(x + w2 + w2k, y + h), VPointF(x + w, y + h2 + h2k), VPointF(x + w, y + h2)); - // 3 -> 12 o'clock - d->cubicTo(VPointF(x + w, y + h2 - h2k), VPointF(x + w2 + w2k, y), VPointF(x+w2, y)); - } -} - -void VPath::addRect(const VRectF &rect, VPath::Direction dir) -{ - if (rect.isNull()) return; - - detach(); - - float x = rect.x(); - float y = rect.y(); - float w = rect.width(); - float h = rect.height(); - - if (dir == VPath::Direction::CW) { - moveTo(VPointF(x + w, y)); - lineTo(VPointF(x + w, y + h)); - lineTo(VPointF(x , y + h)); - lineTo(VPointF(x , y)); - close(); - } else { - moveTo(VPointF(x + w, y)); - lineTo(VPointF(x , y)); - lineTo(VPointF(x , y + h)); - lineTo(VPointF(x + w, y + h)); - close(); - } -} - -void VPath::addRoundRect(const VRectF &rect, float rx, float ry, VPath::Direction dir) -{ - if (vCompare(rx, 0.f) || vCompare(ry, 0.f)) { - addRect(rect, dir); - return; - } - - float x = rect.x(); - float y = rect.y(); - float w = rect.width(); - float h = rect.height(); - // clamp the rx and ry radius value. - rx = 2*rx; - ry = 2*ry; - if (rx > w) rx = w; - if (ry > h) ry = h; - - if (dir == VPath::Direction::CW) { - moveTo(VPointF(x + w, y + ry/2.f)); - arcTo(VRectF(x + w - rx, y + h - ry, rx, ry), 0 , -90, false); - arcTo(VRectF(x, y + h - ry, rx, ry), -90 , -90, false); - arcTo(VRectF(x, y, rx, ry), -180 , -90, false); - arcTo(VRectF(x + w - rx, y, rx, ry), -270 , -90, false); - close(); - } else { - moveTo(VPointF(x + w, y + ry/2.f)); - arcTo(VRectF(x + w - rx, y , rx, ry), 0 , 90, false); - arcTo(VRectF(x, y, rx, ry), 90 , 90, false); - arcTo(VRectF(x, y + h - ry, rx, ry), 180 , 90, false); - arcTo(VRectF(x + w - rx, y + h - ry, rx, ry), 270 , 90, false); - close(); - } -} - void VPath::addPolystarStar(float startAngle, float cx, float cy, float points, float innerRadius, float outerRadius, float innerRoundness, float outerRoundness, @@ -617,7 +476,9 @@ void VPath::addPolystarStar(float startAngle, float cx, float cy, float points, currentAngle += halfAnglePerPoint * angleDir; } - moveTo(VPointF(x + cx, y + cy)); + VPathData &ref = d.write(); + + ref.moveTo(VPointF(x + cx, y + cy)); for (int i = 0; i < numPoints; i++) { float radius = longSegment ? outerRadius : innerRadius; @@ -634,7 +495,7 @@ void VPath::addPolystarStar(float startAngle, float cx, float cy, float points, y = (float) (radius * sin(currentAngle)); if (innerRoundness == 0 && outerRoundness == 0) { - lineTo(VPointF(x + cx, y + cy)); + ref.lineTo(VPointF(x + cx, y + cy)); } else { float cp1Theta = (float) (atan2(previousY, previousX) - M_PI / 2.0 * angleDir); float cp1Dx = (float) cos(cp1Theta); @@ -661,9 +522,9 @@ void VPath::addPolystarStar(float startAngle, float cx, float cy, float points, cp2y *= partialPointAmount; } - cubicTo(VPointF(previousX - cp1x + cx, previousY - cp1y + cy), - VPointF(x + cp2x + cx, y + cp2y + cy), - VPointF(x + cx, y + cy)); + ref.cubicTo(VPointF(previousX - cp1x + cx, previousY - cp1y + cy), + VPointF(x + cp2x + cx, y + cp2y + cy), + VPointF(x + cx, y + cy)); } currentAngle += dTheta * angleDir; @@ -729,11 +590,4 @@ void VPath::addPolystarPolygon(float startAngle, float cx, float cy, float point close(); } -void VPath::transform(const VMatrix &m) -{ - if (isEmpty()) return; - detach(); - d->transform(m); -} - V_END_NAMESPACE diff --git a/src/vector/vpath.h b/src/vector/vpath.h index 2fe0b9d..68acc52 100644 --- a/src/vector/vpath.h +++ b/src/vector/vpath.h @@ -4,6 +4,7 @@ #include "vrect.h" #include "vmatrix.h" #include +#include V_BEGIN_NAMESPACE @@ -22,24 +23,18 @@ public: CubicTo, Close }; - ~VPath(); - VPath(); - VPath(const VPath &path); - VPath(VPath &&other); - VPath &operator=(const VPath &); - VPath &operator=(VPath &&other); bool isEmpty()const; void moveTo(const VPointF &p); - inline void moveTo(float x, float y); + void moveTo(float x, float y); void lineTo(const VPointF &p); - inline void lineTo(float x, float y); + void lineTo(float x, float y); void cubicTo(const VPointF &c1, const VPointF &c2, const VPointF &e); - inline void cubicTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey); + void cubicTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey); void arcTo(const VRectF &rect, float startAngle, float sweepLength, bool forceMoveTo); void close(); void reset(); void reserve(int num_elm); - + int segments() const; void addCircle(float cx, float cy, float radius, VPath::Direction dir = Direction::CW); void addOval(const VRectF &rect, VPath::Direction dir = Direction::CW); void addRoundRect(const VRectF &rect, float rx, float ry, VPath::Direction dir = Direction::CW); @@ -51,19 +46,80 @@ public: void addPolystarPolygon(float startAngle, float cx, float cy, float points, float radius, float roundness, VPath::Direction dir = Direction::CW); - void transform(const VMatrix &m); const std::vector &elements() const; const std::vector &points() const; private: - friend class VRaster; - int segments() const; - VPath copy() const; - void detach(); - void cleanUp(VPathData *x); - VPathData *d; + struct VPathData { + VPathData(); + VPathData(const VPathData &o); + bool isEmpty() const { return m_elements.empty();} + void moveTo(const VPointF &pt); + void lineTo(const VPointF &pt); + void cubicTo(const VPointF &c1, const VPointF &c2, const VPointF &e); + void close(); + void reset(); + void reserve(int num_elm); + void checkNewSegment(); + int segments() const; + void transform(const VMatrix &m); + void addRoundRect(const VRectF &, float, float, VPath::Direction); + void addRect(const VRectF &, VPath::Direction); + void arcTo(const VRectF&, float, float, bool); + void addCircle(float, float, float, VPath::Direction); + void addOval(const VRectF &, VPath::Direction); + const std::vector &elements() const { return m_elements;} + const std::vector &points() const {return m_points;} + std::vector m_points; + std::vector m_elements; + int m_segments; + VPointF mStartPoint; + bool mNewSegment; + }; + + vcow_ptr d; }; +inline bool VPath::isEmpty()const +{ + return d->isEmpty(); +} + +inline void VPath::moveTo(const VPointF &p) +{ + d.write().moveTo(p); +} + +inline void VPath::lineTo(const VPointF &p) +{ + d.write().lineTo(p); +} + +inline void VPath::close() +{ + d.write().close(); +} + +inline void VPath::reset() +{ + d.write().reset(); +} + +inline void VPath::reserve(int num_elm) +{ + d.write().reserve(num_elm); +} + +inline int VPath::segments() const +{ + return d->segments(); +} + +inline void VPath::cubicTo(const VPointF &c1, const VPointF &c2, const VPointF &e) +{ + d.write().cubicTo(c1, c2, e); +} + inline void VPath::lineTo(float x, float y) { lineTo(VPointF(x,y)); @@ -76,7 +132,47 @@ inline void VPath::moveTo(float x, float y) inline void VPath::cubicTo(float c1x, float c1y, float c2x, float c2y, float ex, float ey) { - cubicTo(VPointF(c1x, c1y), VPointF(c2x, c2y), VPointF(ex, ey)); + cubicTo(VPointF(c1x, c1y), VPointF(c2x, c2y), VPointF(ex, ey)); +} + +inline void VPath::transform(const VMatrix &m) +{ + d.write().transform(m); +} + +inline void VPath::arcTo(const VRectF &rect, float startAngle, float sweepLength, bool forceMoveTo) +{ + d.write().arcTo(rect, startAngle, sweepLength, forceMoveTo); +} + +inline void VPath::addRect(const VRectF &rect, VPath::Direction dir) +{ + d.write().addRect(rect, dir); +} + +inline void VPath::addRoundRect(const VRectF &rect, float rx, float ry, VPath::Direction dir) +{ + d.write().addRoundRect(rect, rx, ry, dir); +} + +inline void VPath::addCircle(float cx, float cy, float radius, VPath::Direction dir) +{ + d.write().addCircle(cx, cy, radius, dir); +} + +inline void VPath::addOval(const VRectF &rect, VPath::Direction dir) +{ + d.write().addOval(rect, dir); +} + +inline const std::vector &VPath::elements() const +{ + return d->elements(); +} + +inline const std::vector &VPath::points() const +{ + return d->points(); } V_END_NAMESPACE -- 2.7.4