diff --git a/src/renderer/wg_engine/tvgWgGeometry.cpp b/src/renderer/wg_engine/tvgWgGeometry.cpp index 09097e08..9002e61a 100755 --- a/src/renderer/wg_engine/tvgWgGeometry.cpp +++ b/src/renderer/wg_engine/tvgWgGeometry.cpp @@ -65,7 +65,10 @@ void WgPolyline::appendPoint(WgPoint pt) { if (pts.count > 0) { float distance = pts.last().dist(pt); - if (distance > 0) { + // adjust precision because of real user data points + // can be further than the accepted accuracy, + // but still be considered tha same + if (!tvg::zero(distance*1e-1)) { // update min and max indexes iminx = pts[iminx].x >= pt.x ? pts.count : iminx; imaxx = pts[imaxx].x <= pt.x ? pts.count : imaxx; @@ -217,13 +220,13 @@ void WgGeometryData::appendRect(WgPoint p0, WgPoint p1, WgPoint p2, WgPoint p3) } -void WgGeometryData::appendCircle(WgPoint center, float radius) +void WgGeometryData::appendCircle(WgPoint center, float radius, float scale) { uint32_t indexCenter = positions.pts.count; positions.appendPoint(center); uint32_t index = positions.pts.count; positions.appendPoint({ center.x + gMath->sinus[0] * radius, center.y + gMath->cosin[0] * radius }); - uint32_t nPoints = (uint32_t)(radius * 2.0f); + uint32_t nPoints = (uint32_t)(scale * radius * 2.0f); nPoints = nPoints < 8 ? 8 : nPoints; const uint32_t step = gMath->sinus.count / nPoints; for (uint32_t i = step; i < gMath->sinus.count; i += step) { @@ -279,7 +282,7 @@ void WgGeometryData::appendBlitBox() } -void WgGeometryData::appendStrokeDashed(const WgPolyline* polyline, const RenderStroke *stroke) +void WgGeometryData::appendStrokeDashed(const WgPolyline* polyline, const RenderStroke *stroke, float scale) { assert(stroke); assert(polyline); @@ -308,7 +311,7 @@ void WgGeometryData::appendStrokeDashed(const WgPolyline* polyline, const Render currentLength += stroke->dashPattern[dashIndex]; // append stroke if dash if (dashIndex % 2 != 0) { - appendStroke(&dashed, stroke); + appendStroke(&dashed, stroke, scale); dashed.clear(); } } @@ -318,14 +321,14 @@ void WgGeometryData::appendStrokeDashed(const WgPolyline* polyline, const Render // draw last subline if (dashIndex % 2 == 0) { dashed.appendPoint(pts.last()); - appendStroke(&dashed, stroke); + appendStroke(&dashed, stroke, scale); dashed.clear(); } } } -void WgGeometryData::appendStrokeJoin(const WgPoint& v0, const WgPoint& v1, const WgPoint& v2, StrokeJoin join, float halfWidth, float miterLimit) +void WgGeometryData::appendStrokeJoin(const WgPoint& v0, const WgPoint& v1, const WgPoint& v2, StrokeJoin join, float halfWidth, float miterLimit, float scale) { WgPoint dir0 = (v1 - v0).normal(); WgPoint dir1 = (v2 - v1).normal(); @@ -334,12 +337,13 @@ void WgGeometryData::appendStrokeJoin(const WgPoint& v0, const WgPoint& v1, cons WgPoint offset0 = nrm0 * halfWidth; WgPoint offset1 = nrm1 * halfWidth; if (join == StrokeJoin::Round) { - appendCircle(v1, halfWidth); + appendCircle(v1, halfWidth, scale); } else if (join == StrokeJoin::Bevel) { appendRect(v1 - offset0, v1 + offset1, v1 - offset1, v1 + offset0); } else if (join == StrokeJoin::Miter) { WgPoint nrm = (nrm0 + nrm1); - if (!tvg::zero(dir0.x * dir1.y - dir0.y * dir1.x)) { + // adjust precision because dot product could return above 1 that results acos returns Nan + if (!tvg::zero((dir0.x * dir1.y - dir0.y * dir1.x)*1e-1)) { nrm.normalize(); float cosine = nrm.dot(nrm0); float angle = std::acos(dir0.dot(dir1.negative())); @@ -355,7 +359,7 @@ void WgGeometryData::appendStrokeJoin(const WgPoint& v0, const WgPoint& v1, cons } -void WgGeometryData::appendStroke(const WgPolyline* polyline, const RenderStroke *stroke) +void WgGeometryData::appendStroke(const WgPolyline* polyline, const RenderStroke *stroke, float scale) { assert(stroke); assert(polyline); @@ -369,8 +373,8 @@ void WgGeometryData::appendStroke(const WgPolyline* polyline, const RenderStroke WgPoint nrm0 = WgPoint{ -dir0.y, +dir0.x }; if (stroke->cap == StrokeCap::Round) { appendRect(v0 - nrm0 * wdt, v0 + nrm0 * wdt, v1 - nrm0 * wdt, v1 + nrm0 * wdt); - appendCircle(polyline->pts[0], wdt); - appendCircle(polyline->pts[1], wdt); + appendCircle(polyline->pts[0], wdt, scale); + appendCircle(polyline->pts[1], wdt, scale); } else if (stroke->cap == StrokeCap::Butt) { appendRect(v0 - nrm0 * wdt, v0 + nrm0 * wdt, v1 - nrm0 * wdt, v1 + nrm0 * wdt); } else if (stroke->cap == StrokeCap::Square) { @@ -384,7 +388,7 @@ void WgGeometryData::appendStroke(const WgPolyline* polyline, const RenderStroke WgPoint v0 = polyline->pts[polyline->pts.count - 2]; WgPoint v1 = polyline->pts[0]; WgPoint v2 = polyline->pts[1]; - appendStrokeJoin(v0, v1, v2, stroke->join, wdt, stroke->miterlimit); + appendStrokeJoin(v0, v1, v2, stroke->join, wdt, stroke->miterlimit, scale); } else { // append first cap WgPoint v0 = polyline->pts[0]; @@ -392,7 +396,7 @@ void WgGeometryData::appendStroke(const WgPolyline* polyline, const RenderStroke WgPoint dir0 = (v1 - v0) / polyline->dist[1]; WgPoint nrm0 = WgPoint{ -dir0.y, +dir0.x }; if (stroke->cap == StrokeCap::Round) { - appendCircle(v0, wdt); + appendCircle(v0, wdt, scale); } else if (stroke->cap == StrokeCap::Butt) { // no cap needed } else if (stroke->cap == StrokeCap::Square) { @@ -405,7 +409,7 @@ void WgGeometryData::appendStroke(const WgPolyline* polyline, const RenderStroke dir0 = (v1 - v0) / polyline->dist[polyline->pts.count - 1]; nrm0 = WgPoint{ -dir0.y, +dir0.x }; if (stroke->cap == StrokeCap::Round) { - appendCircle(v1, wdt); + appendCircle(v1, wdt, scale); } else if (stroke->cap == StrokeCap::Butt) { // no cap needed } else if (stroke->cap == StrokeCap::Square) { @@ -425,7 +429,7 @@ void WgGeometryData::appendStroke(const WgPolyline* polyline, const RenderStroke if (i > 0) { WgPoint v0 = polyline->pts[i - 1]; - appendStrokeJoin(v0, v1, v2, stroke->join, wdt, stroke->miterlimit); + appendStrokeJoin(v0, v1, v2, stroke->join, wdt, stroke->miterlimit, scale); } } } diff --git a/src/renderer/wg_engine/tvgWgGeometry.h b/src/renderer/wg_engine/tvgWgGeometry.h index 630b0932..ff0f61de 100755 --- a/src/renderer/wg_engine/tvgWgGeometry.h +++ b/src/renderer/wg_engine/tvgWgGeometry.h @@ -111,16 +111,15 @@ struct WgGeometryData WgGeometryData(); void clear(); - void appendCubic(WgPoint p1, WgPoint p2, WgPoint p3); void appendBox(WgPoint pmin, WgPoint pmax); void appendRect(WgPoint p0, WgPoint p1, WgPoint p2, WgPoint p3); - void appendCircle(WgPoint center, float radius); + void appendCircle(WgPoint center, float radius, float scale = 1.0f); void appendImageBox(float w, float h); void appendBlitBox(); - void appendStrokeDashed(const WgPolyline* polyline, const RenderStroke *stroke); + void appendStrokeDashed(const WgPolyline* polyline, const RenderStroke *stroke, float scale); void appendStrokeJoin(const WgPoint& v0, const WgPoint& v1, const WgPoint& v2, - StrokeJoin join, float halfWidth, float miterLimit); - void appendStroke(const WgPolyline* polyline, const RenderStroke *stroke); + StrokeJoin join, float halfWidth, float miterLimit, float scale); + void appendStroke(const WgPolyline* polyline, const RenderStroke *stroke, float scale); }; #endif // _TVG_WG_GEOMETRY_H_ \ No newline at end of file diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index 5f058c03..ba36add0 100755 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -22,6 +22,7 @@ */ #include +#include "tvgMath.h" #include "tvgWgRenderData.h" #include "tvgWgShaderTypes.h" @@ -327,11 +328,12 @@ void WgRenderDataShape::updateAABB(const Matrix& rt) { } -void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rshape, const Matrix& rt) +void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rshape, const Matrix& tr) { releaseMeshes(context); strokeFirst = rshape.stroke ? rshape.stroke->strokeFirst : false; + float scale = std::max(sqrt(tr.e11*tr.e11 + tr.e21*tr.e21), 1.0f); Array polylines{}; // decode path size_t pntIndex = 0; @@ -349,16 +351,16 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha polylines.last()->close(); } else if (cmd == PathCommand::CubicTo) { assert(polylines.last()->pts.count > 0); - WgPoint pt0 = polylines.last()->pts.last().trans(rt); - WgPoint pt1 = WgPoint(rshape.path.pts[pntIndex + 0]).trans(rt); - WgPoint pt2 = WgPoint(rshape.path.pts[pntIndex + 1]).trans(rt); - WgPoint pt3 = WgPoint(rshape.path.pts[pntIndex + 2]).trans(rt); - uint32_t nsegs = (uint32_t)(pt0.dist(pt1) + pt1.dist(pt2) + pt2.dist(pt3)); + WgPoint pt0 = polylines.last()->pts.last().trans(tr); + WgPoint pt1 = WgPoint(rshape.path.pts[pntIndex + 0]).trans(tr); + WgPoint pt2 = WgPoint(rshape.path.pts[pntIndex + 1]).trans(tr); + WgPoint pt3 = WgPoint(rshape.path.pts[pntIndex + 2]).trans(tr); + uint32_t nsegs = std::max((uint32_t)(pt0.dist(pt1) + pt1.dist(pt2) + pt2.dist(pt3)), 32U); polylines.last()->appendCubic( rshape.path.pts[pntIndex + 0], rshape.path.pts[pntIndex + 1], rshape.path.pts[pntIndex + 2], - nsegs / 2); + nsegs / 4); pntIndex += 3; } } @@ -375,13 +377,13 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha if (!rshape.stroke->strokeTrim(trimBegin, trimEnd)) { trimBegin = 0.0f; trimEnd = 1.0f; } if (rshape.stroke->trim.simultaneous) { for (uint32_t i = 0; i < polylines.count; i++) - updateStrokes(context, polylines[i], rshape.stroke, trimBegin, trimEnd); + updateStrokes(context, polylines[i], rshape.stroke, scale, trimBegin, trimEnd); } else { if (trimBegin <= trimEnd) { - updateStrokesList(context, polylines, rshape.stroke, totalLen, trimBegin, trimEnd); + updateStrokesList(context, polylines, rshape.stroke, totalLen, scale, trimBegin, trimEnd); } else { - updateStrokesList(context, polylines, rshape.stroke, totalLen, 0.0f, trimEnd); - updateStrokesList(context, polylines, rshape.stroke, totalLen, trimBegin, 1.0f); + updateStrokesList(context, polylines, rshape.stroke, totalLen, scale, 0.0f, trimEnd); + updateStrokesList(context, polylines, rshape.stroke, totalLen, scale, trimBegin, 1.0f); } } } @@ -389,7 +391,7 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha for (uint32_t i = 0; i < polylines.count; i++) delete polylines[i]; // update shapes bbox - updateAABB(rt); + updateAABB(tr); meshDataBBox.update(context, pMin, pMax); } @@ -407,7 +409,7 @@ void WgRenderDataShape::updateShapes(WgContext& context, const WgPolyline* polyl } } -void WgRenderDataShape::updateStrokesList(WgContext& context, Array polylines, const RenderStroke* rstroke, float totalLen, float trimBegin, float trimEnd) +void WgRenderDataShape::updateStrokesList(WgContext& context, Array polylines, const RenderStroke* rstroke, float scale, float totalLen, float trimBegin, float trimEnd) { float tp1 = totalLen * trimBegin; // trim point begin float tp2 = totalLen * trimEnd; // trim point end @@ -417,7 +419,7 @@ void WgRenderDataShape::updateStrokesList(WgContext& context, Array float trimBegin = ((pc <= tp1) && (pc + pl > tp1)) ? (tp1 - pc) / pl : 0.0f; float trimEnd = ((pc <= tp2) && (pc + pl > tp2)) ? (tp2 - pc) / pl : 1.0f; if ((pc + pl >= tp1) && (pc <= tp2)) - updateStrokes(context, polylines[i], rstroke, trimBegin, trimEnd); + updateStrokes(context, polylines[i], rstroke, scale, trimBegin, trimEnd); pc += pl; // break if reached the tail if (pc > tp2) break; @@ -425,7 +427,7 @@ void WgRenderDataShape::updateStrokesList(WgContext& context, Array } -void WgRenderDataShape::updateStrokes(WgContext& context, const WgPolyline* polyline, const RenderStroke* rstroke, float trimBegin, float trimEnd) +void WgRenderDataShape::updateStrokes(WgContext& context, const WgPolyline* polyline, const RenderStroke* rstroke, float scale, float trimBegin, float trimEnd) { assert(polyline); // generate strokes geometry @@ -442,7 +444,7 @@ void WgRenderDataShape::updateStrokes(WgContext& context, const WgPolyline* poly polyline->trim(&trimmed, trimBegin, 1.0f); polyline->trim(&trimmed, 0.0f, trimEnd); } - geometryData.appendStrokeDashed(&trimmed, rstroke); + geometryData.appendStrokeDashed(&trimmed, rstroke, scale); } else // trim -> stroke if ((trimBegin != 0.0f) || (trimEnd != 1.0f)) { trimmed.clear(); @@ -452,12 +454,12 @@ void WgRenderDataShape::updateStrokes(WgContext& context, const WgPolyline* poly polyline->trim(&trimmed, trimBegin, 1.0f); polyline->trim(&trimmed, 0.0f, trimEnd); } - geometryData.appendStroke(&trimmed, rstroke); + geometryData.appendStroke(&trimmed, rstroke, scale); } else // split -> stroke if (rstroke->dashPattern) { - geometryData.appendStrokeDashed(polyline, rstroke); + geometryData.appendStrokeDashed(polyline, rstroke, scale); } else { // stroke - geometryData.appendStroke(polyline, rstroke); + geometryData.appendStroke(polyline, rstroke, scale); } // append render meshes and bboxes if(geometryData.positions.pts.count >= 3) { diff --git a/src/renderer/wg_engine/tvgWgRenderData.h b/src/renderer/wg_engine/tvgWgRenderData.h index 8a066b53..2055681e 100755 --- a/src/renderer/wg_engine/tvgWgRenderData.h +++ b/src/renderer/wg_engine/tvgWgRenderData.h @@ -126,10 +126,10 @@ struct WgRenderDataShape: public WgRenderDataPaint void updateBBox(WgPoint pmin, WgPoint pmax); void updateAABB(const Matrix& rt); - void updateMeshes(WgContext& context, const RenderShape& rshape, const Matrix& rt); + void updateMeshes(WgContext& context, const RenderShape& rshape, const Matrix& tr); void updateShapes(WgContext& context, const WgPolyline* polyline); - void updateStrokesList(WgContext& context, Array polylines, const RenderStroke* rstroke, float totalLen, float trimBegin, float trimEnd); - void updateStrokes(WgContext& context, const WgPolyline* polyline, const RenderStroke* rstroke, float trimBegin, float trimEnd); + void updateStrokesList(WgContext& context, Array polylines, const RenderStroke* rstroke, float scale, float totalLen, float trimBegin, float trimEnd); + void updateStrokes(WgContext& context, const WgPolyline* polyline, const RenderStroke* rstroke, float scale, float trimBegin, float trimEnd); void releaseMeshes(WgContext& context); void release(WgContext& context) override; Type type() override { return Type::Shape; };