You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
475 lines
16 KiB
475 lines
16 KiB
/* |
|
** 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; |
|
using UnityEngine.Scripting.APIUpdating; |
|
|
|
namespace UnityEngine.Rendering.Universal |
|
{ |
|
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; |
|
} |
|
} |
|
} |
|
}
|
|
|