mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-19 12:56:34 +00:00
common: code cleanup++
Some checks are pending
Android / build_x86_64 (push) Waiting to run
Android / build_aarch64 (push) Waiting to run
iOS / build_x86_64 (push) Waiting to run
iOS / build_arm64 (push) Waiting to run
macOS / build (push) Waiting to run
macOS / compact_test (push) Waiting to run
macOS / unit_test (push) Waiting to run
Ubuntu / build (push) Waiting to run
Ubuntu / compact_test (push) Waiting to run
Ubuntu / unit_test (push) Waiting to run
Windows / build (push) Waiting to run
Windows / compact_test (push) Waiting to run
Windows / unit_test (push) Waiting to run
Some checks are pending
Android / build_x86_64 (push) Waiting to run
Android / build_aarch64 (push) Waiting to run
iOS / build_x86_64 (push) Waiting to run
iOS / build_arm64 (push) Waiting to run
macOS / build (push) Waiting to run
macOS / compact_test (push) Waiting to run
macOS / unit_test (push) Waiting to run
Ubuntu / build (push) Waiting to run
Ubuntu / compact_test (push) Waiting to run
Ubuntu / unit_test (push) Waiting to run
Windows / build (push) Waiting to run
Windows / compact_test (push) Waiting to run
Windows / unit_test (push) Waiting to run
- Use RenderPath common interfaces instead of direct array manipulations. - Replace multiple scalar operations with Point utility operations where applicable.
This commit is contained in:
parent
d85952b252
commit
a79f9788c1
10 changed files with 181 additions and 362 deletions
|
@ -189,7 +189,6 @@ Point operator*(const Point& pt, const Matrix& m);
|
|||
Point normal(const Point& p1, const Point& p2);
|
||||
void normalize(Point& pt);
|
||||
|
||||
|
||||
static inline constexpr const Point operator*=(Point& pt, const Matrix* m)
|
||||
{
|
||||
if (m) pt *= *m;
|
||||
|
@ -313,6 +312,13 @@ static inline Point operator*(const Point& lhs, const float rhs)
|
|||
}
|
||||
|
||||
|
||||
static inline void operator*=(Point& lhs, const float rhs)
|
||||
{
|
||||
lhs.x *= rhs;
|
||||
lhs.y *= rhs;
|
||||
}
|
||||
|
||||
|
||||
static inline Point operator*(const float& lhs, const Point& rhs)
|
||||
{
|
||||
return {lhs * rhs.x, lhs * rhs.y};
|
||||
|
|
|
@ -33,22 +33,17 @@ static bool _colinear(const Point* p)
|
|||
}
|
||||
|
||||
|
||||
static void _roundCorner(Array<PathCommand>& cmds, Array<Point>& pts, Point& prev, Point& curr, Point& next, float r)
|
||||
static void _roundCorner(RenderPath& out, Point& prev, Point& curr, Point& next, float r)
|
||||
{
|
||||
auto lenPrev = length(prev - curr);
|
||||
auto rPrev = lenPrev > 0.0f ? 0.5f * std::min(lenPrev * 0.5f, r) / lenPrev : 0.0f;
|
||||
auto lenNext = length(next - curr);
|
||||
auto rNext = lenNext > 0.0f ? 0.5f * std::min(lenNext * 0.5f, r) / lenNext : 0.0f;
|
||||
|
||||
auto dPrev = rPrev * (curr - prev);
|
||||
auto dNext = rNext * (curr - next);
|
||||
|
||||
pts.push(curr - 2.0f * dPrev);
|
||||
pts.push(curr - dPrev);
|
||||
pts.push(curr - dNext);
|
||||
pts.push(curr - 2.0f * dNext);
|
||||
cmds.push(PathCommand::LineTo);
|
||||
cmds.push(PathCommand::CubicTo);
|
||||
out.lineTo(curr - 2.0f * dPrev);
|
||||
out.cubicTo(curr - dPrev, curr - dNext, curr - 2.0f * dNext);
|
||||
}
|
||||
|
||||
|
||||
|
@ -106,24 +101,14 @@ void LottieOffsetModifier::corner(RenderPath& out, Line& line, Line& nextLine, u
|
|||
} else {
|
||||
out.pts.push(line.pt2);
|
||||
if (join == StrokeJoin::Round) {
|
||||
out.cmds.push(PathCommand::CubicTo);
|
||||
out.pts.push((line.pt2 + intersect) * 0.5f);
|
||||
out.pts.push((nextLine.pt1 + intersect) * 0.5f);
|
||||
out.pts.push(nextLine.pt1);
|
||||
out.cubicTo((line.pt2 + intersect) * 0.5f, (nextLine.pt1 + intersect) * 0.5f, nextLine.pt1);
|
||||
} else if (join == StrokeJoin::Miter) {
|
||||
auto norm = normal(line.pt1, line.pt2);
|
||||
auto nextNorm = normal(nextLine.pt1, nextLine.pt2);
|
||||
auto miterDirection = (norm + nextNorm) / length(norm + nextNorm);
|
||||
if (1.0f <= miterLimit * fabsf(miterDirection.x * norm.x + miterDirection.y * norm.y)) {
|
||||
out.cmds.push(PathCommand::LineTo);
|
||||
out.pts.push(intersect);
|
||||
}
|
||||
out.cmds.push(PathCommand::LineTo);
|
||||
out.pts.push(nextLine.pt1);
|
||||
} else {
|
||||
out.cmds.push(PathCommand::LineTo);
|
||||
out.pts.push(nextLine.pt1);
|
||||
}
|
||||
if (1.0f <= miterLimit * fabsf(miterDirection.x * norm.x + miterDirection.y * norm.y)) out.lineTo(intersect);
|
||||
out.lineTo(nextLine.pt1);
|
||||
} else out.lineTo(nextLine.pt1);
|
||||
}
|
||||
} else out.pts.push(line.pt2);
|
||||
}
|
||||
|
@ -139,9 +124,8 @@ void LottieOffsetModifier::line(RenderPath& out, PathCommand* inCmds, uint32_t i
|
|||
if (inCmds[curCmd - 1] != PathCommand::LineTo) state.line = _offset(inPts[curPt - 1], inPts[curPt], offset);
|
||||
|
||||
if (state.moveto) {
|
||||
out.cmds.push(PathCommand::MoveTo);
|
||||
out.moveTo(state.line.pt1);
|
||||
state.movetoOutIndex = out.pts.count;
|
||||
out.pts.push(state.line.pt1);
|
||||
state.firstLine = state.line;
|
||||
state.moveto = false;
|
||||
}
|
||||
|
@ -179,7 +163,6 @@ bool LottieRoundnessModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt
|
|||
buffer->clear();
|
||||
|
||||
auto& path = (next) ? *buffer : out;
|
||||
|
||||
path.cmds.reserve(inCmdsCnt * 2);
|
||||
path.pts.reserve((uint32_t)(inPtsCnt * 1.5));
|
||||
auto pivot = path.pts.count;
|
||||
|
@ -189,8 +172,7 @@ bool LottieRoundnessModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt
|
|||
switch (inCmds[iCmds]) {
|
||||
case PathCommand::MoveTo: {
|
||||
startIndex = path.pts.count;
|
||||
path.cmds.push(PathCommand::MoveTo);
|
||||
path.pts.push(inPts[iPts++]);
|
||||
path.moveTo(inPts[iPts++]);
|
||||
break;
|
||||
}
|
||||
case PathCommand::CubicTo: {
|
||||
|
@ -198,24 +180,22 @@ bool LottieRoundnessModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt
|
|||
auto& prev = inPts[iPts - 1];
|
||||
auto& curr = inPts[iPts + 2];
|
||||
if (inCmds[iCmds + 1] == PathCommand::CubicTo && _colinear(inPts + iPts + 2)) {
|
||||
_roundCorner(path.cmds, path.pts, prev, curr, inPts[iPts + 5], r);
|
||||
_roundCorner(path, prev, curr, inPts[iPts + 5], r);
|
||||
iPts += 3;
|
||||
break;
|
||||
} else if (inCmds[iCmds + 1] == PathCommand::Close) {
|
||||
_roundCorner(path.cmds, path.pts, prev, curr, inPts[2], r);
|
||||
_roundCorner(path, prev, curr, inPts[2], r);
|
||||
path.pts[startIndex] = path.pts.last();
|
||||
iPts += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
path.cmds.push(PathCommand::CubicTo);
|
||||
path.pts.push(inPts[iPts++]);
|
||||
path.pts.push(inPts[iPts++]);
|
||||
path.pts.push(inPts[iPts++]);
|
||||
path.cubicTo(inPts[iPts], inPts[iPts + 1], inPts[iPts + 2]);
|
||||
iPts += 3;
|
||||
break;
|
||||
}
|
||||
case PathCommand::Close: {
|
||||
path.cmds.push(PathCommand::Close);
|
||||
path.close();
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
|
@ -249,8 +229,7 @@ bool LottieRoundnessModifier::modifyPolystar(RenderPath& in, RenderPath& out, fl
|
|||
path.pts.grow((uint32_t)(4.5 * in.cmds.count));
|
||||
|
||||
int start = 3 * tvg::zero(outerRoundness);
|
||||
path.cmds.push(PathCommand::MoveTo);
|
||||
path.pts.push(in.pts[start]);
|
||||
path.moveTo(in.pts[start]);
|
||||
|
||||
for (uint32_t i = 1 + start; i < in.pts.count; i += 6) {
|
||||
auto& prev = in.pts[i];
|
||||
|
@ -265,12 +244,9 @@ bool LottieRoundnessModifier::modifyPolystar(RenderPath& in, RenderPath& out, fl
|
|||
auto p2 = curr - dNext;
|
||||
auto p3 = curr - 2.0f * dNext;
|
||||
|
||||
path.cmds.push(PathCommand::CubicTo);
|
||||
path.pts.push(prev); path.pts.push(p0); path.pts.push(p0);
|
||||
path.cmds.push(PathCommand::CubicTo);
|
||||
path.pts.push(p1); path.pts.push(p2); path.pts.push(p3);
|
||||
path.cmds.push(PathCommand::CubicTo);
|
||||
path.pts.push(p3); path.pts.push(next); path.pts.push(nextCtrl);
|
||||
path.cubicTo(prev, p0, p0);
|
||||
path.cubicTo(p1, p2, p3);
|
||||
path.cubicTo(p3, next, nextCtrl);
|
||||
}
|
||||
} else {
|
||||
path.cmds.grow(2 * in.cmds.count);
|
||||
|
@ -278,8 +254,7 @@ bool LottieRoundnessModifier::modifyPolystar(RenderPath& in, RenderPath& out, fl
|
|||
|
||||
auto dPrev = r * (in.pts[1] - in.pts[0]);
|
||||
auto p = in.pts[0] + 2.0f * dPrev;
|
||||
path.cmds.push(PathCommand::MoveTo);
|
||||
path.pts.push(p);
|
||||
path.moveTo(p);
|
||||
|
||||
for (uint32_t i = 1; i < in.pts.count; ++i) {
|
||||
auto& curr = in.pts[i];
|
||||
|
@ -291,10 +266,8 @@ bool LottieRoundnessModifier::modifyPolystar(RenderPath& in, RenderPath& out, fl
|
|||
auto p2 = curr - dNext;
|
||||
auto p3 = curr - 2.0f * dNext;
|
||||
|
||||
path.cmds.push(PathCommand::LineTo);
|
||||
path.pts.push(p0);
|
||||
path.cmds.push(PathCommand::CubicTo);
|
||||
path.pts.push(p1); path.pts.push(p2); path.pts.push(p3);
|
||||
path.lineTo(p0);
|
||||
path.cubicTo(p1, p2, p3);
|
||||
|
||||
dPrev = -1.0f * dNext;
|
||||
}
|
||||
|
@ -359,9 +332,8 @@ bool LottieOffsetModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, P
|
|||
auto line3 = _offset(bezier.ctrl2, bezier.end, offset);
|
||||
|
||||
if (state.moveto) {
|
||||
out.cmds.push(PathCommand::MoveTo);
|
||||
out.moveTo(line1.pt1);
|
||||
state.movetoOutIndex = out.pts.count;
|
||||
out.pts.push(line1.pt1);
|
||||
state.firstLine = line1;
|
||||
state.moveto = false;
|
||||
}
|
||||
|
|
|
@ -181,44 +181,36 @@ bool LottieParser::getValue(PathSet& path)
|
|||
auto pt = pts.begin();
|
||||
|
||||
//Store manipulated results
|
||||
Array<Point> outPts;
|
||||
Array<PathCommand> outCmds;
|
||||
RenderPath temp;
|
||||
|
||||
//Reuse the buffers
|
||||
outPts.data = path.pts;
|
||||
outPts.reserved = path.ptsCnt;
|
||||
outCmds.data = path.cmds;
|
||||
outCmds.reserved = path.cmdsCnt;
|
||||
temp.pts.data = path.pts;
|
||||
temp.pts.reserved = path.ptsCnt;
|
||||
temp.cmds.data = path.cmds;
|
||||
temp.cmds.reserved = path.cmdsCnt;
|
||||
|
||||
size_t extra = closed ? 3 : 0;
|
||||
outPts.reserve(pts.count * 3 + 1 + extra);
|
||||
outCmds.reserve(pts.count + 2);
|
||||
temp.pts.reserve(pts.count * 3 + 1 + extra);
|
||||
temp.cmds.reserve(pts.count + 2);
|
||||
|
||||
outCmds.push(PathCommand::MoveTo);
|
||||
outPts.push(*pt);
|
||||
temp.moveTo(*pt);
|
||||
|
||||
for (++pt, ++out, ++in; pt < pts.end(); ++pt, ++out, ++in) {
|
||||
outCmds.push(PathCommand::CubicTo);
|
||||
outPts.push(*(pt - 1) + *(out - 1));
|
||||
outPts.push(*pt + *in);
|
||||
outPts.push(*pt);
|
||||
temp.cubicTo(*(pt - 1) + *(out - 1), *pt + *in, *pt);
|
||||
}
|
||||
|
||||
if (closed) {
|
||||
outPts.push(pts.last() + outs.last());
|
||||
outPts.push(pts.first() + ins.first());
|
||||
outPts.push(pts.first());
|
||||
outCmds.push(PathCommand::CubicTo);
|
||||
outCmds.push(PathCommand::Close);
|
||||
temp.cubicTo(pts.last() + outs.last(), pts.first() + ins.first(), pts.first());
|
||||
temp.close();
|
||||
}
|
||||
|
||||
path.pts = outPts.data;
|
||||
path.cmds = outCmds.data;
|
||||
path.ptsCnt = outPts.count;
|
||||
path.cmdsCnt = outCmds.count;
|
||||
path.pts = temp.pts.data;
|
||||
path.cmds = temp.cmds.data;
|
||||
path.ptsCnt = temp.pts.count;
|
||||
path.cmdsCnt = temp.cmds.count;
|
||||
|
||||
outPts.data = nullptr;
|
||||
outCmds.data = nullptr;
|
||||
temp.pts.data = nullptr;
|
||||
temp.cmds.data = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#include <cstring>
|
||||
#include <ctype.h>
|
||||
#include "tvgMath.h"
|
||||
#include "tvgShape.h"
|
||||
#include "tvgSvgLoaderCommon.h"
|
||||
#include "tvgSvgPath.h"
|
||||
#include "tvgStr.h"
|
||||
|
@ -69,108 +68,64 @@ static bool _parseFlag(char** content, int* number)
|
|||
}
|
||||
|
||||
|
||||
void _pathAppendArcTo(Array<PathCommand>* cmds, Array<Point>* pts, Point* cur, Point* curCtl, float x, float y, float rx, float ry, float angle, bool largeArc, bool sweep)
|
||||
//Some helpful stuff is available here:
|
||||
//http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
||||
void _pathAppendArcTo(RenderPath& out, Point& cur, Point& curCtl, const Point& next, Point radius, float angle, bool largeArc, bool sweep)
|
||||
{
|
||||
float cxp, cyp, cx, cy;
|
||||
float sx, sy;
|
||||
float cosPhi, sinPhi;
|
||||
float dx2, dy2;
|
||||
float x1p, y1p;
|
||||
float x1p2, y1p2;
|
||||
float rx2, ry2;
|
||||
float lambda;
|
||||
float c;
|
||||
float at;
|
||||
float theta1, deltaTheta;
|
||||
float nat;
|
||||
float delta, bcp;
|
||||
float cosPhiRx, cosPhiRy;
|
||||
float sinPhiRx, sinPhiRy;
|
||||
float cosTheta1, sinTheta1;
|
||||
int segments;
|
||||
|
||||
//Some helpful stuff is available here:
|
||||
//http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
||||
sx = cur->x;
|
||||
sy = cur->y;
|
||||
|
||||
//Correction of out-of-range radii, see F6.6.1 (step 2)
|
||||
rx = fabsf(rx);
|
||||
ry = fabsf(ry);
|
||||
|
||||
angle = deg2rad(angle);
|
||||
cosPhi = cosf(angle);
|
||||
sinPhi = sinf(angle);
|
||||
dx2 = (sx - x) / 2.0f;
|
||||
dy2 = (sy - y) / 2.0f;
|
||||
x1p = cosPhi * dx2 + sinPhi * dy2;
|
||||
y1p = cosPhi * dy2 - sinPhi * dx2;
|
||||
x1p2 = x1p * x1p;
|
||||
y1p2 = y1p * y1p;
|
||||
rx2 = rx * rx;
|
||||
ry2 = ry * ry;
|
||||
lambda = (x1p2 / rx2) + (y1p2 / ry2);
|
||||
auto start = cur;
|
||||
auto cosPhi = cosf(angle);
|
||||
auto sinPhi = sinf(angle);
|
||||
auto d2 = (start - next) * 0.5f;
|
||||
auto x1p = cosPhi * d2.x + sinPhi * d2.y;
|
||||
auto y1p = cosPhi * d2.y - sinPhi * d2.x;
|
||||
auto x1p2 = x1p * x1p;
|
||||
auto y1p2 = y1p * y1p;
|
||||
auto radius2 = Point{radius.x * radius.x, radius.y * radius.y};
|
||||
auto lambda = (x1p2 / radius2.x) + (y1p2 / radius2.y);
|
||||
|
||||
//Correction of out-of-range radii, see F6.6.2 (step 4)
|
||||
if (lambda > 1.0f) {
|
||||
//See F6.6.3
|
||||
float lambdaRoot = sqrtf(lambda);
|
||||
|
||||
rx *= lambdaRoot;
|
||||
ry *= lambdaRoot;
|
||||
//Update rx2 and ry2
|
||||
rx2 = rx * rx;
|
||||
ry2 = ry * ry;
|
||||
radius *= sqrtf(lambda);
|
||||
radius2 = {radius.x * radius.x, radius.y * radius.y};
|
||||
}
|
||||
|
||||
c = (rx2 * ry2) - (rx2 * y1p2) - (ry2 * x1p2);
|
||||
Point cp, center;
|
||||
auto c = (radius2.x * radius2.y) - (radius2.x * y1p2) - (radius2.y * x1p2);
|
||||
|
||||
//Check if there is no possible solution
|
||||
//(i.e. we can't do a square root of a negative value)
|
||||
if (c < 0.0f) {
|
||||
//Scale uniformly until we have a single solution
|
||||
//(see F6.2) i.e. when c == 0.0
|
||||
float scale = sqrtf(1.0f - c / (rx2 * ry2));
|
||||
rx *= scale;
|
||||
ry *= scale;
|
||||
//Update rx2 and ry2
|
||||
rx2 = rx * rx;
|
||||
ry2 = ry * ry;
|
||||
|
||||
radius *= sqrtf(1.0f - c / (radius2.x * radius2.y));
|
||||
radius2 = {radius.x * radius.x, radius.y * radius.y};
|
||||
//Step 2 (F6.5.2) - simplified since c == 0.0
|
||||
cxp = 0.0f;
|
||||
cyp = 0.0f;
|
||||
cp = {0.0f, 0.0f};
|
||||
//Step 3 (F6.5.3 first part) - simplified since cxp and cyp == 0.0
|
||||
cx = 0.0f;
|
||||
cy = 0.0f;
|
||||
center = {0.0f, 0.0f};
|
||||
} else {
|
||||
//Complete c calculation
|
||||
c = sqrtf(c / ((rx2 * y1p2) + (ry2 * x1p2)));
|
||||
c = sqrtf(c / ((radius2.x * y1p2) + (radius2.y * x1p2)));
|
||||
//Inverse sign if Fa == Fs
|
||||
if (largeArc == sweep) c = -c;
|
||||
|
||||
//Step 2 (F6.5.2)
|
||||
cxp = c * (rx * y1p / ry);
|
||||
cyp = c * (-ry * x1p / rx);
|
||||
|
||||
cp = c * Point{(radius.x * y1p / radius.y), (-radius.y * x1p / radius.x)};
|
||||
//Step 3 (F6.5.3 first part)
|
||||
cx = cosPhi * cxp - sinPhi * cyp;
|
||||
cy = sinPhi * cxp + cosPhi * cyp;
|
||||
center = {cosPhi * cp.x - sinPhi * cp.y, sinPhi * cp.x + cosPhi * cp.y};
|
||||
}
|
||||
|
||||
//Step 3 (F6.5.3 second part) we now have the center point of the ellipse
|
||||
cx += (sx + x) / 2.0f;
|
||||
cy += (sy + y) / 2.0f;
|
||||
center += (start + next) * 0.5f;
|
||||
|
||||
//Step 4 (F6.5.4)
|
||||
//We dont' use arccos (as per w3c doc), see
|
||||
//http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
|
||||
//Note: atan2 (0.0, 1.0) == 0.0
|
||||
at = tvg::atan2(((y1p - cyp) / ry), ((x1p - cxp) / rx));
|
||||
theta1 = (at < 0.0f) ? 2.0f * MATH_PI + at : at;
|
||||
|
||||
nat = tvg::atan2(((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
|
||||
deltaTheta = (nat < at) ? 2.0f * MATH_PI - at + nat : nat - at;
|
||||
auto at = tvg::atan2(((y1p - cp.y) / radius.y), ((x1p - cp.x) / radius.x));
|
||||
auto theta1 = (at < 0.0f) ? 2.0f * MATH_PI + at : at;
|
||||
auto nat = tvg::atan2(((-y1p - cp.y) / radius.y), ((-x1p - cp.x) / radius.x));
|
||||
auto deltaTheta = (nat < at) ? 2.0f * MATH_PI - at + nat : nat - at;
|
||||
|
||||
if (sweep) {
|
||||
//Ensure delta theta < 0 or else add 360 degrees
|
||||
|
@ -184,52 +139,35 @@ void _pathAppendArcTo(Array<PathCommand>* cmds, Array<Point>* pts, Point* cur, P
|
|||
//(smaller than 90 degrees)
|
||||
//We add one extra segment because we want something
|
||||
//Smaller than 90deg (i.e. not 90 itself)
|
||||
segments = static_cast<int>(fabsf(deltaTheta / MATH_PI2) + 1.0f);
|
||||
delta = deltaTheta / segments;
|
||||
auto segments = int(fabsf(deltaTheta / MATH_PI2) + 1.0f);
|
||||
auto delta = deltaTheta / segments;
|
||||
|
||||
//http://www.stillhq.com/ctpfaq/2001/comp.text.pdf-faq-2001-04.txt (section 2.13)
|
||||
bcp = 4.0f / 3.0f * (1.0f - cosf(delta / 2.0f)) / sinf(delta / 2.0f);
|
||||
|
||||
cosPhiRx = cosPhi * rx;
|
||||
cosPhiRy = cosPhi * ry;
|
||||
sinPhiRx = sinPhi * rx;
|
||||
sinPhiRy = sinPhi * ry;
|
||||
|
||||
cosTheta1 = cosf(theta1);
|
||||
sinTheta1 = sinf(theta1);
|
||||
auto bcp = 4.0f / 3.0f * (1.0f - cosf(delta / 2.0f)) / sinf(delta / 2.0f);
|
||||
auto cosPhiR = Point{cosPhi * radius.x, cosPhi * radius.y};
|
||||
auto sinPhiR = Point{sinPhi * radius.x, sinPhi * radius.y};
|
||||
auto cosTheta1 = cosf(theta1);
|
||||
auto sinTheta1 = sinf(theta1);
|
||||
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
//End angle (for this segment) = current + delta
|
||||
float c1x, c1y, ex, ey, c2x, c2y;
|
||||
float theta2 = theta1 + delta;
|
||||
float cosTheta2 = cosf(theta2);
|
||||
float sinTheta2 = sinf(theta2);
|
||||
Point p[3];
|
||||
auto theta2 = theta1 + delta;
|
||||
auto cosTheta2 = cosf(theta2);
|
||||
auto sinTheta2 = sinf(theta2);
|
||||
|
||||
//First control point (based on start point sx,sy)
|
||||
c1x = sx - bcp * (cosPhiRx * sinTheta1 + sinPhiRy * cosTheta1);
|
||||
c1y = sy + bcp * (cosPhiRy * cosTheta1 - sinPhiRx * sinTheta1);
|
||||
auto c1 = start + Point{-bcp * (cosPhiR.x * sinTheta1 + sinPhiR.y * cosTheta1), bcp * (cosPhiR.y * cosTheta1 - sinPhiR.x * sinTheta1)};
|
||||
|
||||
//End point (for this segment)
|
||||
ex = cx + (cosPhiRx * cosTheta2 - sinPhiRy * sinTheta2);
|
||||
ey = cy + (sinPhiRx * cosTheta2 + cosPhiRy * sinTheta2);
|
||||
auto e = center + Point{cosPhiR.x * cosTheta2 - sinPhiR.y * sinTheta2, sinPhiR.x * cosTheta2 + cosPhiR.y * sinTheta2};
|
||||
|
||||
//Second control point (based on end point ex,ey)
|
||||
c2x = ex + bcp * (cosPhiRx * sinTheta2 + sinPhiRy * cosTheta2);
|
||||
c2y = ey + bcp * (sinPhiRx * sinTheta2 - cosPhiRy * cosTheta2);
|
||||
cmds->push(PathCommand::CubicTo);
|
||||
p[0] = {c1x, c1y};
|
||||
p[1] = {c2x, c2y};
|
||||
p[2] = {ex, ey};
|
||||
pts->push(p[0]);
|
||||
pts->push(p[1]);
|
||||
pts->push(p[2]);
|
||||
*curCtl = p[1];
|
||||
*cur = p[2];
|
||||
curCtl = e + Point{bcp * (cosPhiR.x * sinTheta2 + sinPhiR.y * cosTheta2), bcp * (sinPhiR.x * sinTheta2 - cosPhiR.y * cosTheta2)};
|
||||
cur = e;
|
||||
out.cubicTo(c1, curCtl, cur);
|
||||
|
||||
//Next start point is the current end point (same for angle)
|
||||
sx = ex;
|
||||
sy = ey;
|
||||
start = e;
|
||||
theta1 = theta2;
|
||||
//Avoid recomputations
|
||||
cosTheta1 = cosTheta2;
|
||||
|
@ -237,6 +175,7 @@ void _pathAppendArcTo(Array<PathCommand>* cmds, Array<Point>* pts, Point* cur, P
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static int _numberCount(char cmd)
|
||||
{
|
||||
int count = 0;
|
||||
|
@ -276,14 +215,13 @@ static int _numberCount(char cmd)
|
|||
count = 7;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
static bool _processCommand(Array<PathCommand>* cmds, Array<Point>* pts, char cmd, float* arr, int count, Point* cur, Point* curCtl, Point* startPoint, bool *isQuadratic, bool* closed)
|
||||
static bool _processCommand(RenderPath& out, char cmd, float* arr, int count, Point& cur, Point& curCtl, Point& start, bool& quadratic, bool& closed)
|
||||
{
|
||||
switch (cmd) {
|
||||
case 'm':
|
||||
|
@ -293,169 +231,120 @@ static bool _processCommand(Array<PathCommand>* cmds, Array<Point>* pts, char cm
|
|||
case 'q':
|
||||
case 't': {
|
||||
for (int i = 0; i < count - 1; i += 2) {
|
||||
arr[i] = arr[i] + cur->x;
|
||||
arr[i + 1] = arr[i + 1] + cur->y;
|
||||
arr[i] = arr[i] + cur.x;
|
||||
arr[i + 1] = arr[i + 1] + cur.y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'h': {
|
||||
arr[0] = arr[0] + cur->x;
|
||||
arr[0] = arr[0] + cur.x;
|
||||
break;
|
||||
}
|
||||
case 'v': {
|
||||
arr[0] = arr[0] + cur->y;
|
||||
arr[0] = arr[0] + cur.y;
|
||||
break;
|
||||
}
|
||||
case 'a': {
|
||||
arr[5] = arr[5] + cur->x;
|
||||
arr[6] = arr[6] + cur->y;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
arr[5] = arr[5] + cur.x;
|
||||
arr[6] = arr[6] + cur.y;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case 'm':
|
||||
case 'M': {
|
||||
Point p = {arr[0], arr[1]};
|
||||
cmds->push(PathCommand::MoveTo);
|
||||
pts->push(p);
|
||||
*cur = {arr[0], arr[1]};
|
||||
*startPoint = {arr[0], arr[1]};
|
||||
start = cur = {arr[0], arr[1]};
|
||||
out.moveTo(cur);
|
||||
break;
|
||||
}
|
||||
case 'l':
|
||||
case 'L': {
|
||||
Point p = {arr[0], arr[1]};
|
||||
cmds->push(PathCommand::LineTo);
|
||||
pts->push(p);
|
||||
*cur = {arr[0], arr[1]};
|
||||
cur = {arr[0], arr[1]};
|
||||
out.lineTo(cur);
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
case 'C': {
|
||||
Point p[3];
|
||||
cmds->push(PathCommand::CubicTo);
|
||||
p[0] = {arr[0], arr[1]};
|
||||
p[1] = {arr[2], arr[3]};
|
||||
p[2] = {arr[4], arr[5]};
|
||||
pts->push(p[0]);
|
||||
pts->push(p[1]);
|
||||
pts->push(p[2]);
|
||||
*curCtl = p[1];
|
||||
*cur = p[2];
|
||||
*isQuadratic = false;
|
||||
curCtl = {arr[2], arr[3]};
|
||||
cur = {arr[4], arr[5]};
|
||||
out.cubicTo({arr[0], arr[1]}, curCtl, cur);
|
||||
quadratic = false;
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
case 'S': {
|
||||
Point p[3], ctrl;
|
||||
if ((cmds->count > 1) && (cmds->last() == PathCommand::CubicTo) &&
|
||||
!(*isQuadratic)) {
|
||||
ctrl.x = 2 * cur->x - curCtl->x;
|
||||
ctrl.y = 2 * cur->y - curCtl->y;
|
||||
Point ctrl;
|
||||
if ((out.cmds.count > 1) && (out.cmds.last() == PathCommand::CubicTo) && !quadratic) {
|
||||
ctrl = 2 * cur - curCtl;
|
||||
} else {
|
||||
ctrl = *cur;
|
||||
ctrl = cur;
|
||||
}
|
||||
cmds->push(PathCommand::CubicTo);
|
||||
p[0] = ctrl;
|
||||
p[1] = {arr[0], arr[1]};
|
||||
p[2] = {arr[2], arr[3]};
|
||||
pts->push(p[0]);
|
||||
pts->push(p[1]);
|
||||
pts->push(p[2]);
|
||||
*curCtl = p[1];
|
||||
*cur = p[2];
|
||||
*isQuadratic = false;
|
||||
curCtl = {arr[0], arr[1]};
|
||||
cur = {arr[2], arr[3]};
|
||||
out.cubicTo(ctrl, curCtl, cur);
|
||||
quadratic = false;
|
||||
break;
|
||||
}
|
||||
case 'q':
|
||||
case 'Q': {
|
||||
Point p[3];
|
||||
float ctrl_x0 = (cur->x + 2 * arr[0]) * (1.0f / 3.0f);
|
||||
float ctrl_y0 = (cur->y + 2 * arr[1]) * (1.0f / 3.0f);
|
||||
float ctrl_x1 = (arr[2] + 2 * arr[0]) * (1.0f / 3.0f);
|
||||
float ctrl_y1 = (arr[3] + 2 * arr[1]) * (1.0f / 3.0f);
|
||||
cmds->push(PathCommand::CubicTo);
|
||||
p[0] = {ctrl_x0, ctrl_y0};
|
||||
p[1] = {ctrl_x1, ctrl_y1};
|
||||
p[2] = {arr[2], arr[3]};
|
||||
pts->push(p[0]);
|
||||
pts->push(p[1]);
|
||||
pts->push(p[2]);
|
||||
*curCtl = {arr[0], arr[1]};
|
||||
*cur = p[2];
|
||||
*isQuadratic = true;
|
||||
auto ctrl1 = (cur + 2 * Point{arr[0], arr[1]}) * (1.0f / 3.0f);
|
||||
auto ctrl2 = (Point{arr[2], arr[3]} + 2 * Point{arr[0], arr[1]}) * (1.0f / 3.0f);
|
||||
curCtl = {arr[0], arr[1]};
|
||||
cur = {arr[2], arr[3]};
|
||||
out.cubicTo(ctrl1, ctrl2, cur);
|
||||
quadratic = true;
|
||||
break;
|
||||
}
|
||||
case 't':
|
||||
case 'T': {
|
||||
Point p[3], ctrl;
|
||||
if ((cmds->count > 1) && (cmds->last() == PathCommand::CubicTo) &&
|
||||
*isQuadratic) {
|
||||
ctrl.x = 2 * cur->x - curCtl->x;
|
||||
ctrl.y = 2 * cur->y - curCtl->y;
|
||||
Point ctrl;
|
||||
if ((out.cmds.count > 1) && (out.cmds.last() == PathCommand::CubicTo) && quadratic) {
|
||||
ctrl = 2 * cur - curCtl;
|
||||
} else {
|
||||
ctrl = *cur;
|
||||
ctrl = cur;
|
||||
}
|
||||
float ctrl_x0 = (cur->x + 2 * ctrl.x) * (1.0f / 3.0f);
|
||||
float ctrl_y0 = (cur->y + 2 * ctrl.y) * (1.0f / 3.0f);
|
||||
float ctrl_x1 = (arr[0] + 2 * ctrl.x) * (1.0f / 3.0f);
|
||||
float ctrl_y1 = (arr[1] + 2 * ctrl.y) * (1.0f / 3.0f);
|
||||
cmds->push(PathCommand::CubicTo);
|
||||
p[0] = {ctrl_x0, ctrl_y0};
|
||||
p[1] = {ctrl_x1, ctrl_y1};
|
||||
p[2] = {arr[0], arr[1]};
|
||||
pts->push(p[0]);
|
||||
pts->push(p[1]);
|
||||
pts->push(p[2]);
|
||||
*curCtl = {ctrl.x, ctrl.y};
|
||||
*cur = p[2];
|
||||
*isQuadratic = true;
|
||||
auto ctrl1 = (cur + 2 * ctrl) * (1.0f / 3.0f);
|
||||
auto ctrl2 = (Point{arr[0], arr[1]} + 2 * ctrl) * (1.0f / 3.0f);
|
||||
curCtl = {ctrl.x, ctrl.y};
|
||||
cur = {arr[0], arr[1]};
|
||||
out.cubicTo(ctrl1, ctrl2, cur);
|
||||
quadratic = true;
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
case 'H': {
|
||||
Point p = {arr[0], cur->y};
|
||||
cmds->push(PathCommand::LineTo);
|
||||
pts->push(p);
|
||||
cur->x = arr[0];
|
||||
out.lineTo({arr[0], cur.y});
|
||||
cur.x = arr[0];
|
||||
break;
|
||||
}
|
||||
case 'v':
|
||||
case 'V': {
|
||||
Point p = {cur->x, arr[0]};
|
||||
cmds->push(PathCommand::LineTo);
|
||||
pts->push(p);
|
||||
cur->y = arr[0];
|
||||
out.lineTo({cur.x, arr[0]});
|
||||
cur.y = arr[0];
|
||||
break;
|
||||
}
|
||||
case 'z':
|
||||
case 'Z': {
|
||||
cmds->push(PathCommand::Close);
|
||||
*cur = *startPoint;
|
||||
*closed = true;
|
||||
out.close();
|
||||
cur = start;
|
||||
closed = true;
|
||||
break;
|
||||
}
|
||||
case 'a':
|
||||
case 'A': {
|
||||
if (tvg::zero(arr[0]) || tvg::zero(arr[1])) {
|
||||
Point p = {arr[5], arr[6]};
|
||||
cmds->push(PathCommand::LineTo);
|
||||
pts->push(p);
|
||||
*cur = {arr[5], arr[6]};
|
||||
} else if (!tvg::equal(cur->x, arr[5]) || !tvg::equal(cur->y, arr[6])) {
|
||||
_pathAppendArcTo(cmds, pts, cur, curCtl, arr[5], arr[6], fabsf(arr[0]), fabsf(arr[1]), arr[2], arr[3], arr[4]);
|
||||
*cur = *curCtl = {arr[5], arr[6]};
|
||||
*isQuadratic = false;
|
||||
cur = {arr[5], arr[6]};
|
||||
out.lineTo(cur);
|
||||
} else if (!tvg::equal(cur.x, arr[5]) || !tvg::equal(cur.y, arr[6])) {
|
||||
_pathAppendArcTo(out, cur, curCtl, {arr[5], arr[6]}, {fabsf(arr[0]), fabsf(arr[1])}, deg2rad(arr[2]), arr[3], arr[4]);
|
||||
cur = curCtl = {arr[5], arr[6]};
|
||||
quadratic = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -497,12 +386,12 @@ static char* _nextCommand(char* path, char* cmd, float* arr, int* count, bool* c
|
|||
}
|
||||
}
|
||||
*count = 0;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
for (int i = 0; i < *count; i++) {
|
||||
if (!_parseNumber(&path, &arr[i])) {
|
||||
*count = 0;
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
path = _skipComma(path);
|
||||
}
|
||||
|
@ -515,29 +404,26 @@ static char* _nextCommand(char* path, char* cmd, float* arr, int* count, bool* c
|
|||
/************************************************************************/
|
||||
|
||||
|
||||
bool svgPathToShape(const char* svgPath, Shape* shape)
|
||||
bool svgPathToShape(const char* svgPath, RenderPath& out)
|
||||
{
|
||||
float numberArray[7];
|
||||
int numberCount = 0;
|
||||
Point cur = { 0, 0 };
|
||||
Point curCtl = { 0, 0 };
|
||||
Point startPoint = { 0, 0 };
|
||||
Point cur = {0, 0};
|
||||
Point curCtl = {0, 0};
|
||||
Point start = {0, 0};
|
||||
char cmd = 0;
|
||||
bool isQuadratic = false;
|
||||
bool closed = false;
|
||||
char* path = (char*)svgPath;
|
||||
|
||||
auto& pts = SHAPE(shape)->rs.path.pts;
|
||||
auto& cmds = SHAPE(shape)->rs.path.cmds;
|
||||
auto lastCmds = cmds.count;
|
||||
auto path = (char*)svgPath;
|
||||
auto lastCmds = out.cmds.count;
|
||||
auto isQuadratic = false;
|
||||
auto closed = false;
|
||||
|
||||
while ((path[0] != '\0')) {
|
||||
path = _nextCommand(path, &cmd, numberArray, &numberCount, &closed);
|
||||
if (!path) break;
|
||||
closed = false;
|
||||
if (!_processCommand(&cmds, &pts, cmd, numberArray, numberCount, &cur, &curCtl, &startPoint, &isQuadratic, &closed)) break;
|
||||
if (!_processCommand(out, cmd, numberArray, numberCount, cur, curCtl, start, isQuadratic, closed)) break;
|
||||
}
|
||||
|
||||
if (cmds.count > lastCmds && cmds[lastCmds] != PathCommand::MoveTo) return false;
|
||||
if (out.cmds.count > lastCmds && out.cmds[lastCmds] != PathCommand::MoveTo) return false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#ifndef _TVG_SVG_PATH_H_
|
||||
#define _TVG_SVG_PATH_H_
|
||||
|
||||
#include <tvgCommon.h>
|
||||
#include "tvgRender.h"
|
||||
|
||||
bool svgPathToShape(const char* svgPath, Shape* shape);
|
||||
bool svgPathToShape(const char* svgPath, RenderPath& out);
|
||||
|
||||
#endif //_TVG_SVG_PATH_H_
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "tvgCompressor.h"
|
||||
#include "tvgFill.h"
|
||||
#include "tvgStr.h"
|
||||
#include "tvgShape.h"
|
||||
#include "tvgSvgLoaderCommon.h"
|
||||
#include "tvgSvgSceneBuilder.h"
|
||||
#include "tvgSvgPath.h"
|
||||
|
@ -454,7 +455,7 @@ static bool _recognizeShape(SvgNode* node, Shape* shape)
|
|||
switch (node->type) {
|
||||
case SvgNodeType::Path: {
|
||||
if (node->node.path.path) {
|
||||
if (!svgPathToShape(node->node.path.path, shape)) {
|
||||
if (!svgPathToShape(node->node.path.path, SHAPE(shape)->rs.path)) {
|
||||
TVGERR("SVG", "Invalid path information.");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -474,10 +474,9 @@ bool TtfReader::convert(Shape* shape, TtfGlyphMetrics& gmetrics, const Point& of
|
|||
if (!this->points(outline, flags, pts, ptsCnt, offset + kerning)) return false;
|
||||
|
||||
//generate tvg paths.
|
||||
auto& pathCmds = SHAPE(shape)->rs.path.cmds;
|
||||
auto& pathPts = SHAPE(shape)->rs.path.pts;
|
||||
pathCmds.reserve(ptsCnt);
|
||||
pathPts.reserve(ptsCnt);
|
||||
auto& path = SHAPE(shape)->rs.path;
|
||||
path.cmds.reserve(ptsCnt);
|
||||
path.pts.reserve(ptsCnt);
|
||||
|
||||
uint32_t begin = 0;
|
||||
|
||||
|
@ -485,42 +484,31 @@ bool TtfReader::convert(Shape* shape, TtfGlyphMetrics& gmetrics, const Point& of
|
|||
//contour must start with move to
|
||||
bool offCurve = !(flags[begin] & ON_CURVE);
|
||||
Point ptsBegin = offCurve ? (pts[begin] + pts[endPts[i]]) * 0.5f : pts[begin];
|
||||
pathCmds.push(PathCommand::MoveTo);
|
||||
pathPts.push(ptsBegin);
|
||||
path.moveTo(ptsBegin);
|
||||
|
||||
auto cnt = endPts[i] - begin + 1;
|
||||
for (uint32_t x = 1; x < cnt; ++x) {
|
||||
if (flags[begin + x] & ON_CURVE) {
|
||||
if (offCurve) {
|
||||
pathCmds.push(PathCommand::CubicTo);
|
||||
pathPts.push(pathPts.last() + (2.0f/3.0f) * (pts[begin + x - 1] - pathPts.last()));
|
||||
pathPts.push(pts[begin + x] + (2.0f/3.0f) * (pts[begin + x - 1] - pts[begin + x]));
|
||||
pathPts.push(pts[begin + x]);
|
||||
path.cubicTo(path.pts.last() + (2.0f/3.0f) * (pts[begin + x - 1] - path.pts.last()), pts[begin + x] + (2.0f/3.0f) * (pts[begin + x - 1] - pts[begin + x]), pts[begin + x]);
|
||||
offCurve = false;
|
||||
} else {
|
||||
pathCmds.push(PathCommand::LineTo);
|
||||
pathPts.push(pts[begin + x]);
|
||||
path.lineTo(pts[begin + x]);
|
||||
}
|
||||
} else {
|
||||
if (offCurve) {
|
||||
pathCmds.push(PathCommand::CubicTo);
|
||||
auto end = (pts[begin + x] + pts[begin + x - 1]) * 0.5f;
|
||||
pathPts.push(pathPts.last() + (2.0f/3.0f) * (pts[begin + x - 1] - pathPts.last()));
|
||||
pathPts.push(end + (2.0f/3.0f) * (pts[begin + x - 1] - end));
|
||||
pathPts.push(end);
|
||||
path.cubicTo(path.pts.last() + (2.0f/3.0f) * (pts[begin + x - 1] - path.pts.last()), end + (2.0f/3.0f) * (pts[begin + x - 1] - end), end);
|
||||
} else {
|
||||
offCurve = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (offCurve) {
|
||||
pathCmds.push(PathCommand::CubicTo);
|
||||
pathPts.push(pathPts.last() + (2.0f/3.0f) * (pts[begin + cnt - 1] - pathPts.last()));
|
||||
pathPts.push(ptsBegin + (2.0f/3.0f) * (pts[begin + cnt - 1] - ptsBegin));
|
||||
pathPts.push(ptsBegin);
|
||||
path.cubicTo(path.pts.last() + (2.0f/3.0f) * (pts[begin + cnt - 1] - path.pts.last()), ptsBegin + (2.0f/3.0f) * (pts[begin + cnt - 1] - ptsBegin), ptsBegin);
|
||||
}
|
||||
//contour must end with close
|
||||
pathCmds.push(PathCommand::Close);
|
||||
path.close();
|
||||
begin = endPts[i] + 1;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -235,6 +235,8 @@ struct RenderPath
|
|||
|
||||
void close()
|
||||
{
|
||||
//Don't close multiple times.
|
||||
if (cmds.count > 0 && cmds.last() == PathCommand::Close) return;
|
||||
cmds.push(PathCommand::Close);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,28 +66,31 @@ Result Shape::appendPath(const PathCommand *cmds, uint32_t cmdCnt, const Point*
|
|||
|
||||
Result Shape::moveTo(float x, float y) noexcept
|
||||
{
|
||||
SHAPE(this)->moveTo(x, y);
|
||||
SHAPE(this)->rs.path.moveTo({x, y});
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result Shape::lineTo(float x, float y) noexcept
|
||||
{
|
||||
SHAPE(this)->lineTo(x, y);
|
||||
SHAPE(this)->rs.path.lineTo({x, y});
|
||||
SHAPE(this)->impl.mark(RenderUpdateFlag::Path);
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result Shape::cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) noexcept
|
||||
{
|
||||
SHAPE(this)->cubicTo(cx1, cy1, cx2, cy2, x, y);
|
||||
SHAPE(this)->rs.path.cubicTo({cx1, cy1}, {cx2, cy2}, {x, y});
|
||||
SHAPE(this)->impl.mark(RenderUpdateFlag::Path);
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
Result Shape::close() noexcept
|
||||
{
|
||||
SHAPE(this)->close();
|
||||
SHAPE(this)->rs.path.close();
|
||||
SHAPE(this)->impl.mark(RenderUpdateFlag::Path);
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
|
|
@ -170,37 +170,6 @@ struct ShapeImpl : Shape
|
|||
rs.path.pts.count += ptsCnt;
|
||||
}
|
||||
|
||||
void moveTo(float x, float y)
|
||||
{
|
||||
rs.path.cmds.push(PathCommand::MoveTo);
|
||||
rs.path.pts.push({x, y});
|
||||
}
|
||||
|
||||
void lineTo(float x, float y)
|
||||
{
|
||||
rs.path.cmds.push(PathCommand::LineTo);
|
||||
rs.path.pts.push({x, y});
|
||||
impl.mark(RenderUpdateFlag::Path);
|
||||
}
|
||||
|
||||
void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
|
||||
{
|
||||
rs.path.cmds.push(PathCommand::CubicTo);
|
||||
rs.path.pts.push({cx1, cy1});
|
||||
rs.path.pts.push({cx2, cy2});
|
||||
rs.path.pts.push({x, y});
|
||||
|
||||
impl.mark(RenderUpdateFlag::Path);
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
//Don't close multiple times.
|
||||
if (rs.path.cmds.count > 0 && rs.path.cmds.last() == PathCommand::Close) return;
|
||||
rs.path.cmds.push(PathCommand::Close);
|
||||
impl.mark(RenderUpdateFlag::Path);
|
||||
}
|
||||
|
||||
void strokeWidth(float width)
|
||||
{
|
||||
if (!rs.stroke) rs.stroke = new RenderStroke();
|
||||
|
|
Loading…
Add table
Reference in a new issue