Singularity/Library/PackageCache/com.unity.render-pipelines..../Runtime/External/LibTessDotNet/MeshUtils.cs

476 lines
16 KiB
C#
Raw Normal View History

2024-05-06 14:45:45 -04:00
/*
** 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;
}
}
}
}