mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
common: refactoring the dash pattern
introdced the length to avoid duplicate among engines
This commit is contained in:
parent
02a28bf9c3
commit
f1e9ce0460
8 changed files with 90 additions and 109 deletions
|
@ -1507,12 +1507,9 @@ void Stroker::stroke(const RenderShape *rshape, const RenderPath& path)
|
||||||
mStrokeWidth = strokeWidth / mMatrix.e11;
|
mStrokeWidth = strokeWidth / mMatrix.e11;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float *patterns = nullptr;
|
auto& dash = rshape->stroke->dash;
|
||||||
auto offset = 0.0f;
|
if (dash.count == 0) doStroke(path);
|
||||||
auto patternCnt = rshape->strokeDash(&patterns, &offset);
|
else doDashStroke(path, dash.pattern, dash.count, dash.offset, dash.length);
|
||||||
|
|
||||||
if (patternCnt == 0) doStroke(path);
|
|
||||||
else doDashStroke(path, patterns, patternCnt, offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1572,14 +1569,14 @@ void Stroker::doStroke(const RenderPath& path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Stroker::doDashStroke(const RenderPath& path, const float *patterns, uint32_t patternCnt, float offset)
|
void Stroker::doDashStroke(const RenderPath& path, const float *patterns, uint32_t patternCnt, float offset, float length)
|
||||||
{
|
{
|
||||||
RenderPath dpath;
|
RenderPath dpath;
|
||||||
|
|
||||||
dpath.cmds.reserve(20 * path.cmds.count);
|
dpath.cmds.reserve(20 * path.cmds.count);
|
||||||
dpath.pts.reserve(20 * path.pts.count);
|
dpath.pts.reserve(20 * path.pts.count);
|
||||||
|
|
||||||
DashStroke dash(&dpath.cmds, &dpath.pts, patterns, patternCnt, offset);
|
DashStroke dash(&dpath.cmds, &dpath.pts, patterns, patternCnt, offset, length);
|
||||||
dash.doStroke(path);
|
dash.doStroke(path);
|
||||||
doStroke(dpath);
|
doStroke(dpath);
|
||||||
}
|
}
|
||||||
|
@ -1915,18 +1912,13 @@ void Stroker::strokeRound(const Point& p, const Point& outDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DashStroke::DashStroke(Array<PathCommand> *cmds, Array<Point> *pts, const float *patterns, uint32_t patternCnt, float offset)
|
DashStroke::DashStroke(Array<PathCommand> *cmds, Array<Point> *pts, const float *patterns, uint32_t patternCnt, float offset, float length)
|
||||||
: mCmds(cmds),
|
: mCmds(cmds),
|
||||||
mPts(pts),
|
mPts(pts),
|
||||||
mDashPattern(patterns),
|
mDashPattern(patterns),
|
||||||
mDashCount(patternCnt),
|
mDashCount(patternCnt),
|
||||||
mDashOffset(offset),
|
mDashOffset(offset),
|
||||||
mCurrLen(),
|
mDashLength(length)
|
||||||
mCurrIdx(),
|
|
||||||
mCurOpGap(false),
|
|
||||||
mMove(true),
|
|
||||||
mPtStart(),
|
|
||||||
mPtCur()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1937,12 +1929,9 @@ void DashStroke::doStroke(const RenderPath& path)
|
||||||
auto offset = mDashOffset;
|
auto offset = mDashOffset;
|
||||||
bool gap = false;
|
bool gap = false;
|
||||||
if (!tvg::zero(mDashOffset)) {
|
if (!tvg::zero(mDashOffset)) {
|
||||||
auto len = 0.0f;
|
auto length = (mDashCount % 2) ? mDashLength * 2 : mDashLength;
|
||||||
for (uint32_t i = 0; i < mDashCount; ++i) len += mDashPattern[i];
|
offset = fmodf(offset, length);
|
||||||
if (mDashCount % 2) len *= 2;
|
if (offset < 0) offset += length;
|
||||||
|
|
||||||
offset = fmodf(offset, len);
|
|
||||||
if (offset < 0) offset += len;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mDashCount * (mDashCount % 2 + 1); ++i, ++idx) {
|
for (uint32_t i = 0; i < mDashCount * (mDashCount % 2 + 1); ++i, ++idx) {
|
||||||
auto curPattern = mDashPattern[i % mDashCount];
|
auto curPattern = mDashPattern[i % mDashCount];
|
||||||
|
|
|
@ -85,7 +85,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void doStroke(const RenderPath& path);
|
void doStroke(const RenderPath& path);
|
||||||
void doDashStroke(const RenderPath& path, const float* patterns, uint32_t patternCnt, float offset);
|
void doDashStroke(const RenderPath& path, const float* patterns, uint32_t patternCnt, float offset, float length);
|
||||||
|
|
||||||
float strokeRadius() const
|
float strokeRadius() const
|
||||||
{
|
{
|
||||||
|
@ -119,8 +119,7 @@ private:
|
||||||
class DashStroke
|
class DashStroke
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DashStroke(Array<PathCommand>* cmds, Array<Point>* pts, const float* patterns, uint32_t patternCnt, float offset);
|
DashStroke(Array<PathCommand>* cmds, Array<Point>* pts, const float* patterns, uint32_t patternCnt, float offset, float length);
|
||||||
~DashStroke() = default;
|
|
||||||
void doStroke(const RenderPath& path);
|
void doStroke(const RenderPath& path);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -135,12 +134,13 @@ private:
|
||||||
const float* mDashPattern;
|
const float* mDashPattern;
|
||||||
uint32_t mDashCount;
|
uint32_t mDashCount;
|
||||||
float mDashOffset;
|
float mDashOffset;
|
||||||
float mCurrLen;
|
float mDashLength;
|
||||||
int32_t mCurrIdx;
|
float mCurrLen = 0.0f;
|
||||||
bool mCurOpGap;
|
int32_t mCurrIdx = 0;
|
||||||
bool mMove;
|
bool mCurOpGap = false;
|
||||||
Point mPtStart;
|
bool mMove = true;
|
||||||
Point mPtCur;
|
Point mPtStart = {};
|
||||||
|
Point mPtCur = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
class BWTessellator
|
class BWTessellator
|
||||||
|
|
|
@ -85,7 +85,7 @@ struct SwShapeTask : SwTask
|
||||||
Additionally, the stroke style should not be dashed. */
|
Additionally, the stroke style should not be dashed. */
|
||||||
bool antialiasing(float strokeWidth)
|
bool antialiasing(float strokeWidth)
|
||||||
{
|
{
|
||||||
return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst || rshape->trimpath() || rshape->stroke->color.a < 255;
|
return strokeWidth < 2.0f || rshape->stroke->dash.count > 0 || rshape->stroke->strokeFirst || rshape->trimpath() || rshape->stroke->color.a < 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
float validStrokeWidth(bool clipper)
|
float validStrokeWidth(bool clipper)
|
||||||
|
|
|
@ -244,7 +244,6 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans
|
||||||
if (trimmed) {
|
if (trimmed) {
|
||||||
RenderPath trimmedPath;
|
RenderPath trimmedPath;
|
||||||
if (!rshape->stroke->trim.trim(rshape->path, trimmedPath)) return nullptr;
|
if (!rshape->stroke->trim.trim(rshape->path, trimmedPath)) return nullptr;
|
||||||
|
|
||||||
cmds = trimmedCmds = trimmedPath.cmds.data;
|
cmds = trimmedCmds = trimmedPath.cmds.data;
|
||||||
cmdCnt = trimmedPath.cmds.count;
|
cmdCnt = trimmedPath.cmds.count;
|
||||||
pts = trimmedPts = trimmedPath.pts.data;
|
pts = trimmedPts = trimmedPath.pts.data;
|
||||||
|
@ -263,19 +262,19 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans
|
||||||
if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
|
if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
|
||||||
|
|
||||||
SwDashStroke dash;
|
SwDashStroke dash;
|
||||||
auto offset = 0.0f;
|
dash.pattern = rshape->stroke->dash.pattern;
|
||||||
dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset);
|
dash.cnt = rshape->stroke->dash.count;
|
||||||
|
auto offset = rshape->stroke->dash.offset;
|
||||||
|
|
||||||
//offset
|
//offset
|
||||||
auto patternLength = 0.0f;
|
|
||||||
uint32_t offIdx = 0;
|
uint32_t offIdx = 0;
|
||||||
if (!tvg::zero(offset)) {
|
if (!tvg::zero(offset)) {
|
||||||
for (size_t i = 0; i < dash.cnt; ++i) patternLength += dash.pattern[i];
|
auto length = rshape->stroke->dash.length;
|
||||||
bool isOdd = dash.cnt % 2;
|
bool isOdd = dash.cnt % 2;
|
||||||
if (isOdd) patternLength *= 2;
|
if (isOdd) length *= 2;
|
||||||
|
|
||||||
offset = fmodf(offset, patternLength);
|
offset = fmodf(offset, length);
|
||||||
if (offset < 0) offset += patternLength;
|
if (offset < 0) offset += length;
|
||||||
|
|
||||||
for (size_t i = 0; i < dash.cnt * (1 + (size_t)isOdd); ++i, ++offIdx) {
|
for (size_t i = 0; i < dash.cnt * (1 + (size_t)isOdd); ++i, ++offIdx) {
|
||||||
auto curPattern = dash.pattern[i % dash.cnt];
|
auto curPattern = dash.pattern[i % dash.cnt];
|
||||||
|
@ -510,7 +509,7 @@ bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix&
|
||||||
auto ret = true;
|
auto ret = true;
|
||||||
|
|
||||||
//Dash style with/without trimming
|
//Dash style with/without trimming
|
||||||
if (rshape->stroke->dashCnt > 0) {
|
if (rshape->stroke->dash.count > 0) {
|
||||||
shapeOutline = _genDashOutline(rshape, transform, mpool, tid, rshape->trimpath());
|
shapeOutline = _genDashOutline(rshape, transform, mpool, tid, rshape->trimpath());
|
||||||
if (!shapeOutline) return false;
|
if (!shapeOutline) return false;
|
||||||
dashStroking = true;
|
dashStroking = true;
|
||||||
|
|
|
@ -127,9 +127,12 @@ struct RenderStroke
|
||||||
float width = 0.0f;
|
float width = 0.0f;
|
||||||
RenderColor color{};
|
RenderColor color{};
|
||||||
Fill *fill = nullptr;
|
Fill *fill = nullptr;
|
||||||
float* dashPattern = nullptr;
|
struct {
|
||||||
uint32_t dashCnt = 0;
|
float* pattern = nullptr;
|
||||||
float dashOffset = 0.0f;
|
uint32_t count = 0;
|
||||||
|
float offset = 0.0f;
|
||||||
|
float length = 0.0f;
|
||||||
|
} dash;
|
||||||
float miterlimit = 4.0f;
|
float miterlimit = 4.0f;
|
||||||
RenderTrimPath trim;
|
RenderTrimPath trim;
|
||||||
StrokeCap cap = StrokeCap::Square;
|
StrokeCap cap = StrokeCap::Square;
|
||||||
|
@ -145,15 +148,16 @@ struct RenderStroke
|
||||||
if (rhs.fill) fill = rhs.fill->duplicate();
|
if (rhs.fill) fill = rhs.fill->duplicate();
|
||||||
else fill = nullptr;
|
else fill = nullptr;
|
||||||
|
|
||||||
tvg::free(dashPattern);
|
tvg::free(dash.pattern);
|
||||||
if (rhs.dashCnt > 0) {
|
if (rhs.dash.count > 0) {
|
||||||
dashPattern = tvg::malloc<float*>(sizeof(float) * rhs.dashCnt);
|
dash.pattern = tvg::malloc<float*>(sizeof(float) * rhs.dash.count);
|
||||||
memcpy(dashPattern, rhs.dashPattern, sizeof(float) * rhs.dashCnt);
|
memcpy(dash.pattern, rhs.dash.pattern, sizeof(float) * rhs.dash.count);
|
||||||
} else {
|
} else {
|
||||||
dashPattern = nullptr;
|
dash.pattern = nullptr;
|
||||||
}
|
}
|
||||||
dashCnt = rhs.dashCnt;
|
dash.count = rhs.dash.count;
|
||||||
dashOffset = rhs.dashOffset;
|
dash.offset = rhs.dash.offset;
|
||||||
|
dash.length = rhs.dash.length;
|
||||||
miterlimit = rhs.miterlimit;
|
miterlimit = rhs.miterlimit;
|
||||||
cap = rhs.cap;
|
cap = rhs.cap;
|
||||||
join = rhs.join;
|
join = rhs.join;
|
||||||
|
@ -163,7 +167,7 @@ struct RenderStroke
|
||||||
|
|
||||||
~RenderStroke()
|
~RenderStroke()
|
||||||
{
|
{
|
||||||
tvg::free(dashPattern);
|
tvg::free(dash.pattern);
|
||||||
delete(fill);
|
delete(fill);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -223,9 +227,9 @@ struct RenderShape
|
||||||
uint32_t strokeDash(const float** dashPattern, float* offset) const
|
uint32_t strokeDash(const float** dashPattern, float* offset) const
|
||||||
{
|
{
|
||||||
if (!stroke) return 0;
|
if (!stroke) return 0;
|
||||||
if (dashPattern) *dashPattern = stroke->dashPattern;
|
if (dashPattern) *dashPattern = stroke->dash.pattern;
|
||||||
if (offset) *offset = stroke->dashOffset;
|
if (offset) *offset = stroke->dash.offset;
|
||||||
return stroke->dashCnt;
|
return stroke->dash.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
StrokeCap strokeCap() const
|
StrokeCap strokeCap() const
|
||||||
|
|
|
@ -282,34 +282,28 @@ struct Shape::Impl : Paint::Impl
|
||||||
|
|
||||||
Result strokeDash(const float* pattern, uint32_t cnt, float offset)
|
Result strokeDash(const float* pattern, uint32_t cnt, float offset)
|
||||||
{
|
{
|
||||||
if ((cnt == 1) || (!pattern && cnt > 0) || (pattern && cnt == 0)) {
|
if ((cnt == 1) || (!pattern && cnt > 0) || (pattern && cnt == 0)) return Result::InvalidArguments;
|
||||||
|
if (!rs.stroke) rs.stroke = new RenderStroke;
|
||||||
|
//Reset dash
|
||||||
|
auto& dash = rs.stroke->dash;
|
||||||
|
if (dash.count != cnt) {
|
||||||
|
tvg::free(dash.pattern);
|
||||||
|
dash.pattern = nullptr;
|
||||||
|
}
|
||||||
|
if (cnt > 0) {
|
||||||
|
if (!dash.pattern) dash.pattern = tvg::malloc<float*>(sizeof(float) * cnt);
|
||||||
|
dash.length = 0.0f;
|
||||||
|
for (uint32_t i = 0; i < cnt; ++i) {
|
||||||
|
if (pattern[i] < FLT_EPSILON) {
|
||||||
|
dash.count = 0;
|
||||||
return Result::InvalidArguments;
|
return Result::InvalidArguments;
|
||||||
}
|
}
|
||||||
|
dash.pattern[i] = pattern[i];
|
||||||
for (uint32_t i = 0; i < cnt; i++) {
|
dash.length += dash.pattern[i];
|
||||||
if (pattern[i] < FLOAT_EPSILON) return Result::InvalidArguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Reset dash
|
|
||||||
if (!pattern && cnt == 0) {
|
|
||||||
tvg::free(rs.stroke->dashPattern);
|
|
||||||
rs.stroke->dashPattern = nullptr;
|
|
||||||
} else {
|
|
||||||
if (!rs.stroke) rs.stroke = new RenderStroke();
|
|
||||||
if (rs.stroke->dashCnt != cnt) {
|
|
||||||
tvg::free(rs.stroke->dashPattern);
|
|
||||||
rs.stroke->dashPattern = nullptr;
|
|
||||||
}
|
|
||||||
if (!rs.stroke->dashPattern) {
|
|
||||||
rs.stroke->dashPattern = tvg::malloc<float*>(sizeof(float) * cnt);
|
|
||||||
if (!rs.stroke->dashPattern) return Result::FailedAllocation;
|
|
||||||
}
|
|
||||||
for (uint32_t i = 0; i < cnt; ++i) {
|
|
||||||
rs.stroke->dashPattern[i] = pattern[i];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rs.stroke->dashCnt = cnt;
|
rs.stroke->dash.count = cnt;
|
||||||
rs.stroke->dashOffset = offset;
|
rs.stroke->dash.offset = offset;
|
||||||
renderFlag |= RenderUpdateFlag::Stroke;
|
renderFlag |= RenderUpdateFlag::Stroke;
|
||||||
|
|
||||||
return Result::Success;
|
return Result::Success;
|
||||||
|
|
|
@ -353,47 +353,42 @@ struct WgIndexedVertexBuffer
|
||||||
icount += 6;
|
icount += 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dash buffer by pattern
|
|
||||||
void appendStrokesDashed(const WgVertexBuffer& buff, const RenderStroke* rstroke)
|
void appendStrokesDashed(const WgVertexBuffer& buff, const RenderStroke* rstroke)
|
||||||
{
|
{
|
||||||
// dashed buffer
|
|
||||||
dashed->reset(scale);
|
dashed->reset(scale);
|
||||||
// ignore single points polyline
|
auto& dash = rstroke->dash;
|
||||||
if (buff.count < 2) return;
|
|
||||||
const float* dashPattern = rstroke->dashPattern;
|
if (buff.count < 2 || tvg::zero(dash.length)) return;
|
||||||
size_t dashCnt = rstroke->dashCnt;
|
|
||||||
// starting state
|
uint32_t index = 0;
|
||||||
uint32_t index_dash = 0;
|
auto total = dash.pattern[index];
|
||||||
float len_total = dashPattern[index_dash];
|
auto length = (dash.count % 2) ? dash.length * 2 : dash.length;
|
||||||
// get dashes length
|
|
||||||
float dashes_lenth{};
|
|
||||||
for (uint32_t i = 0; i < dashCnt * (dashCnt % 2 + 1); i++) {
|
|
||||||
dashes_lenth += dashPattern[i % dashCnt];
|
|
||||||
}
|
|
||||||
if (dashes_lenth == 0) return;
|
|
||||||
// normalize dash offset
|
// normalize dash offset
|
||||||
float dashOffset = rstroke->dashOffset;
|
auto dashOffset = dash.offset;
|
||||||
while(dashOffset < 0) dashOffset += dashes_lenth;
|
while(dashOffset < 0) dashOffset += length;
|
||||||
while(dashOffset > dashes_lenth) dashOffset -= dashes_lenth;
|
while(dashOffset > length) dashOffset -= length;
|
||||||
auto gap = false;
|
auto gap = false;
|
||||||
|
|
||||||
// scip dashes by offset
|
// scip dashes by offset
|
||||||
while(len_total <= dashOffset) {
|
while(total <= dashOffset) {
|
||||||
index_dash = (index_dash + 1) % dashCnt;
|
index = (index + 1) % dash.count;
|
||||||
len_total += dashPattern[index_dash];
|
total += dash.pattern[index];
|
||||||
gap = !gap;
|
gap = !gap;
|
||||||
}
|
}
|
||||||
len_total -= dashOffset;
|
total -= dashOffset;
|
||||||
|
|
||||||
// iterate by polyline points
|
// iterate by polyline points
|
||||||
for (uint32_t i = 0; i < buff.count - 1; i++) {
|
for (uint32_t i = 0; i < buff.count - 1; i++) {
|
||||||
// append current polyline point
|
|
||||||
if (!gap) dashed->append(buff.data[i]);
|
if (!gap) dashed->append(buff.data[i]);
|
||||||
// move inside polyline segment
|
// move inside polyline segment
|
||||||
while(len_total < buff.dist[i+1].interval) {
|
while(total < buff.dist[i+1].interval) {
|
||||||
// get current point
|
// get current point
|
||||||
dashed->append(tvg::lerp(buff.data[i], buff.data[i+1], len_total / buff.dist[i+1].interval));
|
dashed->append(tvg::lerp(buff.data[i], buff.data[i+1], total / buff.dist[i+1].interval));
|
||||||
// update current state
|
// update current state
|
||||||
index_dash = (index_dash + 1) % dashCnt;
|
index = (index + 1) % dash.count;
|
||||||
len_total += dashPattern[index_dash];
|
total += dash.pattern[index];
|
||||||
// preceed stroke if dash
|
// preceed stroke if dash
|
||||||
if (!gap) {
|
if (!gap) {
|
||||||
dashed->updateDistances();
|
dashed->updateDistances();
|
||||||
|
@ -403,7 +398,7 @@ struct WgIndexedVertexBuffer
|
||||||
gap = !gap;
|
gap = !gap;
|
||||||
}
|
}
|
||||||
// update current subline length
|
// update current subline length
|
||||||
len_total -= buff.dist[i+1].interval;
|
total -= buff.dist[i+1].interval;
|
||||||
}
|
}
|
||||||
// draw last subline
|
// draw last subline
|
||||||
if (!gap) {
|
if (!gap) {
|
||||||
|
|
|
@ -394,8 +394,8 @@ void WgRenderDataShape::proceedStrokes(WgContext& context, const RenderStroke* r
|
||||||
{
|
{
|
||||||
assert(rstroke);
|
assert(rstroke);
|
||||||
auto strokesGenerator = pool->reqIndexedVertexBuffer(buff.scale);
|
auto strokesGenerator = pool->reqIndexedVertexBuffer(buff.scale);
|
||||||
if (rstroke->dashPattern) strokesGenerator->appendStrokesDashed(buff, rstroke);
|
if (rstroke->dash.count == 0) strokesGenerator->appendStrokes(buff, rstroke);
|
||||||
else strokesGenerator->appendStrokes(buff, rstroke);
|
else strokesGenerator->appendStrokesDashed(buff, rstroke);
|
||||||
|
|
||||||
appendStroke(context, *strokesGenerator);
|
appendStroke(context, *strokesGenerator);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue