Initial commit

This commit is contained in:
AbstractConcept 2022-09-13 00:36:34 -05:00
commit 3c7cc0c973
8391 changed files with 704313 additions and 0 deletions

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9214d94ab547c5447a11c7a7c6a59482
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,107 @@
/*
** 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
*/
namespace Unity.SpriteShape.External
{
namespace LibTessDotNet
{
internal class Dict<TValue> where TValue : class
{
public class Node
{
internal TValue _key;
internal Node _prev, _next;
public TValue Key { get { return _key; } }
public Node Prev { get { return _prev; } }
public Node Next { get { return _next; } }
}
public delegate bool LessOrEqual(TValue lhs, TValue rhs);
private LessOrEqual _leq;
Node _head;
public Dict(LessOrEqual leq)
{
_leq = leq;
_head = new Node { _key = null };
_head._prev = _head;
_head._next = _head;
}
public Node Insert(TValue key)
{
return InsertBefore(_head, key);
}
public Node InsertBefore(Node node, TValue key)
{
do {
node = node._prev;
} while (node._key != null && !_leq(node._key, key));
var newNode = new Node { _key = key };
newNode._next = node._next;
node._next._prev = newNode;
newNode._prev = node;
node._next = newNode;
return newNode;
}
public Node Find(TValue key)
{
var node = _head;
do {
node = node._next;
} while (node._key != null && !_leq(key, node._key));
return node;
}
public Node Min()
{
return _head._next;
}
public void Remove(Node node)
{
node._next._prev = node._prev;
node._prev._next = node._next;
}
}
}
} // namespace Unity.VectorGraphics.External

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d1f51a5b71c3ce943b689d3664e4d5fd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,301 @@
/*
** 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 Unity.SpriteShape.External
{
using Real = System.Single;
namespace LibTessDotNet
{
internal static class Geom
{
public static bool IsWindingInside(WindingRule rule, int n)
{
switch (rule)
{
case WindingRule.EvenOdd:
return (n & 1) == 1;
case WindingRule.NonZero:
return n != 0;
case WindingRule.Positive:
return n > 0;
case WindingRule.Negative:
return n < 0;
case WindingRule.AbsGeqTwo:
return n >= 2 || n <= -2;
}
throw new Exception("Wrong winding rule");
}
public static bool VertCCW(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
return (u._s * (v._t - w._t) + v._s * (w._t - u._t) + w._s * (u._t - v._t)) >= 0.0f;
}
public static bool VertEq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs)
{
return lhs._s == rhs._s && lhs._t == rhs._t;
}
public static bool VertLeq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs)
{
return (lhs._s < rhs._s) || (lhs._s == rhs._s && lhs._t <= rhs._t);
}
/// <summary>
/// Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
/// evaluates the t-coord of the edge uw at the s-coord of the vertex v.
/// Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
/// If uw is vertical (and thus passes thru v), the result is zero.
///
/// The calculation is extremely accurate and stable, even when v
/// is very close to u or w. In particular if we set v->t = 0 and
/// let r be the negated result (this evaluates (uw)(v->s)), then
/// r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
/// </summary>
public static Real EdgeEval(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
Debug.Assert(VertLeq(u, v) && VertLeq(v, w));
var gapL = v._s - u._s;
var gapR = w._s - v._s;
if (gapL + gapR > 0.0f)
{
if (gapL < gapR)
{
return (v._t - u._t) + (u._t - w._t) * (gapL / (gapL + gapR));
}
else
{
return (v._t - w._t) + (w._t - u._t) * (gapR / (gapL + gapR));
}
}
/* vertical line */
return 0;
}
/// <summary>
/// Returns a number whose sign matches EdgeEval(u,v,w) but which
/// is cheaper to evaluate. Returns > 0, == 0 , or < 0
/// as v is above, on, or below the edge uw.
/// </summary>
public static Real EdgeSign(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
Debug.Assert(VertLeq(u, v) && VertLeq(v, w));
var gapL = v._s - u._s;
var gapR = w._s - v._s;
if (gapL + gapR > 0.0f)
{
return (v._t - w._t) * gapL + (v._t - u._t) * gapR;
}
/* vertical line */
return 0;
}
public static bool TransLeq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs)
{
return (lhs._t < rhs._t) || (lhs._t == rhs._t && lhs._s <= rhs._s);
}
public static Real TransEval(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
Debug.Assert(TransLeq(u, v) && TransLeq(v, w));
var gapL = v._t - u._t;
var gapR = w._t - v._t;
if (gapL + gapR > 0.0f)
{
if (gapL < gapR)
{
return (v._s - u._s) + (u._s - w._s) * (gapL / (gapL + gapR));
}
else
{
return (v._s - w._s) + (w._s - u._s) * (gapR / (gapL + gapR));
}
}
/* vertical line */
return 0;
}
public static Real TransSign(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
Debug.Assert(TransLeq(u, v) && TransLeq(v, w));
var gapL = v._t - u._t;
var gapR = w._t - v._t;
if (gapL + gapR > 0.0f)
{
return (v._s - w._s) * gapL + (v._s - u._s) * gapR;
}
/* vertical line */
return 0;
}
public static bool EdgeGoesLeft(MeshUtils.Edge e)
{
return VertLeq(e._Dst, e._Org);
}
public static bool EdgeGoesRight(MeshUtils.Edge e)
{
return VertLeq(e._Org, e._Dst);
}
public static Real VertL1dist(MeshUtils.Vertex u, MeshUtils.Vertex v)
{
return Math.Abs(u._s - v._s) + Math.Abs(u._t - v._t);
}
public static void AddWinding(MeshUtils.Edge eDst, MeshUtils.Edge eSrc)
{
eDst._winding += eSrc._winding;
eDst._Sym._winding += eSrc._Sym._winding;
}
public static Real Interpolate(Real a, Real x, Real b, Real y)
{
if (a < 0.0f)
{
a = 0.0f;
}
if (b < 0.0f)
{
b = 0.0f;
}
return ((a <= b) ? ((b == 0.0f) ? ((x+y) / 2.0f)
: (x + (y-x) * (a/(a+b))))
: (y + (x-y) * (b/(a+b))));
}
static void Swap(ref MeshUtils.Vertex a, ref MeshUtils.Vertex b)
{
var tmp = a;
a = b;
b = tmp;
}
/// <summary>
/// Given edges (o1,d1) and (o2,d2), compute their point of intersection.
/// The computed point is guaranteed to lie in the intersection of the
/// bounding rectangles defined by each edge.
/// </summary>
public static void EdgeIntersect(MeshUtils.Vertex o1, MeshUtils.Vertex d1, MeshUtils.Vertex o2, MeshUtils.Vertex d2, MeshUtils.Vertex v)
{
// This is certainly not the most efficient way to find the intersection
// of two line segments, but it is very numerically stable.
//
// Strategy: find the two middle vertices in the VertLeq ordering,
// and interpolate the intersection s-value from these. Then repeat
// using the TransLeq ordering to find the intersection t-value.
if (!VertLeq(o1, d1)) { Swap(ref o1, ref d1); }
if (!VertLeq(o2, d2)) { Swap(ref o2, ref d2); }
if (!VertLeq(o1, o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); }
if (!VertLeq(o2, d1))
{
// Technically, no intersection -- do our best
v._s = (o2._s + d1._s) / 2.0f;
}
else if (VertLeq(d1, d2))
{
// Interpolate between o2 and d1
var z1 = EdgeEval(o1, o2, d1);
var z2 = EdgeEval(o2, d1, d2);
if (z1 + z2 < 0.0f)
{
z1 = -z1;
z2 = -z2;
}
v._s = Interpolate(z1, o2._s, z2, d1._s);
}
else
{
// Interpolate between o2 and d2
var z1 = EdgeSign(o1, o2, d1);
var z2 = -EdgeSign(o1, d2, d1);
if (z1 + z2 < 0.0f)
{
z1 = -z1;
z2 = -z2;
}
v._s = Interpolate(z1, o2._s, z2, d2._s);
}
// Now repeat the process for t
if (!TransLeq(o1, d1)) { Swap(ref o1, ref d1); }
if (!TransLeq(o2, d2)) { Swap(ref o2, ref d2); }
if (!TransLeq(o1, o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); }
if (!TransLeq(o2, d1))
{
// Technically, no intersection -- do our best
v._t = (o2._t + d1._t) / 2.0f;
}
else if (TransLeq(d1, d2))
{
// Interpolate between o2 and d1
var z1 = TransEval(o1, o2, d1);
var z2 = TransEval(o2, d1, d2);
if (z1 + z2 < 0.0f)
{
z1 = -z1;
z2 = -z2;
}
v._t = Interpolate(z1, o2._t, z2, d1._t);
}
else
{
// Interpolate between o2 and d2
var z1 = TransSign(o1, o2, d1);
var z2 = -TransSign(o1, d2, d1);
if (z1 + z2 < 0.0f)
{
z1 = -z1;
z2 = -z2;
}
v._t = Interpolate(z1, o2._t, z2, d2._t);
}
}
}
}
} // namespace Unity.VectorGraphics.External

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8eb4e2609b653584b88dc0ee64a2ba24
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,25 @@
** 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.

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b5ea83a04894a434f9b5e5b5d91c75e5
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,500 @@
/*
** 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 Unity.SpriteShape.External
{
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);
}
}
}
} // namespace Unity.VectorGraphics.External

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d834cd56fabc3447b5e84a6ad97d96a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,465 @@
/*
** 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.Collections.Generic;
using System.Diagnostics;
namespace Unity.SpriteShape.External
{
using Real = System.Single;
namespace LibTessDotNet
{
internal struct Vec3
{
public readonly static Vec3 Zero = new Vec3();
public Real X, Y, Z;
public Real this[int index]
{
get
{
if (index == 0) return X;
if (index == 1) return Y;
if (index == 2) return Z;
throw new IndexOutOfRangeException();
}
set
{
if (index == 0) X = value;
else if (index == 1) Y = value;
else if (index == 2) Z = value;
else throw new IndexOutOfRangeException();
}
}
public static void Sub(ref Vec3 lhs, ref Vec3 rhs, out Vec3 result)
{
result.X = lhs.X - rhs.X;
result.Y = lhs.Y - rhs.Y;
result.Z = lhs.Z - rhs.Z;
}
public static void Neg(ref Vec3 v)
{
v.X = -v.X;
v.Y = -v.Y;
v.Z = -v.Z;
}
public static void Dot(ref Vec3 u, ref Vec3 v, out Real dot)
{
dot = u.X * v.X + u.Y * v.Y + u.Z * v.Z;
}
public static void Normalize(ref Vec3 v)
{
var len = v.X * v.X + v.Y * v.Y + v.Z * v.Z;
Debug.Assert(len >= 0.0f);
len = 1.0f / (Real)Math.Sqrt(len);
v.X *= len;
v.Y *= len;
v.Z *= len;
}
public static int LongAxis(ref Vec3 v)
{
int i = 0;
if (Math.Abs(v.Y) > Math.Abs(v.X)) i = 1;
if (Math.Abs(v.Z) > Math.Abs(i == 0 ? v.X : v.Y)) i = 2;
return i;
}
public override string ToString()
{
return string.Format("{0}, {1}, {2}", X, Y, Z);
}
}
internal static class MeshUtils
{
public const int Undef = ~0;
public abstract class Pooled<T> where T : Pooled<T>, new()
{
private static Stack<T> _stack;
public abstract void Reset();
public virtual void OnFree() { }
public static T Create()
{
if (_stack != null && _stack.Count > 0)
{
return _stack.Pop();
}
return new T();
}
public void Free()
{
OnFree();
Reset();
if (_stack == null)
{
_stack = new Stack<T>();
}
_stack.Push((T)this);
}
}
public class Vertex : Pooled<Vertex>
{
internal Vertex _prev, _next;
internal Edge _anEdge;
internal Vec3 _coords;
internal Real _s, _t;
internal PQHandle _pqHandle;
internal int _n;
internal object _data;
public override void Reset()
{
_prev = _next = null;
_anEdge = null;
_coords = Vec3.Zero;
_s = 0;
_t = 0;
_pqHandle = new PQHandle();
_n = 0;
_data = null;
}
}
public class Face : Pooled<Face>
{
internal Face _prev, _next;
internal Edge _anEdge;
internal Face _trail;
internal int _n;
internal bool _marked, _inside;
internal int VertsCount
{
get
{
int n = 0;
var eCur = _anEdge;
do {
n++;
eCur = eCur._Lnext;
} while (eCur != _anEdge);
return n;
}
}
public override void Reset()
{
_prev = _next = null;
_anEdge = null;
_trail = null;
_n = 0;
_marked = false;
_inside = false;
}
}
public struct EdgePair
{
internal Edge _e, _eSym;
public static EdgePair Create()
{
var pair = new MeshUtils.EdgePair();
pair._e = MeshUtils.Edge.Create();
pair._e._pair = pair;
pair._eSym = MeshUtils.Edge.Create();
pair._eSym._pair = pair;
return pair;
}
public void Reset()
{
_e = _eSym = null;
}
}
public class Edge : Pooled<Edge>
{
internal EdgePair _pair;
internal Edge _next, _Sym, _Onext, _Lnext;
internal Vertex _Org;
internal Face _Lface;
internal Tess.ActiveRegion _activeRegion;
internal int _winding;
internal Face _Rface { get { return _Sym._Lface; } set { _Sym._Lface = value; } }
internal Vertex _Dst { get { return _Sym._Org; } set { _Sym._Org = value; } }
internal Edge _Oprev { get { return _Sym._Lnext; } set { _Sym._Lnext = value; } }
internal Edge _Lprev { get { return _Onext._Sym; } set { _Onext._Sym = value; } }
internal Edge _Dprev { get { return _Lnext._Sym; } set { _Lnext._Sym = value; } }
internal Edge _Rprev { get { return _Sym._Onext; } set { _Sym._Onext = value; } }
internal Edge _Dnext { get { return _Rprev._Sym; } set { _Rprev._Sym = value; } }
internal Edge _Rnext { get { return _Oprev._Sym; } set { _Oprev._Sym = value; } }
internal static void EnsureFirst(ref Edge e)
{
if (e == e._pair._eSym)
{
e = e._Sym;
}
}
public override void Reset()
{
_pair.Reset();
_next = _Sym = _Onext = _Lnext = null;
_Org = null;
_Lface = null;
_activeRegion = null;
_winding = 0;
}
}
/// <summary>
/// MakeEdge creates a new pair of half-edges which form their own loop.
/// No vertex or face structures are allocated, but these must be assigned
/// before the current edge operation is completed.
/// </summary>
public static Edge MakeEdge(Edge eNext)
{
Debug.Assert(eNext != null);
var pair = EdgePair.Create();
var e = pair._e;
var eSym = pair._eSym;
// Make sure eNext points to the first edge of the edge pair
Edge.EnsureFirst(ref eNext);
// Insert in circular doubly-linked list before eNext.
// Note that the prev pointer is stored in Sym->next.
var ePrev = eNext._Sym._next;
eSym._next = ePrev;
ePrev._Sym._next = e;
e._next = eNext;
eNext._Sym._next = eSym;
e._Sym = eSym;
e._Onext = e;
e._Lnext = eSym;
e._Org = null;
e._Lface = null;
e._winding = 0;
e._activeRegion = null;
eSym._Sym = e;
eSym._Onext = eSym;
eSym._Lnext = e;
eSym._Org = null;
eSym._Lface = null;
eSym._winding = 0;
eSym._activeRegion = null;
return e;
}
/// <summary>
/// Splice( a, b ) is best described by the Guibas/Stolfi paper or the
/// CS348a notes (see Mesh.cs). Basically it modifies the mesh so that
/// a->Onext and b->Onext are exchanged. This can have various effects
/// depending on whether a and b belong to different face or vertex rings.
/// For more explanation see Mesh.Splice().
/// </summary>
public static void Splice(Edge a, Edge b)
{
var aOnext = a._Onext;
var bOnext = b._Onext;
aOnext._Sym._Lnext = b;
bOnext._Sym._Lnext = a;
a._Onext = bOnext;
b._Onext = aOnext;
}
/// <summary>
/// MakeVertex( eOrig, vNext ) attaches a new vertex and makes it the
/// origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
/// a place to insert the new vertex in the global vertex list. We insert
/// the new vertex *before* vNext so that algorithms which walk the vertex
/// list will not see the newly created vertices.
/// </summary>
public static void MakeVertex(Edge eOrig, Vertex vNext)
{
var vNew = MeshUtils.Vertex.Create();
// insert in circular doubly-linked list before vNext
var vPrev = vNext._prev;
vNew._prev = vPrev;
vPrev._next = vNew;
vNew._next = vNext;
vNext._prev = vNew;
vNew._anEdge = eOrig;
// leave coords, s, t undefined
// fix other edges on this vertex loop
var e = eOrig;
do {
e._Org = vNew;
e = e._Onext;
} while (e != eOrig);
}
/// <summary>
/// MakeFace( eOrig, fNext ) attaches a new face and makes it the left
/// face of all edges in the face loop to which eOrig belongs. "fNext" gives
/// a place to insert the new face in the global face list. We insert
/// the new face *before* fNext so that algorithms which walk the face
/// list will not see the newly created faces.
/// </summary>
public static void MakeFace(Edge eOrig, Face fNext)
{
var fNew = MeshUtils.Face.Create();
// insert in circular doubly-linked list before fNext
var fPrev = fNext._prev;
fNew._prev = fPrev;
fPrev._next = fNew;
fNew._next = fNext;
fNext._prev = fNew;
fNew._anEdge = eOrig;
fNew._trail = null;
fNew._marked = false;
// The new face is marked "inside" if the old one was. This is a
// convenience for the common case where a face has been split in two.
fNew._inside = fNext._inside;
// fix other edges on this face loop
var e = eOrig;
do {
e._Lface = fNew;
e = e._Lnext;
} while (e != eOrig);
}
/// <summary>
/// KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
/// and removes from the global edge list.
/// </summary>
public static void KillEdge(Edge eDel)
{
// Half-edges are allocated in pairs, see EdgePair above
Edge.EnsureFirst(ref eDel);
// delete from circular doubly-linked list
var eNext = eDel._next;
var ePrev = eDel._Sym._next;
eNext._Sym._next = ePrev;
ePrev._Sym._next = eNext;
eDel.Free();
}
/// <summary>
/// KillVertex( vDel ) destroys a vertex and removes it from the global
/// vertex list. It updates the vertex loop to point to a given new vertex.
/// </summary>
public static void KillVertex(Vertex vDel, Vertex newOrg)
{
var eStart = vDel._anEdge;
// change the origin of all affected edges
var e = eStart;
do {
e._Org = newOrg;
e = e._Onext;
} while (e != eStart);
// delete from circular doubly-linked list
var vPrev = vDel._prev;
var vNext = vDel._next;
vNext._prev = vPrev;
vPrev._next = vNext;
vDel.Free();
}
/// <summary>
/// KillFace( fDel ) destroys a face and removes it from the global face
/// list. It updates the face loop to point to a given new face.
/// </summary>
public static void KillFace(Face fDel, Face newLFace)
{
var eStart = fDel._anEdge;
// change the left face of all affected edges
var e = eStart;
do {
e._Lface = newLFace;
e = e._Lnext;
} while (e != eStart);
// delete from circular doubly-linked list
var fPrev = fDel._prev;
var fNext = fDel._next;
fNext._prev = fPrev;
fPrev._next = fNext;
fDel.Free();
}
/// <summary>
/// Return signed area of face.
/// </summary>
public static Real FaceArea(Face f)
{
Real area = 0;
var e = f._anEdge;
do
{
area += (e._Org._s - e._Dst._s) * (e._Org._t + e._Dst._t);
e = e._Lnext;
} while (e != f._anEdge);
return area;
}
}
}
} // namespace Unity.VectorGraphics.External

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ada7faed6fbdf4a409392af3cfb70479
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,246 @@
/*
** 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 Unity.SpriteShape.External
{
namespace LibTessDotNet
{
internal struct PQHandle
{
public static readonly int Invalid = 0x0fffffff;
internal int _handle;
}
internal class PriorityHeap<TValue> where TValue : class
{
public delegate bool LessOrEqual(TValue lhs, TValue rhs);
protected class HandleElem
{
internal TValue _key;
internal int _node;
}
private LessOrEqual _leq;
private int[] _nodes;
private HandleElem[] _handles;
private int _size, _max;
private int _freeList;
private bool _initialized;
public bool Empty { get { return _size == 0; } }
public PriorityHeap(int initialSize, LessOrEqual leq)
{
_leq = leq;
_nodes = new int[initialSize + 1];
_handles = new HandleElem[initialSize + 1];
_size = 0;
_max = initialSize;
_freeList = 0;
_initialized = false;
_nodes[1] = 1;
_handles[1] = new HandleElem { _key = null };
}
private void FloatDown(int curr)
{
int child;
int hCurr, hChild;
hCurr = _nodes[curr];
while (true)
{
child = curr << 1;
if (child < _size && _leq(_handles[_nodes[child + 1]]._key, _handles[_nodes[child]]._key))
{
++child;
}
Debug.Assert(child <= _max);
hChild = _nodes[child];
if (child > _size || _leq(_handles[hCurr]._key, _handles[hChild]._key))
{
_nodes[curr] = hCurr;
_handles[hCurr]._node = curr;
break;
}
_nodes[curr] = hChild;
_handles[hChild]._node = curr;
curr = child;
}
}
private void FloatUp(int curr)
{
int parent;
int hCurr, hParent;
hCurr = _nodes[curr];
while (true)
{
parent = curr >> 1;
hParent = _nodes[parent];
if (parent == 0 || _leq(_handles[hParent]._key, _handles[hCurr]._key))
{
_nodes[curr] = hCurr;
_handles[hCurr]._node = curr;
break;
}
_nodes[curr] = hParent;
_handles[hParent]._node = curr;
curr = parent;
}
}
public void Init()
{
for (int i = _size; i >= 1; --i)
{
FloatDown(i);
}
_initialized = true;
}
public PQHandle Insert(TValue value)
{
int curr = ++_size;
if ((curr * 2) > _max)
{
_max <<= 1;
Array.Resize(ref _nodes, _max + 1);
Array.Resize(ref _handles, _max + 1);
}
int free;
if (_freeList == 0)
{
free = curr;
}
else
{
free = _freeList;
_freeList = _handles[free]._node;
}
_nodes[curr] = free;
if (_handles[free] == null)
{
_handles[free] = new HandleElem { _key = value, _node = curr };
}
else
{
_handles[free]._node = curr;
_handles[free]._key = value;
}
if (_initialized)
{
FloatUp(curr);
}
Debug.Assert(free != PQHandle.Invalid);
return new PQHandle { _handle = free };
}
public TValue ExtractMin()
{
Debug.Assert(_initialized);
int hMin = _nodes[1];
TValue min = _handles[hMin]._key;
if (_size > 0)
{
_nodes[1] = _nodes[_size];
_handles[_nodes[1]]._node = 1;
_handles[hMin]._key = null;
_handles[hMin]._node = _freeList;
_freeList = hMin;
if (--_size > 0)
{
FloatDown(1);
}
}
return min;
}
public TValue Minimum()
{
Debug.Assert(_initialized);
return _handles[_nodes[1]]._key;
}
public void Remove(PQHandle handle)
{
Debug.Assert(_initialized);
int hCurr = handle._handle;
Debug.Assert(hCurr >= 1 && hCurr <= _max && _handles[hCurr]._key != null);
int curr = _handles[hCurr]._node;
_nodes[curr] = _nodes[_size];
_handles[_nodes[curr]]._node = curr;
if (curr <= --_size)
{
if (curr <= 1 || _leq(_handles[_nodes[curr >> 1]]._key, _handles[_nodes[curr]]._key))
{
FloatDown(curr);
}
else
{
FloatUp(curr);
}
}
_handles[hCurr]._key = null;
_handles[hCurr]._node = _freeList;
_freeList = hCurr;
}
}
}
} // namespace Unity.VectorGraphics.External

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 08bd485b57bc7c7498c8597502c34793
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,231 @@
/*
** 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.Collections.Generic;
using System.Diagnostics;
namespace Unity.SpriteShape.External
{
namespace LibTessDotNet
{
internal class PriorityQueue<TValue> where TValue : class
{
private PriorityHeap<TValue>.LessOrEqual _leq;
private PriorityHeap<TValue> _heap;
private TValue[] _keys;
private int[] _order;
private int _size, _max;
private bool _initialized;
public bool Empty { get { return _size == 0 && _heap.Empty; } }
public PriorityQueue(int initialSize, PriorityHeap<TValue>.LessOrEqual leq)
{
_leq = leq;
_heap = new PriorityHeap<TValue>(initialSize, leq);
_keys = new TValue[initialSize];
_size = 0;
_max = initialSize;
_initialized = false;
}
class StackItem
{
internal int p, r;
};
static void Swap(ref int a, ref int b)
{
int tmp = a;
a = b;
b = tmp;
}
public void Init()
{
var stack = new Stack<StackItem>();
int p, r, i, j, piv;
uint seed = 2016473283;
p = 0;
r = _size - 1;
_order = new int[_size + 1];
for (piv = 0, i = p; i <= r; ++piv, ++i)
{
_order[i] = piv;
}
stack.Push(new StackItem { p = p, r = r });
while (stack.Count > 0)
{
var top = stack.Pop();
p = top.p;
r = top.r;
while (r > p + 10)
{
seed = seed * 1539415821 + 1;
i = p + (int)(seed % (r - p + 1));
piv = _order[i];
_order[i] = _order[p];
_order[p] = piv;
i = p - 1;
j = r + 1;
do {
do { ++i; } while (!_leq(_keys[_order[i]], _keys[piv]));
do { --j; } while (!_leq(_keys[piv], _keys[_order[j]]));
Swap(ref _order[i], ref _order[j]);
} while (i < j);
Swap(ref _order[i], ref _order[j]);
if (i - p < r - j)
{
stack.Push(new StackItem { p = j + 1, r = r });
r = i - 1;
}
else
{
stack.Push(new StackItem { p = p, r = i - 1 });
p = j + 1;
}
}
for (i = p + 1; i <= r; ++i)
{
piv = _order[i];
for (j = i; j > p && !_leq(_keys[piv], _keys[_order[j - 1]]); --j)
{
_order[j] = _order[j - 1];
}
_order[j] = piv;
}
}
#if DEBUG
p = 0;
r = _size - 1;
for (i = p; i < r; ++i)
{
Debug.Assert(_leq(_keys[_order[i + 1]], _keys[_order[i]]), "Wrong sort");
}
#endif
_max = _size;
_initialized = true;
_heap.Init();
}
public PQHandle Insert(TValue value)
{
if (_initialized)
{
return _heap.Insert(value);
}
int curr = _size;
if (++_size >= _max)
{
_max <<= 1;
Array.Resize(ref _keys, _max);
}
_keys[curr] = value;
return new PQHandle { _handle = -(curr + 1) };
}
public TValue ExtractMin()
{
Debug.Assert(_initialized);
if (_size == 0)
{
return _heap.ExtractMin();
}
TValue sortMin = _keys[_order[_size - 1]];
if (!_heap.Empty)
{
TValue heapMin = _heap.Minimum();
if (_leq(heapMin, sortMin))
return _heap.ExtractMin();
}
do {
--_size;
} while (_size > 0 && _keys[_order[_size - 1]] == null);
return sortMin;
}
public TValue Minimum()
{
Debug.Assert(_initialized);
if (_size == 0)
{
return _heap.Minimum();
}
TValue sortMin = _keys[_order[_size - 1]];
if (!_heap.Empty)
{
TValue heapMin = _heap.Minimum();
if (_leq(heapMin, sortMin))
return heapMin;
}
return sortMin;
}
public void Remove(PQHandle handle)
{
Debug.Assert(_initialized);
int curr = handle._handle;
if (curr >= 0)
{
_heap.Remove(handle);
return;
}
curr = -(curr + 1);
Debug.Assert(curr < _max && _keys[curr] != null);
_keys[curr] = null;
while (_size > 0 && _keys[_order[_size - 1]] == null)
{
--_size;
}
}
}
}
} // namespace Unity.VectorGraphics.External

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: daf70eb4f3701c347bfa9c15178b236a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 64ce47adfe8718046a27fd95ffeee1b1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,746 @@
/*
** 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 Unity.SpriteShape.External
{
using Real = System.Single;
namespace LibTessDotNet
{
internal enum WindingRule
{
EvenOdd,
NonZero,
Positive,
Negative,
AbsGeqTwo
}
internal enum ElementType
{
Polygons,
ConnectedPolygons,
BoundaryContours
}
internal enum ContourOrientation
{
Original,
Clockwise,
CounterClockwise
}
internal struct ContourVertex
{
public Vec3 Position;
public object Data;
public override string ToString()
{
return string.Format("{0}, {1}", Position, Data);
}
}
internal delegate object CombineCallback(Vec3 position, object[] data, Real[] weights);
internal partial class Tess
{
private Mesh _mesh;
private Vec3 _normal;
private Vec3 _sUnit;
private Vec3 _tUnit;
private Real _bminX, _bminY, _bmaxX, _bmaxY;
private WindingRule _windingRule;
private Dict<ActiveRegion> _dict;
private PriorityQueue<MeshUtils.Vertex> _pq;
private MeshUtils.Vertex _event;
private CombineCallback _combineCallback;
private ContourVertex[] _vertices;
private int _vertexCount;
private int[] _elements;
private int _elementCount;
public Vec3 Normal { get { return _normal; } set { _normal = value; } }
public Real SUnitX = 1;
public Real SUnitY = 0;
public Real SentinelCoord = 4e30f;
/// <summary>
/// If true, will remove empty (zero area) polygons.
/// </summary>
public bool NoEmptyPolygons = false;
/// <summary>
/// If true, will use pooling to reduce GC (compare performance with/without, can vary wildly).
/// </summary>
public bool UsePooling = false;
public ContourVertex[] Vertices { get { return _vertices; } }
public int VertexCount { get { return _vertexCount; } }
public int[] Elements { get { return _elements; } }
public int ElementCount { get { return _elementCount; } }
public Tess()
{
_normal = Vec3.Zero;
_bminX = _bminY = _bmaxX = _bmaxY = 0;
_windingRule = WindingRule.EvenOdd;
_mesh = null;
_vertices = null;
_vertexCount = 0;
_elements = null;
_elementCount = 0;
}
private void ComputeNormal(ref Vec3 norm)
{
var v = _mesh._vHead._next;
var minVal = new Real[3] { v._coords.X, v._coords.Y, v._coords.Z };
var minVert = new MeshUtils.Vertex[3] { v, v, v };
var maxVal = new Real[3] { v._coords.X, v._coords.Y, v._coords.Z };
var maxVert = new MeshUtils.Vertex[3] { v, v, v };
for (; v != _mesh._vHead; v = v._next)
{
if (v._coords.X < minVal[0]) { minVal[0] = v._coords.X; minVert[0] = v; }
if (v._coords.Y < minVal[1]) { minVal[1] = v._coords.Y; minVert[1] = v; }
if (v._coords.Z < minVal[2]) { minVal[2] = v._coords.Z; minVert[2] = v; }
if (v._coords.X > maxVal[0]) { maxVal[0] = v._coords.X; maxVert[0] = v; }
if (v._coords.Y > maxVal[1]) { maxVal[1] = v._coords.Y; maxVert[1] = v; }
if (v._coords.Z > maxVal[2]) { maxVal[2] = v._coords.Z; maxVert[2] = v; }
}
// Find two vertices separated by at least 1/sqrt(3) of the maximum
// distance between any two vertices
int i = 0;
if (maxVal[1] - minVal[1] > maxVal[0] - minVal[0]) { i = 1; }
if (maxVal[2] - minVal[2] > maxVal[i] - minVal[i]) { i = 2; }
if (minVal[i] >= maxVal[i])
{
// All vertices are the same -- normal doesn't matter
norm = new Vec3 { X = 0, Y = 0, Z = 1 };
return;
}
// Look for a third vertex which forms the triangle with maximum area
// (Length of normal == twice the triangle area)
Real maxLen2 = 0, tLen2;
var v1 = minVert[i];
var v2 = maxVert[i];
Vec3 d1, d2, tNorm;
Vec3.Sub(ref v1._coords, ref v2._coords, out d1);
for (v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
Vec3.Sub(ref v._coords, ref v2._coords, out d2);
tNorm.X = d1.Y * d2.Z - d1.Z * d2.Y;
tNorm.Y = d1.Z * d2.X - d1.X * d2.Z;
tNorm.Z = d1.X * d2.Y - d1.Y * d2.X;
tLen2 = tNorm.X*tNorm.X + tNorm.Y*tNorm.Y + tNorm.Z*tNorm.Z;
if (tLen2 > maxLen2)
{
maxLen2 = tLen2;
norm = tNorm;
}
}
if (maxLen2 <= 0.0f)
{
// All points lie on a single line -- any decent normal will do
norm = Vec3.Zero;
i = Vec3.LongAxis(ref d1);
norm[i] = 1;
}
}
private void CheckOrientation()
{
// When we compute the normal automatically, we choose the orientation
// so that the the sum of the signed areas of all contours is non-negative.
Real area = 0.0f;
for (var f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
if (f._anEdge._winding <= 0)
{
continue;
}
area += MeshUtils.FaceArea(f);
}
if (area < 0.0f)
{
// Reverse the orientation by flipping all the t-coordinates
for (var v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
v._t = -v._t;
}
Vec3.Neg(ref _tUnit);
}
}
private void ProjectPolygon()
{
var norm = _normal;
bool computedNormal = false;
if (norm.X == 0.0f && norm.Y == 0.0f && norm.Z == 0.0f)
{
ComputeNormal(ref norm);
_normal = norm;
computedNormal = true;
}
int i = Vec3.LongAxis(ref norm);
_sUnit[i] = 0;
_sUnit[(i + 1) % 3] = SUnitX;
_sUnit[(i + 2) % 3] = SUnitY;
_tUnit[i] = 0;
_tUnit[(i + 1) % 3] = norm[i] > 0.0f ? -SUnitY : SUnitY;
_tUnit[(i + 2) % 3] = norm[i] > 0.0f ? SUnitX : -SUnitX;
// Project the vertices onto the sweep plane
for (var v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
Vec3.Dot(ref v._coords, ref _sUnit, out v._s);
Vec3.Dot(ref v._coords, ref _tUnit, out v._t);
}
if (computedNormal)
{
CheckOrientation();
}
// Compute ST bounds.
bool first = true;
for (var v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
if (first)
{
_bminX = _bmaxX = v._s;
_bminY = _bmaxY = v._t;
first = false;
}
else
{
if (v._s < _bminX) _bminX = v._s;
if (v._s > _bmaxX) _bmaxX = v._s;
if (v._t < _bminY) _bminY = v._t;
if (v._t > _bmaxY) _bmaxY = v._t;
}
}
}
/// <summary>
/// TessellateMonoRegion( face ) tessellates a monotone region
/// (what else would it do??) The region must consist of a single
/// loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
/// case means that any vertical line intersects the interior of the
/// region in a single interval.
///
/// Tessellation consists of adding interior edges (actually pairs of
/// half-edges), to split the region into non-overlapping triangles.
///
/// The basic idea is explained in Preparata and Shamos (which I don't
/// have handy right now), although their implementation is more
/// complicated than this one. The are two edge chains, an upper chain
/// and a lower chain. We process all vertices from both chains in order,
/// from right to left.
///
/// The algorithm ensures that the following invariant holds after each
/// vertex is processed: the untessellated region consists of two
/// chains, where one chain (say the upper) is a single edge, and
/// the other chain is concave. The left vertex of the single edge
/// is always to the left of all vertices in the concave chain.
///
/// Each step consists of adding the rightmost unprocessed vertex to one
/// of the two chains, and forming a fan of triangles from the rightmost
/// of two chain endpoints. Determining whether we can add each triangle
/// to the fan is a simple orientation test. By making the fan as large
/// as possible, we restore the invariant (check it yourself).
/// </summary>
private void TessellateMonoRegion(MeshUtils.Face face)
{
// All edges are oriented CCW around the boundary of the region.
// First, find the half-edge whose origin vertex is rightmost.
// Since the sweep goes from left to right, face->anEdge should
// be close to the edge we want.
var up = face._anEdge;
Debug.Assert(up._Lnext != up && up._Lnext._Lnext != up);
while (Geom.VertLeq(up._Dst, up._Org)) up = up._Lprev;
while (Geom.VertLeq(up._Org, up._Dst)) up = up._Lnext;
var lo = up._Lprev;
while (up._Lnext != lo)
{
if (Geom.VertLeq(up._Dst, lo._Org))
{
// up.Dst is on the left. It is safe to form triangles from lo.Org.
// The EdgeGoesLeft test guarantees progress even when some triangles
// are CW, given that the upper and lower chains are truly monotone.
while (lo._Lnext != up && (Geom.EdgeGoesLeft(lo._Lnext)
|| Geom.EdgeSign(lo._Org, lo._Dst, lo._Lnext._Dst) <= 0.0f))
{
lo = _mesh.Connect(lo._Lnext, lo)._Sym;
}
lo = lo._Lprev;
}
else
{
// lo.Org is on the left. We can make CCW triangles from up.Dst.
while (lo._Lnext != up && (Geom.EdgeGoesRight(up._Lprev)
|| Geom.EdgeSign(up._Dst, up._Org, up._Lprev._Org) >= 0.0f))
{
up = _mesh.Connect(up, up._Lprev)._Sym;
}
up = up._Lnext;
}
}
// Now lo.Org == up.Dst == the leftmost vertex. The remaining region
// can be tessellated in a fan from this leftmost vertex.
Debug.Assert(lo._Lnext != up);
while (lo._Lnext._Lnext != up)
{
lo = _mesh.Connect(lo._Lnext, lo)._Sym;
}
}
/// <summary>
/// TessellateInterior( mesh ) tessellates each region of
/// the mesh which is marked "inside" the polygon. Each such region
/// must be monotone.
/// </summary>
private void TessellateInterior()
{
MeshUtils.Face f, next;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = next)
{
// Make sure we don't try to tessellate the new triangles.
next = f._next;
if (f._inside)
{
TessellateMonoRegion(f);
}
}
}
/// <summary>
/// DiscardExterior zaps (ie. sets to null) all faces
/// which are not marked "inside" the polygon. Since further mesh operations
/// on NULL faces are not allowed, the main purpose is to clean up the
/// mesh so that exterior loops are not represented in the data structure.
/// </summary>
private void DiscardExterior()
{
MeshUtils.Face f, next;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = next)
{
// Since f will be destroyed, save its next pointer.
next = f._next;
if( ! f._inside ) {
_mesh.ZapFace(f);
}
}
}
/// <summary>
/// SetWindingNumber( value, keepOnlyBoundary ) resets the
/// winding numbers on all edges so that regions marked "inside" the
/// polygon have a winding number of "value", and regions outside
/// have a winding number of 0.
///
/// If keepOnlyBoundary is TRUE, it also deletes all edges which do not
/// separate an interior region from an exterior one.
/// </summary>
private void SetWindingNumber(int value, bool keepOnlyBoundary)
{
MeshUtils.Edge e, eNext;
for (e = _mesh._eHead._next; e != _mesh._eHead; e = eNext)
{
eNext = e._next;
if (e._Rface._inside != e._Lface._inside)
{
/* This is a boundary edge (one side is interior, one is exterior). */
e._winding = (e._Lface._inside) ? value : -value;
}
else
{
/* Both regions are interior, or both are exterior. */
if (!keepOnlyBoundary)
{
e._winding = 0;
}
else
{
_mesh.Delete(e);
}
}
}
}
private int GetNeighbourFace(MeshUtils.Edge edge)
{
if (edge._Rface == null)
return MeshUtils.Undef;
if (!edge._Rface._inside)
return MeshUtils.Undef;
return edge._Rface._n;
}
private void OutputPolymesh(ElementType elementType, int polySize)
{
MeshUtils.Vertex v;
MeshUtils.Face f;
MeshUtils.Edge edge;
int maxFaceCount = 0;
int maxVertexCount = 0;
int faceVerts, i;
if (polySize < 3)
{
polySize = 3;
}
// Assume that the input data is triangles now.
// Try to merge as many polygons as possible
if (polySize > 3)
{
_mesh.MergeConvexFaces(polySize);
}
// Mark unused
for (v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
v._n = MeshUtils.Undef;
// Create unique IDs for all vertices and faces.
for (f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
f._n = MeshUtils.Undef;
if (!f._inside) continue;
if (NoEmptyPolygons)
{
var area = MeshUtils.FaceArea(f);
if (Math.Abs(area) < Real.Epsilon)
{
continue;
}
}
edge = f._anEdge;
faceVerts = 0;
do {
v = edge._Org;
if (v._n == MeshUtils.Undef)
{
v._n = maxVertexCount;
maxVertexCount++;
}
faceVerts++;
edge = edge._Lnext;
}
while (edge != f._anEdge);
Debug.Assert(faceVerts <= polySize);
f._n = maxFaceCount;
++maxFaceCount;
}
_elementCount = maxFaceCount;
if (elementType == ElementType.ConnectedPolygons)
maxFaceCount *= 2;
_elements = new int[maxFaceCount * polySize];
_vertexCount = maxVertexCount;
_vertices = new ContourVertex[_vertexCount];
// Output vertices.
for (v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
if (v._n != MeshUtils.Undef)
{
// Store coordinate
_vertices[v._n].Position = v._coords;
_vertices[v._n].Data = v._data;
}
}
// Output indices.
int elementIndex = 0;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
if (!f._inside) continue;
if (NoEmptyPolygons)
{
var area = MeshUtils.FaceArea(f);
if (Math.Abs(area) < Real.Epsilon)
{
continue;
}
}
// Store polygon
edge = f._anEdge;
faceVerts = 0;
do {
v = edge._Org;
_elements[elementIndex++] = v._n;
faceVerts++;
edge = edge._Lnext;
} while (edge != f._anEdge);
// Fill unused.
for (i = faceVerts; i < polySize; ++i)
{
_elements[elementIndex++] = MeshUtils.Undef;
}
// Store polygon connectivity
if (elementType == ElementType.ConnectedPolygons)
{
edge = f._anEdge;
do
{
_elements[elementIndex++] = GetNeighbourFace(edge);
edge = edge._Lnext;
} while (edge != f._anEdge);
// Fill unused.
for (i = faceVerts; i < polySize; ++i)
{
_elements[elementIndex++] = MeshUtils.Undef;
}
}
}
}
private void OutputContours()
{
MeshUtils.Face f;
MeshUtils.Edge edge, start;
int startVert = 0;
int vertCount = 0;
_vertexCount = 0;
_elementCount = 0;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
if (!f._inside) continue;
start = edge = f._anEdge;
do
{
++_vertexCount;
edge = edge._Lnext;
}
while (edge != start);
++_elementCount;
}
_elements = new int[_elementCount * 2];
_vertices = new ContourVertex[_vertexCount];
int vertIndex = 0;
int elementIndex = 0;
startVert = 0;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
if (!f._inside) continue;
vertCount = 0;
start = edge = f._anEdge;
do {
_vertices[vertIndex].Position = edge._Org._coords;
_vertices[vertIndex].Data = edge._Org._data;
++vertIndex;
++vertCount;
edge = edge._Lnext;
} while (edge != start);
_elements[elementIndex++] = startVert;
_elements[elementIndex++] = vertCount;
startVert += vertCount;
}
}
private Real SignedArea(ContourVertex[] vertices)
{
Real area = 0.0f;
for (int i = 0; i < vertices.Length; i++)
{
var v0 = vertices[i];
var v1 = vertices[(i + 1) % vertices.Length];
area += v0.Position.X * v1.Position.Y;
area -= v0.Position.Y * v1.Position.X;
}
return 0.5f * area;
}
public void AddContour(ContourVertex[] vertices)
{
AddContour(vertices, ContourOrientation.Original);
}
public void AddContour(ContourVertex[] vertices, ContourOrientation forceOrientation)
{
if (_mesh == null)
{
_mesh = new Mesh();
}
bool reverse = false;
if (forceOrientation != ContourOrientation.Original)
{
var area = SignedArea(vertices);
reverse = (forceOrientation == ContourOrientation.Clockwise && area < 0.0f) || (forceOrientation == ContourOrientation.CounterClockwise && area > 0.0f);
}
MeshUtils.Edge e = null;
for (int i = 0; i < vertices.Length; ++i)
{
if (e == null)
{
e = _mesh.MakeEdge();
_mesh.Splice(e, e._Sym);
}
else
{
// Create a new vertex and edge which immediately follow e
// in the ordering around the left face.
_mesh.SplitEdge(e);
e = e._Lnext;
}
int index = reverse ? vertices.Length - 1 - i : i;
// The new vertex is now e._Org.
e._Org._coords = vertices[index].Position;
e._Org._data = vertices[index].Data;
// The winding of an edge says how the winding number changes as we
// cross from the edge's right face to its left face. We add the
// vertices in such an order that a CCW contour will add +1 to
// the winding number of the region inside the contour.
e._winding = 1;
e._Sym._winding = -1;
}
}
public void Tessellate(WindingRule windingRule, ElementType elementType, int polySize)
{
Tessellate(windingRule, elementType, polySize, null);
}
public void Tessellate(WindingRule windingRule, ElementType elementType, int polySize, CombineCallback combineCallback)
{
_normal = Vec3.Zero;
_vertices = null;
_elements = null;
_windingRule = windingRule;
_combineCallback = combineCallback;
if (_mesh == null)
{
return;
}
// Determine the polygon normal and project vertices onto the plane
// of the polygon.
ProjectPolygon();
// ComputeInterior computes the planar arrangement specified
// by the given contours, and further subdivides this arrangement
// into regions. Each region is marked "inside" if it belongs
// to the polygon, according to the rule given by windingRule.
// Each interior region is guaranteed be monotone.
ComputeInterior();
// If the user wants only the boundary contours, we throw away all edges
// except those which separate the interior from the exterior.
// Otherwise we tessellate all the regions marked "inside".
if (elementType == ElementType.BoundaryContours)
{
SetWindingNumber(1, true);
}
else
{
TessellateInterior();
}
_mesh.Check();
if (elementType == ElementType.BoundaryContours)
{
OutputContours();
}
else
{
OutputPolymesh(elementType, polySize);
}
if (UsePooling)
{
_mesh.Free();
}
_mesh = null;
}
}
}
} // namespace Unity.VectorGraphics.External

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 829c254d9e402e64183afa0e99951e04
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: