mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 21:53:41 +00:00
gl_engine: enhance the tessellation algorithm
* merge vertices that are close enough before tessellation * append return branch in tessellation to prevent dead loop caused by floating point precision
This commit is contained in:
parent
a3e2189afa
commit
3f9b0eff22
3 changed files with 30 additions and 12 deletions
|
@ -42,7 +42,10 @@ bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag)
|
||||||
fillIndex.clear();
|
fillIndex.clear();
|
||||||
|
|
||||||
Tessellator tess{&fillVertex, &fillIndex};
|
Tessellator tess{&fillVertex, &fillIndex};
|
||||||
tess.tessellate(&rshape, true);
|
if (!tess.tessellate(&rshape, true)) {
|
||||||
|
fillVertex.clear();
|
||||||
|
fillIndex.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
||||||
|
|
|
@ -662,8 +662,10 @@ static bool _validEdgePair(Edge* left, Edge* right) {
|
||||||
bool ActiveEdgeList::valid()
|
bool ActiveEdgeList::valid()
|
||||||
{
|
{
|
||||||
auto left = head;
|
auto left = head;
|
||||||
if (!left) {
|
if (!left && !tail) {
|
||||||
return true;
|
return true;
|
||||||
|
} else if (!left || !tail) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto right = left->right; right; right = right->right) {
|
for(auto right = left->right; right; right = right->right) {
|
||||||
|
@ -898,7 +900,7 @@ Tessellator::~Tessellator()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Tessellator::tessellate(const RenderShape *rshape, bool antialias)
|
bool Tessellator::tessellate(const RenderShape *rshape, bool antialias)
|
||||||
{
|
{
|
||||||
auto cmds = rshape->path.cmds.data;
|
auto cmds = rshape->path.cmds.data;
|
||||||
auto cmdCnt = rshape->path.cmds.count;
|
auto cmdCnt = rshape->path.cmds.count;
|
||||||
|
@ -913,9 +915,9 @@ void Tessellator::tessellate(const RenderShape *rshape, bool antialias)
|
||||||
|
|
||||||
this->mergeVertices();
|
this->mergeVertices();
|
||||||
|
|
||||||
this->simplifyMesh();
|
if (!this->simplifyMesh()) return false;
|
||||||
|
|
||||||
this->tessMesh();
|
if (!this->tessMesh()) return false;
|
||||||
|
|
||||||
// output triangles
|
// output triangles
|
||||||
for (auto poly = this->pPolygon; poly; poly = poly->next) {
|
for (auto poly = this->pPolygon; poly; poly = poly->next) {
|
||||||
|
@ -935,6 +937,8 @@ void Tessellator::tessellate(const RenderShape *rshape, bool antialias)
|
||||||
if (antialias) {
|
if (antialias) {
|
||||||
// TODO extract outline from current polygon list and generate aa edges
|
// TODO extract outline from current polygon list and generate aa edges
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tessellator::tessellate(const Array<const RenderShape *> &shapes)
|
void Tessellator::tessellate(const Array<const RenderShape *> &shapes)
|
||||||
|
@ -1085,7 +1089,7 @@ void Tessellator::mergeVertices()
|
||||||
for (auto v = pMesh->head->next; v;) {
|
for (auto v = pMesh->head->next; v;) {
|
||||||
auto next = v->next;
|
auto next = v->next;
|
||||||
|
|
||||||
if (detail::VertexCompare::compare(v->point, v->prev->point)) {
|
if (detail::VertexCompare::compare(v->point, v->prev->point) || detail::_pointLength(v->point - v->prev->point) <= 0.025f) {
|
||||||
// already sorted, this means these two points is same
|
// already sorted, this means these two points is same
|
||||||
v->point = v->prev->point;
|
v->point = v->prev->point;
|
||||||
}
|
}
|
||||||
|
@ -1107,7 +1111,7 @@ void Tessellator::mergeVertices()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tessellator::simplifyMesh()
|
bool Tessellator::simplifyMesh()
|
||||||
{
|
{
|
||||||
/// this is a basic sweep line algorithm
|
/// this is a basic sweep line algorithm
|
||||||
/// https://www.youtube.com/watch?v=qkhUNzCGDt0&t=293s
|
/// https://www.youtube.com/watch?v=qkhUNzCGDt0&t=293s
|
||||||
|
@ -1134,6 +1138,11 @@ void Tessellator::simplifyMesh()
|
||||||
v->left = left_enclosing;
|
v->left = left_enclosing;
|
||||||
v->right = right_enclosing;
|
v->right = right_enclosing;
|
||||||
|
|
||||||
|
if (!ael.valid()) {
|
||||||
|
// If AEL is not valid, means we meet the problem caused by floating point precision
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (v->edge_below.head) {
|
if (v->edge_below.head) {
|
||||||
for (auto e = v->edge_below.head; e; e = e->below_next) {
|
for (auto e = v->edge_below.head; e; e = e->below_next) {
|
||||||
// check current edge is intersected by left or right neighbor edges
|
// check current edge is intersected by left or right neighbor edges
|
||||||
|
@ -1154,7 +1163,7 @@ void Tessellator::simplifyMesh()
|
||||||
|
|
||||||
if (!ael.valid()) {
|
if (!ael.valid()) {
|
||||||
// If AEL is not valid, means we meet the problem caused by floating point precision
|
// If AEL is not valid, means we meet the problem caused by floating point precision
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are done for all edge end with current point
|
// we are done for all edge end with current point
|
||||||
|
@ -1170,9 +1179,11 @@ void Tessellator::simplifyMesh()
|
||||||
left = e;
|
left = e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tessellator::tessMesh()
|
bool Tessellator::tessMesh()
|
||||||
{
|
{
|
||||||
/// this function also use sweep line algorithm
|
/// this function also use sweep line algorithm
|
||||||
/// but during the process, we calculate the winding number of left and right
|
/// but during the process, we calculate the winding number of left and right
|
||||||
|
@ -1185,6 +1196,8 @@ void Tessellator::tessMesh()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ael.valid()) return false;
|
||||||
|
|
||||||
detail::Edge *left_enclosing = nullptr;
|
detail::Edge *left_enclosing = nullptr;
|
||||||
detail::Edge *right_enclosing = nullptr;
|
detail::Edge *right_enclosing = nullptr;
|
||||||
|
|
||||||
|
@ -1315,6 +1328,8 @@ void Tessellator::tessMesh()
|
||||||
v->edge_below.tail->right_poly = right_poly;
|
v->edge_below.tail->right_poly = right_poly;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Tessellator::matchFillRule(int32_t winding)
|
bool Tessellator::matchFillRule(int32_t winding)
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
Tessellator(Array<float>* points, Array<uint32_t>* indices);
|
Tessellator(Array<float>* points, Array<uint32_t>* indices);
|
||||||
~Tessellator();
|
~Tessellator();
|
||||||
|
|
||||||
void tessellate(const RenderShape *rshape, bool antialias = false);
|
bool tessellate(const RenderShape *rshape, bool antialias = false);
|
||||||
|
|
||||||
void tessellate(const Array<const RenderShape*> &shapes);
|
void tessellate(const Array<const RenderShape*> &shapes);
|
||||||
|
|
||||||
|
@ -65,9 +65,9 @@ private:
|
||||||
|
|
||||||
void mergeVertices();
|
void mergeVertices();
|
||||||
|
|
||||||
void simplifyMesh();
|
bool simplifyMesh();
|
||||||
|
|
||||||
void tessMesh();
|
bool tessMesh();
|
||||||
|
|
||||||
bool matchFillRule(int32_t winding);
|
bool matchFillRule(int32_t winding);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue