123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- /*
- ** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
- ** Copyright (C) 2011 Silicon Graphics, Inc.
- ** All Rights Reserved.
- **
- ** Permission is hereby granted, free of charge, to any person obtaining a copy
- ** of this software and associated documentation files (the "Software"), to deal
- ** in the Software without restriction, including without limitation the rights
- ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- ** of the Software, and to permit persons to whom the Software is furnished to do so,
- ** subject to the following conditions:
- **
- ** The above copyright notice including the dates of first publication and either this
- ** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
- ** included in all copies or substantial portions of the Software.
- **
- ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- ** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- ** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
- ** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
- ** OR OTHER DEALINGS IN THE SOFTWARE.
- **
- ** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
- ** be used in advertising or otherwise to promote the sale, use or other dealings in
- ** this Software without prior written authorization from Silicon Graphics, Inc.
- */
- /*
- ** Original Author: Eric Veach, July 1994.
- ** libtess2: Mikko Mononen, http://code.google.com/p/libtess2/.
- ** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet
- */
- using System;
- using System.Diagnostics;
- namespace UnityEngine.Experimental.Rendering.Universal
- {
- namespace LibTessDotNet
- {
- internal class Mesh : MeshUtils.Pooled<Mesh>
- {
- internal MeshUtils.Vertex _vHead;
- internal MeshUtils.Face _fHead;
- internal MeshUtils.Edge _eHead, _eHeadSym;
- public Mesh()
- {
- var v = _vHead = MeshUtils.Vertex.Create();
- var f = _fHead = MeshUtils.Face.Create();
- var pair = MeshUtils.EdgePair.Create();
- var e = _eHead = pair._e;
- var eSym = _eHeadSym = pair._eSym;
- v._next = v._prev = v;
- v._anEdge = null;
- f._next = f._prev = f;
- f._anEdge = null;
- f._trail = null;
- f._marked = false;
- f._inside = false;
- e._next = e;
- e._Sym = eSym;
- e._Onext = null;
- e._Lnext = null;
- e._Org = null;
- e._Lface = null;
- e._winding = 0;
- e._activeRegion = null;
- eSym._next = eSym;
- eSym._Sym = e;
- eSym._Onext = null;
- eSym._Lnext = null;
- eSym._Org = null;
- eSym._Lface = null;
- eSym._winding = 0;
- eSym._activeRegion = null;
- }
- public override void Reset()
- {
- _vHead = null;
- _fHead = null;
- _eHead = _eHeadSym = null;
- }
- public override void OnFree()
- {
- for (MeshUtils.Face f = _fHead._next, fNext = _fHead; f != _fHead; f = fNext)
- {
- fNext = f._next;
- f.Free();
- }
- for (MeshUtils.Vertex v = _vHead._next, vNext = _vHead; v != _vHead; v = vNext)
- {
- vNext = v._next;
- v.Free();
- }
- for (MeshUtils.Edge e = _eHead._next, eNext = _eHead; e != _eHead; e = eNext)
- {
- eNext = e._next;
- e.Free();
- }
- }
- /// <summary>
- /// Creates one edge, two vertices and a loop (face).
- /// The loop consists of the two new half-edges.
- /// </summary>
- public MeshUtils.Edge MakeEdge()
- {
- var e = MeshUtils.MakeEdge(_eHead);
- MeshUtils.MakeVertex(e, _vHead);
- MeshUtils.MakeVertex(e._Sym, _vHead);
- MeshUtils.MakeFace(e, _fHead);
- return e;
- }
- /// <summary>
- /// Splice is the basic operation for changing the
- /// mesh connectivity and topology. It changes the mesh so that
- /// eOrg->Onext = OLD( eDst->Onext )
- /// eDst->Onext = OLD( eOrg->Onext )
- /// where OLD(...) means the value before the meshSplice operation.
- ///
- /// This can have two effects on the vertex structure:
- /// - if eOrg->Org != eDst->Org, the two vertices are merged together
- /// - if eOrg->Org == eDst->Org, the origin is split into two vertices
- /// In both cases, eDst->Org is changed and eOrg->Org is untouched.
- ///
- /// Similarly (and independently) for the face structure,
- /// - if eOrg->Lface == eDst->Lface, one loop is split into two
- /// - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
- /// In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
- ///
- /// Some special cases:
- /// If eDst == eOrg, the operation has no effect.
- /// If eDst == eOrg->Lnext, the new face will have a single edge.
- /// If eDst == eOrg->Lprev, the old face will have a single edge.
- /// If eDst == eOrg->Onext, the new vertex will have a single edge.
- /// If eDst == eOrg->Oprev, the old vertex will have a single edge.
- /// </summary>
- public void Splice(MeshUtils.Edge eOrg, MeshUtils.Edge eDst)
- {
- if (eOrg == eDst)
- {
- return;
- }
- bool joiningVertices = false;
- if (eDst._Org != eOrg._Org)
- {
- // We are merging two disjoint vertices -- destroy eDst->Org
- joiningVertices = true;
- MeshUtils.KillVertex(eDst._Org, eOrg._Org);
- }
- bool joiningLoops = false;
- if (eDst._Lface != eOrg._Lface)
- {
- // We are connecting two disjoint loops -- destroy eDst->Lface
- joiningLoops = true;
- MeshUtils.KillFace(eDst._Lface, eOrg._Lface);
- }
- // Change the edge structure
- MeshUtils.Splice(eDst, eOrg);
- if (!joiningVertices)
- {
- // We split one vertex into two -- the new vertex is eDst->Org.
- // Make sure the old vertex points to a valid half-edge.
- MeshUtils.MakeVertex(eDst, eOrg._Org);
- eOrg._Org._anEdge = eOrg;
- }
- if (!joiningLoops)
- {
- // We split one loop into two -- the new loop is eDst->Lface.
- // Make sure the old face points to a valid half-edge.
- MeshUtils.MakeFace(eDst, eOrg._Lface);
- eOrg._Lface._anEdge = eOrg;
- }
- }
- /// <summary>
- /// Removes the edge eDel. There are several cases:
- /// if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
- /// eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
- /// the newly created loop will contain eDel->Dst. If the deletion of eDel
- /// would create isolated vertices, those are deleted as well.
- /// </summary>
- public void Delete(MeshUtils.Edge eDel)
- {
- var eDelSym = eDel._Sym;
- // First step: disconnect the origin vertex eDel->Org. We make all
- // changes to get a consistent mesh in this "intermediate" state.
- bool joiningLoops = false;
- if (eDel._Lface != eDel._Rface)
- {
- // We are joining two loops into one -- remove the left face
- joiningLoops = true;
- MeshUtils.KillFace(eDel._Lface, eDel._Rface);
- }
- if (eDel._Onext == eDel)
- {
- MeshUtils.KillVertex(eDel._Org, null);
- }
- else
- {
- // Make sure that eDel->Org and eDel->Rface point to valid half-edges
- eDel._Rface._anEdge = eDel._Oprev;
- eDel._Org._anEdge = eDel._Onext;
- MeshUtils.Splice(eDel, eDel._Oprev);
- if (!joiningLoops)
- {
- // We are splitting one loop into two -- create a new loop for eDel.
- MeshUtils.MakeFace(eDel, eDel._Lface);
- }
- }
- // Claim: the mesh is now in a consistent state, except that eDel->Org
- // may have been deleted. Now we disconnect eDel->Dst.
- if (eDelSym._Onext == eDelSym)
- {
- MeshUtils.KillVertex(eDelSym._Org, null);
- MeshUtils.KillFace(eDelSym._Lface, null);
- }
- else
- {
- // Make sure that eDel->Dst and eDel->Lface point to valid half-edges
- eDel._Lface._anEdge = eDelSym._Oprev;
- eDelSym._Org._anEdge = eDelSym._Onext;
- MeshUtils.Splice(eDelSym, eDelSym._Oprev);
- }
- // Any isolated vertices or faces have already been freed.
- MeshUtils.KillEdge(eDel);
- }
- /// <summary>
- /// Creates a new edge such that eNew == eOrg.Lnext and eNew.Dst is a newly created vertex.
- /// eOrg and eNew will have the same left face.
- /// </summary>
- public MeshUtils.Edge AddEdgeVertex(MeshUtils.Edge eOrg)
- {
- var eNew = MeshUtils.MakeEdge(eOrg);
- var eNewSym = eNew._Sym;
- // Connect the new edge appropriately
- MeshUtils.Splice(eNew, eOrg._Lnext);
- // Set vertex and face information
- eNew._Org = eOrg._Dst;
- MeshUtils.MakeVertex(eNewSym, eNew._Org);
- eNew._Lface = eNewSym._Lface = eOrg._Lface;
- return eNew;
- }
- /// <summary>
- /// Splits eOrg into two edges eOrg and eNew such that eNew == eOrg.Lnext.
- /// The new vertex is eOrg.Dst == eNew.Org.
- /// eOrg and eNew will have the same left face.
- /// </summary>
- public MeshUtils.Edge SplitEdge(MeshUtils.Edge eOrg)
- {
- var eTmp = AddEdgeVertex(eOrg);
- var eNew = eTmp._Sym;
- // Disconnect eOrg from eOrg->Dst and connect it to eNew->Org
- MeshUtils.Splice(eOrg._Sym, eOrg._Sym._Oprev);
- MeshUtils.Splice(eOrg._Sym, eNew);
- // Set the vertex and face information
- eOrg._Dst = eNew._Org;
- eNew._Dst._anEdge = eNew._Sym; // may have pointed to eOrg->Sym
- eNew._Rface = eOrg._Rface;
- eNew._winding = eOrg._winding; // copy old winding information
- eNew._Sym._winding = eOrg._Sym._winding;
- return eNew;
- }
- /// <summary>
- /// Creates a new edge from eOrg->Dst to eDst->Org, and returns the corresponding half-edge eNew.
- /// If eOrg->Lface == eDst->Lface, this splits one loop into two,
- /// and the newly created loop is eNew->Lface. Otherwise, two disjoint
- /// loops are merged into one, and the loop eDst->Lface is destroyed.
- ///
- /// If (eOrg == eDst), the new face will have only two edges.
- /// If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
- /// If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
- /// </summary>
- public MeshUtils.Edge Connect(MeshUtils.Edge eOrg, MeshUtils.Edge eDst)
- {
- var eNew = MeshUtils.MakeEdge(eOrg);
- var eNewSym = eNew._Sym;
- bool joiningLoops = false;
- if (eDst._Lface != eOrg._Lface)
- {
- // We are connecting two disjoint loops -- destroy eDst->Lface
- joiningLoops = true;
- MeshUtils.KillFace(eDst._Lface, eOrg._Lface);
- }
- // Connect the new edge appropriately
- MeshUtils.Splice(eNew, eOrg._Lnext);
- MeshUtils.Splice(eNewSym, eDst);
- // Set the vertex and face information
- eNew._Org = eOrg._Dst;
- eNewSym._Org = eDst._Org;
- eNew._Lface = eNewSym._Lface = eOrg._Lface;
- // Make sure the old face points to a valid half-edge
- eOrg._Lface._anEdge = eNewSym;
- if (!joiningLoops)
- {
- MeshUtils.MakeFace(eNew, eOrg._Lface);
- }
- return eNew;
- }
- /// <summary>
- /// Destroys a face and removes it from the global face list. All edges of
- /// fZap will have a NULL pointer as their left face. Any edges which
- /// also have a NULL pointer as their right face are deleted entirely
- /// (along with any isolated vertices this produces).
- /// An entire mesh can be deleted by zapping its faces, one at a time,
- /// in any order. Zapped faces cannot be used in further mesh operations!
- /// </summary>
- public void ZapFace(MeshUtils.Face fZap)
- {
- var eStart = fZap._anEdge;
- // walk around face, deleting edges whose right face is also NULL
- var eNext = eStart._Lnext;
- MeshUtils.Edge e, eSym;
- do {
- e = eNext;
- eNext = e._Lnext;
- e._Lface = null;
- if (e._Rface == null)
- {
- // delete the edge -- see TESSmeshDelete above
- if (e._Onext == e)
- {
- MeshUtils.KillVertex(e._Org, null);
- }
- else
- {
- // Make sure that e._Org points to a valid half-edge
- e._Org._anEdge = e._Onext;
- MeshUtils.Splice(e, e._Oprev);
- }
- eSym = e._Sym;
- if (eSym._Onext == eSym)
- {
- MeshUtils.KillVertex(eSym._Org, null);
- }
- else
- {
- // Make sure that eSym._Org points to a valid half-edge
- eSym._Org._anEdge = eSym._Onext;
- MeshUtils.Splice(eSym, eSym._Oprev);
- }
- MeshUtils.KillEdge(e);
- }
- } while (e != eStart);
- /* delete from circular doubly-linked list */
- var fPrev = fZap._prev;
- var fNext = fZap._next;
- fNext._prev = fPrev;
- fPrev._next = fNext;
- fZap.Free();
- }
- public void MergeConvexFaces(int maxVertsPerFace)
- {
- for (var f = _fHead._next; f != _fHead; f = f._next)
- {
- // Skip faces which are outside the result
- if (!f._inside)
- {
- continue;
- }
- var eCur = f._anEdge;
- var vStart = eCur._Org;
- while (true)
- {
- var eNext = eCur._Lnext;
- var eSym = eCur._Sym;
- if (eSym != null && eSym._Lface != null && eSym._Lface._inside)
- {
- // Try to merge the neighbour faces if the resulting polygons
- // does not exceed maximum number of vertices.
- int curNv = f.VertsCount;
- int symNv = eSym._Lface.VertsCount;
- if ((curNv + symNv - 2) <= maxVertsPerFace)
- {
- // Merge if the resulting poly is convex.
- if (Geom.VertCCW(eCur._Lprev._Org, eCur._Org, eSym._Lnext._Lnext._Org) &&
- Geom.VertCCW(eSym._Lprev._Org, eSym._Org, eCur._Lnext._Lnext._Org))
- {
- eNext = eSym._Lnext;
- Delete(eSym);
- eCur = null;
- }
- }
- }
- if (eCur != null && eCur._Lnext._Org == vStart)
- break;
- // Continue to next edge.
- eCur = eNext;
- }
- }
- }
- [Conditional("DEBUG")]
- public void Check()
- {
- MeshUtils.Edge e;
- MeshUtils.Face fPrev = _fHead, f;
- for (fPrev = _fHead; (f = fPrev._next) != _fHead; fPrev = f)
- {
- e = f._anEdge;
- do {
- Debug.Assert(e._Sym != e);
- Debug.Assert(e._Sym._Sym == e);
- Debug.Assert(e._Lnext._Onext._Sym == e);
- Debug.Assert(e._Onext._Sym._Lnext == e);
- Debug.Assert(e._Lface == f);
- e = e._Lnext;
- } while (e != f._anEdge);
- }
- Debug.Assert(f._prev == fPrev && f._anEdge == null);
- MeshUtils.Vertex vPrev = _vHead, v;
- for (vPrev = _vHead; (v = vPrev._next) != _vHead; vPrev = v)
- {
- Debug.Assert(v._prev == vPrev);
- e = v._anEdge;
- do
- {
- Debug.Assert(e._Sym != e);
- Debug.Assert(e._Sym._Sym == e);
- Debug.Assert(e._Lnext._Onext._Sym == e);
- Debug.Assert(e._Onext._Sym._Lnext == e);
- Debug.Assert(e._Org == v);
- e = e._Onext;
- } while (e != v._anEdge);
- }
- Debug.Assert(v._prev == vPrev && v._anEdge == null);
- MeshUtils.Edge ePrev = _eHead;
- for (ePrev = _eHead; (e = ePrev._next) != _eHead; ePrev = e)
- {
- Debug.Assert(e._Sym._next == ePrev._Sym);
- Debug.Assert(e._Sym != e);
- Debug.Assert(e._Sym._Sym == e);
- Debug.Assert(e._Org != null);
- Debug.Assert(e._Dst != null);
- Debug.Assert(e._Lnext._Onext._Sym == e);
- Debug.Assert(e._Onext._Sym._Lnext == e);
- }
- Debug.Assert(e._Sym._next == ePrev._Sym
- && e._Sym == _eHeadSym
- && e._Sym._Sym == e
- && e._Org == null && e._Dst == null
- && e._Lface == null && e._Rface == null);
- }
- }
- }
- }
|