mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
wg_engine: apply common trimming logic
The trim-related implementation has been removed and replaced with the one available in common. @Issue: https://github.com/thorvg/thorvg/issues/2854
This commit is contained in:
parent
8ed4c2f302
commit
cb8cadfbba
3 changed files with 55 additions and 108 deletions
|
@ -161,56 +161,51 @@ struct WgVertexBuffer
|
||||||
append(bezier.at((float)i / nsegs));
|
append(bezier.at((float)i / nsegs));
|
||||||
}
|
}
|
||||||
|
|
||||||
// trim source buffer
|
|
||||||
void trim(const WgVertexBuffer& buff, float beg, float end)
|
|
||||||
{
|
|
||||||
// empty buffer guard
|
|
||||||
if (buff.vcount == 0) return;
|
|
||||||
// initialize
|
|
||||||
float len_beg = buff.total() * beg;
|
|
||||||
float len_end = buff.total() * end;
|
|
||||||
// find points
|
|
||||||
size_t index_beg = buff.getIndexByLength(len_beg);
|
|
||||||
size_t index_end = buff.getIndexByLength(len_end);
|
|
||||||
float len_total_beg = buff.vleng[index_beg];
|
|
||||||
float len_total_end = buff.vleng[index_end];
|
|
||||||
float len_seg_beg = buff.vdist[index_beg];
|
|
||||||
float len_seg_end = buff.vdist[index_end];
|
|
||||||
// append points
|
|
||||||
float t_beg = len_seg_beg > 0.0f ? 1.0f - (len_total_beg - len_beg) / len_seg_beg : 0.0f;
|
|
||||||
float t_end = len_seg_end > 0.0f ? 1.0f - (len_total_end - len_end) / len_seg_end : 0.0f;
|
|
||||||
//t_beg == 1 handled in appendRange
|
|
||||||
if (index_beg > 0 && t_beg != 1.0f) append(lerp(buff.vbuff[index_beg-1], buff.vbuff[index_beg], t_beg));
|
|
||||||
appendRange(buff, index_beg, index_end);
|
|
||||||
//t_end == 0 handled in appendRange
|
|
||||||
if (index_end > 0 && t_end != 0.0f) append(lerp(buff.vbuff[index_end-1], buff.vbuff[index_end], t_end));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// decode path with callback for external prcesses
|
// decode path with callback for external prcesses
|
||||||
void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline)
|
void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline, bool trim = false)
|
||||||
{
|
{
|
||||||
// decode path
|
// decode path
|
||||||
reset(tscale);
|
reset(tscale);
|
||||||
|
|
||||||
|
PathCommand *cmds, *trimmedCmds = nullptr;
|
||||||
|
Point *pts, *trimmedPts = nullptr;
|
||||||
|
uint32_t cmdCnt{};
|
||||||
|
|
||||||
|
if (trim) {
|
||||||
|
RenderPath trimmedPath;
|
||||||
|
if (!rshape.stroke->trim.trim(rshape.path, trimmedPath)) return;
|
||||||
|
|
||||||
|
cmds = trimmedCmds = trimmedPath.cmds.data;
|
||||||
|
cmdCnt = trimmedPath.cmds.count;
|
||||||
|
pts = trimmedPts = trimmedPath.pts.data;
|
||||||
|
|
||||||
|
trimmedPath.cmds.data = nullptr;
|
||||||
|
trimmedPath.pts.data = nullptr;
|
||||||
|
} else {
|
||||||
|
cmds = rshape.path.cmds.data;
|
||||||
|
cmdCnt = rshape.path.cmds.count;
|
||||||
|
pts = rshape.path.pts.data;
|
||||||
|
}
|
||||||
|
|
||||||
size_t pntIndex = 0;
|
size_t pntIndex = 0;
|
||||||
ARRAY_FOREACH(p, rshape.path.cmds) {
|
for (uint32_t i = 0; i < cmdCnt; i++) {
|
||||||
auto cmd = *p;
|
auto& cmd = cmds[i];
|
||||||
if (cmd == PathCommand::MoveTo) {
|
if (cmd == PathCommand::MoveTo) {
|
||||||
// after path decoding we need to update distances and total length
|
// after path decoding we need to update distances and total length
|
||||||
if (update_dist) updateDistances();
|
if (update_dist) updateDistances();
|
||||||
if ((onPolyline) && (vcount > 0)) onPolyline(*this);
|
if ((onPolyline) && (vcount > 0)) onPolyline(*this);
|
||||||
reset(tscale);
|
reset(tscale);
|
||||||
append(rshape.path.pts[pntIndex]);
|
append(pts[pntIndex]);
|
||||||
pntIndex++;
|
pntIndex++;
|
||||||
} else if (cmd == PathCommand::LineTo) {
|
} else if (cmd == PathCommand::LineTo) {
|
||||||
append(rshape.path.pts[pntIndex]);
|
append(pts[pntIndex]);
|
||||||
pntIndex++;
|
pntIndex++;
|
||||||
} else if (cmd == PathCommand::Close) {
|
} else if (cmd == PathCommand::Close) {
|
||||||
close();
|
close();
|
||||||
// proceed path if close command is not the last command and next command is LineTo or CubicTo
|
// proceed path if close command is not the last command and next command is LineTo or CubicTo
|
||||||
if (((p + 1) < rshape.path.cmds.end()) &&
|
if (i + 1 < cmdCnt &&
|
||||||
((*(p + 1) == PathCommand::LineTo) ||
|
(cmds[i + 1] == PathCommand::LineTo ||
|
||||||
(*(p + 1) == PathCommand::CubicTo))) {
|
cmds[i + 1] == PathCommand::CubicTo)) {
|
||||||
// proceed current path
|
// proceed current path
|
||||||
if (update_dist) updateDistances();
|
if (update_dist) updateDistances();
|
||||||
if ((vcount > 0) && (onPolyline)) onPolyline(*this);
|
if ((vcount > 0) && (onPolyline)) onPolyline(*this);
|
||||||
|
@ -221,10 +216,14 @@ struct WgVertexBuffer
|
||||||
}
|
}
|
||||||
} else if (cmd == PathCommand::CubicTo) {
|
} else if (cmd == PathCommand::CubicTo) {
|
||||||
// append tesselated cubic spline with tscale param
|
// append tesselated cubic spline with tscale param
|
||||||
appendCubic(vbuff[vcount - 1], rshape.path.pts[pntIndex + 0], rshape.path.pts[pntIndex + 1], rshape.path.pts[pntIndex + 2]);
|
appendCubic(vbuff[vcount - 1], pts[pntIndex + 0], pts[pntIndex + 1], pts[pntIndex + 2]);
|
||||||
pntIndex += 3;
|
pntIndex += 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(trimmedCmds);
|
||||||
|
free(trimmedPts);
|
||||||
|
|
||||||
// after path decoding we need to update distances and total length
|
// after path decoding we need to update distances and total length
|
||||||
if (update_dist) updateDistances();
|
if (update_dist) updateDistances();
|
||||||
if ((vcount > 0) && (onPolyline)) onPolyline(*this);
|
if ((vcount > 0) && (onPolyline)) onPolyline(*this);
|
||||||
|
|
|
@ -385,61 +385,23 @@ void WgRenderDataShape::updateMeshes(WgContext& context, const RenderShape &rsha
|
||||||
// path decoded vertex buffer
|
// path decoded vertex buffer
|
||||||
WgVertexBuffer pbuff;
|
WgVertexBuffer pbuff;
|
||||||
pbuff.reset(scale);
|
pbuff.reset(scale);
|
||||||
// append shape without strokes
|
|
||||||
if (!rshape.stroke) {
|
if (rshape.strokeTrim()) {
|
||||||
pbuff.decodePath(rshape, false, [&](const WgVertexBuffer& path_buff) {
|
WgVertexBuffer trimbuff;
|
||||||
|
trimbuff.reset(scale);
|
||||||
|
|
||||||
|
pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) {
|
||||||
appendShape(context, path_buff);
|
appendShape(context, path_buff);
|
||||||
});
|
});
|
||||||
// append shape with strokes
|
trimbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) {
|
||||||
|
appendShape(context, path_buff);
|
||||||
|
proceedStrokes(context, rshape.stroke, path_buff);
|
||||||
|
}, true);
|
||||||
} else {
|
} else {
|
||||||
float tbeg{}, tend{};
|
pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) {
|
||||||
if (!rshape.stroke->trim.get(tbeg, tend)) { tbeg = 0.0f; tend = 1.0f; }
|
appendShape(context, path_buff);
|
||||||
bool loop = tbeg > tend;
|
if (rshape.stroke) proceedStrokes(context, rshape.stroke, path_buff);
|
||||||
if (tbeg == tend) {
|
});
|
||||||
pbuff.decodePath(rshape, false, [&](const WgVertexBuffer& path_buff) {
|
|
||||||
appendShape(context, path_buff);
|
|
||||||
});
|
|
||||||
} else if (rshape.stroke->trim.simultaneous) {
|
|
||||||
pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) {
|
|
||||||
appendShape(context, path_buff);
|
|
||||||
if (loop) {
|
|
||||||
proceedStrokes(context, rshape.stroke, tbeg, 1.0f, path_buff);
|
|
||||||
proceedStrokes(context, rshape.stroke, 0.0f, tend, path_buff);
|
|
||||||
} else {
|
|
||||||
proceedStrokes(context, rshape.stroke, tbeg, tend, path_buff);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
float totalLen = 0.0f;
|
|
||||||
pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) {
|
|
||||||
appendShape(context, path_buff);
|
|
||||||
totalLen += path_buff.total();
|
|
||||||
});
|
|
||||||
float len_beg = totalLen * tbeg; // trim length begin
|
|
||||||
float len_end = totalLen * tend; // trim length end
|
|
||||||
float len_acc = 0.0; // accumulated length
|
|
||||||
// append strokes
|
|
||||||
pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) {
|
|
||||||
float len_path = path_buff.total(); // current path length
|
|
||||||
if (loop) {
|
|
||||||
if (len_acc + len_path >= len_beg) {
|
|
||||||
auto tbeg = len_acc <= len_beg ? (len_beg - len_acc) / len_path : 0.0f;
|
|
||||||
proceedStrokes(context, rshape.stroke, tbeg, 1.0f, path_buff);
|
|
||||||
}
|
|
||||||
if (len_acc < len_end) {
|
|
||||||
auto tend = len_acc + len_path >= len_end ? (len_end - len_acc) / len_path : 1.0f;
|
|
||||||
proceedStrokes(context, rshape.stroke, 0.0f, tend, path_buff);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (len_acc + len_path >= len_beg && len_acc <= len_end) {
|
|
||||||
auto tbeg = len_acc <= len_beg ? (len_beg - len_acc) / len_path : 0.0f;
|
|
||||||
auto tend = len_acc + len_path >= len_end ? (len_end - len_acc) / len_path : 1.0f;
|
|
||||||
proceedStrokes(context, rshape.stroke, tbeg, tend, path_buff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
len_acc += len_path;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// update shapes bbox (with empty path handling)
|
// update shapes bbox (with empty path handling)
|
||||||
if ((this->meshGroupShapesBBox.meshes.count > 0 ) ||
|
if ((this->meshGroupShapesBBox.meshes.count > 0 ) ||
|
||||||
|
@ -450,29 +412,15 @@ void WgRenderDataShape::updateMeshes(WgContext& context, const RenderShape &rsha
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WgRenderDataShape::proceedStrokes(WgContext& context, const RenderStroke* rstroke, float tbeg, float tend, const WgVertexBuffer& buff)
|
void WgRenderDataShape::proceedStrokes(WgContext& context, const RenderStroke* rstroke, const WgVertexBuffer& buff)
|
||||||
{
|
{
|
||||||
assert(rstroke);
|
assert(rstroke);
|
||||||
static WgVertexBufferInd strokesGenerator;
|
static WgVertexBufferInd strokesGenerator;
|
||||||
strokesGenerator.reset(buff.tscale);
|
strokesGenerator.reset(buff.tscale);
|
||||||
// trim -> dash -> stroke
|
|
||||||
if ((tbeg != 0.0f) || (tend != 1.0f)) {
|
if (rstroke->dashPattern) strokesGenerator.appendStrokesDashed(buff, rstroke);
|
||||||
if (tbeg == tend) return;
|
else strokesGenerator.appendStrokes(buff, rstroke);
|
||||||
WgVertexBuffer trimed_buff;
|
|
||||||
trimed_buff.reset(buff.tscale);
|
|
||||||
trimed_buff.trim(buff, tbeg, tend);
|
|
||||||
trimed_buff.updateDistances();
|
|
||||||
// trim ->dash -> stroke
|
|
||||||
if (rstroke->dashPattern) strokesGenerator.appendStrokesDashed(trimed_buff, rstroke);
|
|
||||||
// trim -> stroke
|
|
||||||
else strokesGenerator.appendStrokes(trimed_buff, rstroke);
|
|
||||||
} else
|
|
||||||
// dash -> stroke
|
|
||||||
if (rstroke->dashPattern) {
|
|
||||||
strokesGenerator.appendStrokesDashed(buff, rstroke);
|
|
||||||
// stroke
|
|
||||||
} else
|
|
||||||
strokesGenerator.appendStrokes(buff, rstroke);
|
|
||||||
appendStroke(context, strokesGenerator);
|
appendStroke(context, strokesGenerator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ struct WgRenderDataShape: public WgRenderDataPaint
|
||||||
void updateBBox(Point pmin, Point pmax);
|
void updateBBox(Point pmin, Point pmax);
|
||||||
void updateAABB(const Matrix& tr);
|
void updateAABB(const Matrix& tr);
|
||||||
void updateMeshes(WgContext& context, const RenderShape& rshape, const Matrix& tr);
|
void updateMeshes(WgContext& context, const RenderShape& rshape, const Matrix& tr);
|
||||||
void proceedStrokes(WgContext& context, const RenderStroke* rstroke, float tbeg, float tend, const WgVertexBuffer& buff);
|
void proceedStrokes(WgContext& context, const RenderStroke* rstroke, const WgVertexBuffer& buff);
|
||||||
void releaseMeshes(WgContext& context);
|
void releaseMeshes(WgContext& context);
|
||||||
void release(WgContext& context) override;
|
void release(WgContext& context) override;
|
||||||
Type type() override { return Type::Shape; };
|
Type type() override { return Type::Shape; };
|
||||||
|
|
Loading…
Add table
Reference in a new issue