wg_engine: fix cubic splines and circles tesselation quality

Tesseletion factor now depends on scale matix of the shape
This commit is contained in:
Sergii Liebodkin 2024-10-30 12:02:23 +00:00 committed by Mira Grudzinska
parent f13c72e3d7
commit 8b27efc99f
2 changed files with 21 additions and 11 deletions

View file

@ -39,15 +39,17 @@ struct WgVertexBuffer
float vleng[WG_POINTS_COUNT]; // distance to the first point through all previous points float vleng[WG_POINTS_COUNT]; // distance to the first point through all previous points
size_t vcount{}; size_t vcount{};
bool closed{}; bool closed{};
float tscale = 1.0f; // tesselation scale
// callback for external process of polyline // callback for external process of polyline
using onPolylineFn = std::function<void(const WgVertexBuffer& buff)>; using onPolylineFn = std::function<void(const WgVertexBuffer& buff)>;
// reset buffer // reset buffer
void reset() void reset(float scale)
{ {
vcount = 0; vcount = 0;
closed = false; closed = false;
tscale = scale;
} }
// get the last point with optional index offset from the end // get the last point with optional index offset from the end
@ -134,8 +136,8 @@ struct WgVertexBuffer
{ {
// get approx circle length // get approx circle length
float clen = 2.0f * radius * MATH_PI; float clen = 2.0f * radius * MATH_PI;
size_t nsegs = std::max((uint32_t)(clen / 8), 16U); size_t nsegs = std::max((uint32_t)(clen * tscale / 8), 16U);
// append circle // append circle^
Point prev { std::sin(0.0f) * radius, std::cos(0.0f) * radius }; Point prev { std::sin(0.0f) * radius, std::cos(0.0f) * radius };
for (size_t i = 1; i <= nsegs; i++) { for (size_t i = 1; i <= nsegs; i++) {
float t = (2.0f * MATH_PI * i) / nsegs; 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) void appendCubic(const Point& v0, const Point& v1, const Point& v2, const Point& v3)
{ {
// get approx cubic length // get approx cubic length
float clen = length(v0 - v1) + length(v1 - v2) + length(v2 - v3); float clen = (length(v0 - v1) + length(v1 - v2) + length(v2 - v3));
size_t nsegs = std::max((uint32_t)(clen / 8), 16U); size_t nsegs = std::max((uint32_t)(clen * tscale / 16), 16U);
// append cubic // append cubic
Bezier bezier{v0, v1, v2, v3}; Bezier bezier{v0, v1, v2, v3};
for (size_t i = 1; i <= nsegs; i++) for (size_t i = 1; i <= nsegs; i++)
@ -189,7 +191,7 @@ struct WgVertexBuffer
void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline) void decodePath(const RenderShape& rshape, bool update_dist, onPolylineFn onPolyline)
{ {
// decode path // decode path
reset(); reset(tscale);
size_t pntIndex = 0; size_t pntIndex = 0;
for (uint32_t cmdIndex = 0; cmdIndex < rshape.path.cmds.count; cmdIndex++) { for (uint32_t cmdIndex = 0; cmdIndex < rshape.path.cmds.count; cmdIndex++) {
PathCommand cmd = rshape.path.cmds[cmdIndex]; PathCommand cmd = rshape.path.cmds[cmdIndex];
@ -198,7 +200,7 @@ struct WgVertexBuffer
if (update_dist) updateDistances(); if (update_dist) updateDistances();
if ((onPolyline) && (vcount != 0)) if ((onPolyline) && (vcount != 0))
onPolyline(*this); onPolyline(*this);
reset(); reset(tscale);
append(rshape.path.pts[pntIndex]); append(rshape.path.pts[pntIndex]);
pntIndex++; pntIndex++;
} else if (cmd == PathCommand::LineTo) { } else if (cmd == PathCommand::LineTo) {
@ -226,11 +228,13 @@ struct WgVertexBufferInd
uint32_t ibuff[WG_POINTS_COUNT*16]; uint32_t ibuff[WG_POINTS_COUNT*16];
size_t vcount = 0; size_t vcount = 0;
size_t icount = 0; size_t icount = 0;
float tscale = 1.0f;
// reset buffer // reset buffer
void reset() void reset(float scale)
{ {
icount = vcount = 0; icount = vcount = 0;
tscale = scale;
} }
// get min and max values of the buffer // get min and max values of the buffer
@ -269,7 +273,7 @@ struct WgVertexBufferInd
{ {
// dashed buffer // dashed buffer
WgVertexBuffer dashed; WgVertexBuffer dashed;
dashed.reset(); dashed.reset(tscale);
// ignore single points polyline // ignore single points polyline
if (buff.vcount < 2) return; if (buff.vcount < 2) return;
const float* dashPattern = rstroke->dashPattern; const float* dashPattern = rstroke->dashPattern;
@ -294,7 +298,7 @@ struct WgVertexBufferInd
if (index_dash % 2 != 0) { if (index_dash % 2 != 0) {
dashed.updateDistances(); dashed.updateDistances();
appendStrokes(dashed, rstroke); appendStrokes(dashed, rstroke);
dashed.reset(); dashed.reset(tscale);
} }
} }
// update current subline length // update current subline length
@ -391,6 +395,7 @@ struct WgVertexBufferInd
if ((rstroke->join == StrokeJoin::Round) || (rstroke->cap == StrokeCap::Round)) { if ((rstroke->join == StrokeJoin::Round) || (rstroke->cap == StrokeCap::Round)) {
// create mesh for circle // create mesh for circle
WgVertexBuffer circle; WgVertexBuffer circle;
circle.reset(buff.tscale);
circle.appendCircle(halfWidth); circle.appendCircle(halfWidth);
// append caps (round) // append caps (round)
if (rstroke->cap == StrokeCap::Round) { if (rstroke->cap == StrokeCap::Round) {

View file

@ -381,8 +381,12 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha
releaseMeshes(context); releaseMeshes(context);
strokeFirst = rshape.stroke ? rshape.stroke->strokeFirst : false; 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 // path decoded vertex buffer
WgVertexBuffer pbuff; WgVertexBuffer pbuff;
pbuff.reset(scale);
// append shape without strokes // append shape without strokes
if (!rshape.stroke) { if (!rshape.stroke) {
pbuff.decodePath(rshape, false, [&](const WgVertexBuffer& path_buff) { 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) void WgRenderDataShape::proceedStrokes(WgContext context, const RenderStroke* rstroke, float tbeg, float tend, const WgVertexBuffer& buff)
{ {
assert(rstroke); assert(rstroke);
gStrokesGenerator->reset(); gStrokesGenerator->reset(buff.tscale);
// trim -> dash -> stroke // trim -> dash -> stroke
if ((tbeg != 0.0f) || (tend != 1.0f)) { if ((tbeg != 0.0f) || (tend != 1.0f)) {
if (tbeg == tend) return; if (tbeg == tend) return;
WgVertexBuffer trimed_buff; WgVertexBuffer trimed_buff;
trimed_buff.reset(buff.tscale);
trimed_buff.trim(buff, tbeg, tend); trimed_buff.trim(buff, tbeg, tend);
trimed_buff.updateDistances(); trimed_buff.updateDistances();
// trim ->dash -> stroke // trim ->dash -> stroke