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