mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
wg_engine: fix cubic splines and circles tesselation quality
Tesseletion factor now depends on scale matix of the shape
This commit is contained in:
parent
f13c72e3d7
commit
8b27efc99f
2 changed files with 21 additions and 11 deletions
|
@ -39,15 +39,17 @@ struct WgVertexBuffer
|
|||
float vleng[WG_POINTS_COUNT]; // distance to the first point through all previous points
|
||||
size_t vcount{};
|
||||
bool closed{};
|
||||
float tscale = 1.0f; // tesselation scale
|
||||
|
||||
// callback for external process of polyline
|
||||
using onPolylineFn = std::function<void(const WgVertexBuffer& buff)>;
|
||||
|
||||
// reset buffer
|
||||
void reset()
|
||||
void reset(float scale)
|
||||
{
|
||||
vcount = 0;
|
||||
closed = false;
|
||||
tscale = scale;
|
||||
}
|
||||
|
||||
// get the last point with optional index offset from the end
|
||||
|
@ -134,8 +136,8 @@ struct WgVertexBuffer
|
|||
{
|
||||
// get approx circle length
|
||||
float clen = 2.0f * radius * MATH_PI;
|
||||
size_t nsegs = std::max((uint32_t)(clen / 8), 16U);
|
||||
// append circle
|
||||
size_t nsegs = std::max((uint32_t)(clen * tscale / 8), 16U);
|
||||
// append circle^
|
||||
Point prev { std::sin(0.0f) * radius, std::cos(0.0f) * radius };
|
||||
for (size_t i = 1; i <= nsegs; i++) {
|
||||
float t = (2.0f * MATH_PI * i) / nsegs;
|
||||
|
@ -151,8 +153,8 @@ struct WgVertexBuffer
|
|||
void appendCubic(const Point& v0, const Point& v1, const Point& v2, const Point& v3)
|
||||
{
|
||||
// get approx cubic length
|
||||
float clen = length(v0 - v1) + length(v1 - v2) + length(v2 - v3);
|
||||
size_t nsegs = std::max((uint32_t)(clen / 8), 16U);
|
||||
float clen = (length(v0 - v1) + length(v1 - v2) + length(v2 - v3));
|
||||
size_t nsegs = std::max((uint32_t)(clen * tscale / 16), 16U);
|
||||
// append cubic
|
||||
Bezier bezier{v0, v1, v2, v3};
|
||||
for (size_t i = 1; i <= nsegs; i++)
|
||||
|
@ -189,7 +191,7 @@ struct WgVertexBuffer
|
|||
void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline)
|
||||
{
|
||||
// decode path
|
||||
reset();
|
||||
reset(tscale);
|
||||
size_t pntIndex = 0;
|
||||
for (uint32_t cmdIndex = 0; cmdIndex < rshape.path.cmds.count; cmdIndex++) {
|
||||
PathCommand cmd = rshape.path.cmds[cmdIndex];
|
||||
|
@ -198,7 +200,7 @@ struct WgVertexBuffer
|
|||
if (update_dist) updateDistances();
|
||||
if ((onPolyline) && (vcount != 0))
|
||||
onPolyline(*this);
|
||||
reset();
|
||||
reset(tscale);
|
||||
append(rshape.path.pts[pntIndex]);
|
||||
pntIndex++;
|
||||
} else if (cmd == PathCommand::LineTo) {
|
||||
|
@ -226,11 +228,13 @@ struct WgVertexBufferInd
|
|||
uint32_t ibuff[WG_POINTS_COUNT*16];
|
||||
size_t vcount = 0;
|
||||
size_t icount = 0;
|
||||
float tscale = 1.0f;
|
||||
|
||||
// reset buffer
|
||||
void reset()
|
||||
void reset(float scale)
|
||||
{
|
||||
icount = vcount = 0;
|
||||
tscale = scale;
|
||||
}
|
||||
|
||||
// get min and max values of the buffer
|
||||
|
@ -269,7 +273,7 @@ struct WgVertexBufferInd
|
|||
{
|
||||
// dashed buffer
|
||||
WgVertexBuffer dashed;
|
||||
dashed.reset();
|
||||
dashed.reset(tscale);
|
||||
// ignore single points polyline
|
||||
if (buff.vcount < 2) return;
|
||||
const float* dashPattern = rstroke->dashPattern;
|
||||
|
@ -294,7 +298,7 @@ struct WgVertexBufferInd
|
|||
if (index_dash % 2 != 0) {
|
||||
dashed.updateDistances();
|
||||
appendStrokes(dashed, rstroke);
|
||||
dashed.reset();
|
||||
dashed.reset(tscale);
|
||||
}
|
||||
}
|
||||
// update current subline length
|
||||
|
@ -391,6 +395,7 @@ struct WgVertexBufferInd
|
|||
if ((rstroke->join == StrokeJoin::Round) || (rstroke->cap == StrokeCap::Round)) {
|
||||
// create mesh for circle
|
||||
WgVertexBuffer circle;
|
||||
circle.reset(buff.tscale);
|
||||
circle.appendCircle(halfWidth);
|
||||
// append caps (round)
|
||||
if (rstroke->cap == StrokeCap::Round) {
|
||||
|
|
|
@ -381,8 +381,12 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha
|
|||
releaseMeshes(context);
|
||||
strokeFirst = rshape.stroke ? rshape.stroke->strokeFirst : false;
|
||||
|
||||
// get object scale
|
||||
float scale = std::max(std::min(length(Point{tr.e11 + tr.e12,tr.e21 + tr.e22}), 8.0f), 1.0f);
|
||||
|
||||
// path decoded vertex buffer
|
||||
WgVertexBuffer pbuff;
|
||||
pbuff.reset(scale);
|
||||
// append shape without strokes
|
||||
if (!rshape.stroke) {
|
||||
pbuff.decodePath(rshape, false, [&](const WgVertexBuffer& path_buff) {
|
||||
|
@ -451,11 +455,12 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha
|
|||
void WgRenderDataShape::proceedStrokes(WgContext context, const RenderStroke* rstroke, float tbeg, float tend, const WgVertexBuffer& buff)
|
||||
{
|
||||
assert(rstroke);
|
||||
gStrokesGenerator->reset();
|
||||
gStrokesGenerator->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
|
||||
|
|
Loading…
Add table
Reference in a new issue