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));
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
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;
|
||||
ARRAY_FOREACH(p, rshape.path.cmds) {
|
||||
auto cmd = *p;
|
||||
for (uint32_t i = 0; i < cmdCnt; i++) {
|
||||
auto& cmd = cmds[i];
|
||||
if (cmd == PathCommand::MoveTo) {
|
||||
// after path decoding we need to update distances and total length
|
||||
if (update_dist) updateDistances();
|
||||
if ((onPolyline) && (vcount > 0)) onPolyline(*this);
|
||||
reset(tscale);
|
||||
append(rshape.path.pts[pntIndex]);
|
||||
append(pts[pntIndex]);
|
||||
pntIndex++;
|
||||
} else if (cmd == PathCommand::LineTo) {
|
||||
append(rshape.path.pts[pntIndex]);
|
||||
append(pts[pntIndex]);
|
||||
pntIndex++;
|
||||
} else if (cmd == PathCommand::Close) {
|
||||
close();
|
||||
// proceed path if close command is not the last command and next command is LineTo or CubicTo
|
||||
if (((p + 1) < rshape.path.cmds.end()) &&
|
||||
((*(p + 1) == PathCommand::LineTo) ||
|
||||
(*(p + 1) == PathCommand::CubicTo))) {
|
||||
if (i + 1 < cmdCnt &&
|
||||
(cmds[i + 1] == PathCommand::LineTo ||
|
||||
cmds[i + 1] == PathCommand::CubicTo)) {
|
||||
// proceed current path
|
||||
if (update_dist) updateDistances();
|
||||
if ((vcount > 0) && (onPolyline)) onPolyline(*this);
|
||||
|
@ -221,10 +216,14 @@ struct WgVertexBuffer
|
|||
}
|
||||
} else if (cmd == PathCommand::CubicTo) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
free(trimmedCmds);
|
||||
free(trimmedPts);
|
||||
|
||||
// after path decoding we need to update distances and total length
|
||||
if (update_dist) updateDistances();
|
||||
if ((vcount > 0) && (onPolyline)) onPolyline(*this);
|
||||
|
|
|
@ -385,61 +385,23 @@ void WgRenderDataShape::updateMeshes(WgContext& context, const RenderShape &rsha
|
|||
// path decoded vertex buffer
|
||||
WgVertexBuffer pbuff;
|
||||
pbuff.reset(scale);
|
||||
// append shape without strokes
|
||||
if (!rshape.stroke) {
|
||||
pbuff.decodePath(rshape, false, [&](const WgVertexBuffer& path_buff) {
|
||||
appendShape(context, path_buff);
|
||||
});
|
||||
// append shape with strokes
|
||||
} else {
|
||||
float tbeg{}, tend{};
|
||||
if (!rshape.stroke->trim.get(tbeg, tend)) { tbeg = 0.0f; tend = 1.0f; }
|
||||
bool loop = tbeg > tend;
|
||||
if (tbeg == tend) {
|
||||
pbuff.decodePath(rshape, false, [&](const WgVertexBuffer& path_buff) {
|
||||
appendShape(context, path_buff);
|
||||
});
|
||||
} else if (rshape.stroke->trim.simultaneous) {
|
||||
|
||||
if (rshape.strokeTrim()) {
|
||||
WgVertexBuffer trimbuff;
|
||||
trimbuff.reset(scale);
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
trimbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) {
|
||||
appendShape(context, path_buff);
|
||||
proceedStrokes(context, rshape.stroke, path_buff);
|
||||
}, true);
|
||||
} else {
|
||||
float totalLen = 0.0f;
|
||||
pbuff.decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) {
|
||||
appendShape(context, path_buff);
|
||||
totalLen += path_buff.total();
|
||||
if (rshape.stroke) proceedStrokes(context, rshape.stroke, path_buff);
|
||||
});
|
||||
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)
|
||||
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);
|
||||
static WgVertexBufferInd strokesGenerator;
|
||||
strokesGenerator.reset(buff.tscale);
|
||||
// trim -> dash -> stroke
|
||||
if ((tbeg != 0.0f) || (tend != 1.0f)) {
|
||||
if (tbeg == tend) return;
|
||||
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);
|
||||
|
||||
if (rstroke->dashPattern) strokesGenerator.appendStrokesDashed(buff, rstroke);
|
||||
else strokesGenerator.appendStrokes(buff, rstroke);
|
||||
|
||||
appendStroke(context, strokesGenerator);
|
||||
}
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ struct WgRenderDataShape: public WgRenderDataPaint
|
|||
void updateBBox(Point pmin, Point pmax);
|
||||
void updateAABB(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 release(WgContext& context) override;
|
||||
Type type() override { return Type::Shape; };
|
||||
|
|
Loading…
Add table
Reference in a new issue