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
|
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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue