diff --git a/Demo/Android/Xamarin.OpenGL/Xamarin.OpenGL.csproj b/Demo/Android/Xamarin.OpenGL/Xamarin.OpenGL.csproj
index 9d0361cf..49fb4c7f 100644
--- a/Demo/Android/Xamarin.OpenGL/Xamarin.OpenGL.csproj
+++ b/Demo/Android/Xamarin.OpenGL/Xamarin.OpenGL.csproj
@@ -94,10 +94,6 @@
{280d17d5-4435-4ead-839a-33c5a8990e7e}
Typography.OpenFont
-
- {fb5f78f5-c921-405d-8f21-42f7c15c2ad9}
- PixelFarm.MiniAgg.One
-
diff --git a/Demo/Shared/DrawingGL.Common.projitems b/Demo/Shared/DrawingGL.Common.projitems
index b7342c69..80ac7e74 100644
--- a/Demo/Shared/DrawingGL.Common.projitems
+++ b/Demo/Shared/DrawingGL.Common.projitems
@@ -33,7 +33,6 @@
-
diff --git a/Demo/Shared/DrawingGL.Text/TextPrinter.cs b/Demo/Shared/DrawingGL.Text/TextPrinter.cs
index c2cf1f64..4d6cf526 100644
--- a/Demo/Shared/DrawingGL.Text/TextPrinter.cs
+++ b/Demo/Shared/DrawingGL.Text/TextPrinter.cs
@@ -3,6 +3,7 @@
using Typography.OpenFont;
using Typography.TextLayout;
using Typography.Contours;
+using Tesselate;
namespace DrawingGL.Text
{
@@ -23,7 +24,7 @@ class TextPrinter : TextPrinterBase
// for tess
//
SimpleCurveFlattener _curveFlattener;
- TessTool _tessTool;
+ Tesselate.TessTool _tessTool;
Typeface _currentTypeface;
@@ -31,11 +32,11 @@ class TextPrinter : TextPrinterBase
struct ProcessedGlyph
{
public readonly float[] tessData;
- public readonly ushort tessNElements;
- public ProcessedGlyph(float[] tessData, ushort tessNElements)
+ public readonly ushort vertextCount;
+ public ProcessedGlyph(float[] tessData, ushort vertextCount)
{
this.tessData = tessData;
- this.tessNElements = tessNElements;
+ this.vertextCount = vertextCount;
}
}
GlyphMeshCollection _glyphMeshCollection = new GlyphMeshCollection();
@@ -48,7 +49,7 @@ public TextPrinter()
//
_curveFlattener = new SimpleCurveFlattener();
- _tessTool = new TessTool();
+ _tessTool = new Tesselate.TessTool();
}
@@ -181,17 +182,17 @@ public void GenerateGlyphRuns(TextRun outputTextRun, char[] charBuffer, int star
//do tess
int[] endContours;
float[] flattenPoints = _curveFlattener.Flatten(writablePath._points, out endContours);
- int nTessElems;
- tessData = _tessTool.TessPolygon(flattenPoints, endContours, out nTessElems);
- //-------
- processGlyph = new ProcessedGlyph(tessData, (ushort)nTessElems);
+
+ tessData = _tessTool.TessAsTriVertexArray(flattenPoints, endContours, out int vertexCount);
+ processGlyph = new ProcessedGlyph(tessData, (ushort)vertexCount);
+
_glyphMeshCollection.RegisterCachedGlyph(glyphPlan.glyphIndex, processGlyph);
}
outputTextRun.AddGlyph(
new GlyphRun(glyphPlan,
processGlyph.tessData,
- processGlyph.tessNElements));
+ processGlyph.vertextCount));
}
}
public override void DrawString(char[] textBuffer, int startAt, int len, float x, float y)
diff --git a/Demo/Shared/DrawingGL/Path.cs b/Demo/Shared/DrawingGL/Path.cs
index ec7491f9..4b4dacc3 100644
--- a/Demo/Shared/DrawingGL/Path.cs
+++ b/Demo/Shared/DrawingGL/Path.cs
@@ -111,13 +111,13 @@ public struct GlyphRun
//glyph run contains...
//1.
Typography.TextLayout.UnscaledGlyphPlan _glyphPlan; //10 bytes
- public float[] tessData; //4
- public ushort nTessElements;//2
- internal GlyphRun(Typography.TextLayout.UnscaledGlyphPlan glyphPlan, float[] tessData, ushort nTessElements)
+ public float[] _tessData; //4
+ public ushort _vertextCount;
+ internal GlyphRun(Typography.TextLayout.UnscaledGlyphPlan glyphPlan, float[] tessData, ushort vertextCount)
{
_glyphPlan = glyphPlan;
- this.tessData = tessData;
- this.nTessElements = nTessElements;
+ _tessData = tessData;
+ _vertextCount = vertextCount;
}
public Typography.TextLayout.UnscaledGlyphPlan GlyphPlan => _glyphPlan;
diff --git a/Demo/Shared/DrawingGL/SimpleCanvas.cs b/Demo/Shared/DrawingGL/SimpleCanvas.cs
index 0a317dda..09ea65a4 100644
--- a/Demo/Shared/DrawingGL/SimpleCanvas.cs
+++ b/Demo/Shared/DrawingGL/SimpleCanvas.cs
@@ -21,7 +21,7 @@ public class SimpleCanvas
MyMat4 _flipVerticalView;
MyMat4 _orthoAndFlip;
- TessTool _tessTool;
+ Tesselate.TessTool _tessTool;
SimpleCurveFlattener _curveFlattener;
//---------------------------------
CanvasToShaderSharedResource _shaderRes;
@@ -56,7 +56,7 @@ public SimpleCanvas(int view_width, int view_height)
//------------
//tools
Tesselate.Tesselator tt = new Tesselate.Tesselator();
- _tessTool = new TessTool(tt);
+ _tessTool = new Tesselate.TessTool(tt);
_curveFlattener = new SimpleCurveFlattener();
ClearColor = Color.White;
//--------
@@ -133,8 +133,8 @@ public void FillTextRun(TextRun textRun, float x, float y)
_fillShader.FillTriangles(
- run.tessData,
- run.nTessElements,
+ run._tessData,
+ run._vertextCount ,
this.FillColor
);
}
diff --git a/Demo/Shared/DrawingGL/TessTool.cs b/Demo/Shared/DrawingGL/TessTool.cs
index 019f87da..f2b36e1f 100644
--- a/Demo/Shared/DrawingGL/TessTool.cs
+++ b/Demo/Shared/DrawingGL/TessTool.cs
@@ -11,39 +11,33 @@
using System;
using System.Collections.Generic;
-using Tesselate;
+
-namespace DrawingGL
+namespace Tesselate
{
- struct TessVertex2d
+ public struct TessVertex2d
{
- public double m_X;
- public double m_Y;
+ public double x;
+ public double y;
public TessVertex2d(double x, double y)
{
- m_X = x;
- m_Y = y;
+ this.x = x;
+ this.y = y;
}
-#if DEBUG
- public override string ToString()
- {
- return this.m_X + "," + this.m_Y;
- }
-#endif
-
}
+
+
///
/// listen and handle the event from tesslator
///
- class TessListener
+ class TessListener : Tesselator.ITessListener
{
internal List _tempVertexList = new List();
internal List _resultIndexList = new List();
int _inputVertexCount;
- Tesselator.TriangleListType _triangleListType;
-
+ //Tesselator.TriangleListType _triangleListType;
public TessListener()
{
//empty not use
@@ -51,13 +45,17 @@ public TessListener()
_tempVertexList.Add(new TessVertex2d(0, 0));
}
- void OnBegin(Tesselator.TriangleListType type)
+ void Tesselator.ITessListener.BeginRead() { }
+ void Tesselator.ITessListener.Begin(Tesselator.TriangleListType type)
{
+#if DEBUG
+
if (type != Tesselator.TriangleListType.Triangles)
{
}
- _triangleListType = type;
+#endif
+ //_triangleListType = type;
//what type of triangle list
//Console.WriteLine("begin: " + type.ToString());
@@ -81,21 +79,21 @@ void OnBegin(Tesselator.TriangleListType type)
//}
}
- void OnEnd()
+ void Tesselator.ITessListener.End()
{
//Assert.IsTrue(GetNextOutputAsString() == "E");
//Console.WriteLine("end");
}
- void OnVertex(int index)
+ void Tesselator.ITessListener.Vertext(int index)
{
//Assert.IsTrue(GetNextOutputAsString() == "V");
//Assert.AreEqual(GetNextOutputAsInt(), index);
if (index < 0)
{
//use data from temp store***
- //that will be append to the end of result
- _resultIndexList.Add((ushort)(_inputVertexCount + (-index)));
+ //that will be appended to the end of result
+ _resultIndexList.Add((ushort)(_inputVertexCount + (-index)));//** minus,=> make it positive sign.
//resultVertexList.Add(this.tempVertextList[-index]);
//Console.WriteLine("temp_v_cb:" + index + ":(" + tempVertextList[-index] + ")");
@@ -108,18 +106,20 @@ void OnVertex(int index)
}
}
- void OnEdgeFlag(bool IsEdge)
+
+ public bool NeedEdgeFlag { get; set; }
+ void Tesselator.ITessListener.EdgeFlag(bool boundaryEdge_isEdge)
{
//Console.WriteLine("edge: " + IsEdge);
//Assert.IsTrue(GetNextOutputAsString() == "F");
//Assert.AreEqual(GetNextOutputAsBool(), IsEdge);
}
- void OnCombine(double v0,
- double v1,
- double v2,
- ref Tesselator.CombineParameters combinePars,
- out int outData)
+ void Tesselator.ITessListener.Combine(double v0,
+ double v1,
+ double v2,
+ ref Tesselator.CombineParameters combinePars,
+ out int outData)
{
//double error = .001;
//Assert.IsTrue(GetNextOutputAsString() == "C");
@@ -147,6 +147,15 @@ void OnCombine(double v0,
//----------------------------------------
}
+
+ public bool NeedMash { get; set; }
+ void Tesselator.ITessListener.Mesh(Mesh mesh)
+ {
+
+ }
+
+
+
///
/// connect to actual Tesselator
///
@@ -154,14 +163,18 @@ void OnCombine(double v0,
///
public void Connect(Tesselator tesselator, bool setEdgeFlag)
{
- tesselator.callBegin = OnBegin;
- tesselator.callEnd = OnEnd;
- tesselator.callVertex = OnVertex;
- tesselator.callCombine = OnCombine;
- if (setEdgeFlag)
- {
- tesselator.callEdgeFlag = OnEdgeFlag;
- }
+
+ NeedEdgeFlag = setEdgeFlag;
+ tesselator.SetListener(this);
+
+ //tesselator.callBegin = OnBegin;
+ //tesselator.callEnd = OnEnd;
+ //tesselator.callVertex = OnVertex;
+ //tesselator.callCombine = OnCombine;
+ //if (setEdgeFlag)
+ //{
+ // tesselator.callEdgeFlag = OnEdgeFlag;
+ //}
}
///
/// clear previous results and load a new input vertex list
@@ -171,18 +184,17 @@ public void ResetAndLoadInputVertexList(int inputVertexCount)
{
_inputVertexCount = inputVertexCount;
//1. reset
- _triangleListType = Tesselator.TriangleListType.LineLoop;//?
+ //_triangleListType = Tesselator.TriangleListType.LineLoop;//?
_tempVertexList.Clear();
_resultIndexList.Clear();
}
}
- class TessTool
+ public class TessTool
{
readonly Tesselator _tess;
readonly TessListener _tessListener;
-
public TessTool() : this(new Tesselator() { WindingRule = Tesselator.WindingRuleType.NonZero }) { }
public TessTool(Tesselator tess)
{
@@ -195,18 +207,19 @@ public Tesselator.WindingRuleType WindingRuleType
get => _tess.WindingRule;
set => _tess.WindingRule = value;
}
- public List TessIndexList => _tessListener._resultIndexList;
- public List TempVertexList => _tessListener._tempVertexList;
+ internal List TessIndexList => _tessListener._resultIndexList;
+ internal List TempVertexList => _tessListener._tempVertexList;
public bool TessPolygon(float[] vertex2dCoords, int[] contourEndPoints)
{
+ //internal tess the polygon
+
int ncoords = vertex2dCoords.Length / 2;
_tessListener.ResetAndLoadInputVertexList(ncoords);
- if (ncoords == 0) { return false; }
- //this support sub contour in the same array of vertex2dCoords
+ if (ncoords == 0) return false;
//-----------------------
+ //this support sub contour in the same array of vertex2dCoords
_tess.BeginPolygon();
-
- if (contourEndPoints == null || contourEndPoints.Length == 1)
+ if (contourEndPoints == null)
{
//only 1 contour
int beginAt = 0;
@@ -216,13 +229,15 @@ public bool TessPolygon(float[] vertex2dCoords, int[] contourEndPoints)
{
_tess.AddVertex(
vertex2dCoords[i << 1], //*2
- vertex2dCoords[(i << 1) + 1], 0, i); //*2+1
+ vertex2dCoords[(i << 1) + 1], i); //*2+1
}
beginAt = thisContourEndAt + 1;
_tess.EndContour();
+
}
else
{
+ //may have more than 1 contour
int nContourCount = contourEndPoints.Length;
int beginAt = 0;
for (int m = 0; m < nContourCount; ++m)
@@ -232,25 +247,20 @@ public bool TessPolygon(float[] vertex2dCoords, int[] contourEndPoints)
for (int i = beginAt; i < thisContourEndAt; ++i)
{
_tess.AddVertex(
- vertex2dCoords[i << 1],
- vertex2dCoords[(i << 1) + 1],
- 0,
+ vertex2dCoords[i << 1], //*2
+ vertex2dCoords[(i << 1) + 1], //*2+1
i);
-
}
beginAt = thisContourEndAt + 1;
_tess.EndContour();
}
}
- //
- //
_tess.EndPolygon();
+ //-----------------------
return true;
}
}
-
-
- static class TessToolExtensions
+ public static class TessToolExtensions
{
///
/// tess and read result as triangle list vertex array (for GLES draw-array)
@@ -260,7 +270,10 @@ static class TessToolExtensions
///
///
///
- public static float[] TessAsTriVertexArray(this TessTool tessTool, float[] vertex2dCoords, int[] contourEndPoints, out int vertexCount)
+ public static float[] TessAsTriVertexArray(this TessTool tessTool,
+ float[] vertex2dCoords,
+ int[] contourEndPoints,
+ out int vertexCount)
{
if (!tessTool.TessPolygon(vertex2dCoords, contourEndPoints))
{
@@ -286,8 +299,8 @@ public static float[] TessAsTriVertexArray(this TessTool tessTool, float[] verte
{
//extra coord (newly created)
TessVertex2d extraVertex = tempVertexList[index - orgVertexCount];
- vtx[n] = (float)extraVertex.m_X;
- vtx[n + 1] = (float)extraVertex.m_Y;
+ vtx[n] = (float)extraVertex.x;
+ vtx[n + 1] = (float)extraVertex.y;
}
else
{
@@ -343,14 +356,995 @@ public static ushort[] TessAsTriIndexArray(this TessTool tessTool,
for (int i = vertex2dCoords.Length; i < endAt; ++i)
{
TessVertex2d v = tempVertexList[p];
- outputCoords[q] = (float)v.m_X;
- outputCoords[q + 1] = (float)v.m_Y;
+ outputCoords[q] = (float)v.x;
+ outputCoords[q + 1] = (float)v.y;
p++;
q += 2;
}
return indexList.ToArray();
}
+ }
+
+ public class Tesselator
+ {
+ // The begin/end calls must be properly nested. We keep track of
+ // the current state to enforce the ordering.
+ enum ProcessingState
+ {
+ Dormant, InPolygon, InContour
+ }
+ // We cache vertex data for single-contour polygons so that we can
+ // try a quick-and-dirty decomposition first.
+ const int MAX_CACHE_SIZE = 100;
+ internal const double MAX_COORD = 1.0e150;
+
+
+ public struct CombineParameters
+ {
+ public int d0, d1, d2, d3;
+ public double w0, w1, w2, w3;
+ }
+ public enum TriangleListType
+ {
+ LineLoop,
+ Triangles,
+ TriangleStrip,
+ TriangleFan
+ }
+
+ public enum WindingRuleType
+ {
+ //see: https://www.glprogramming.com/red/chapter11.html
+ //http://what-when-how.com/opengl-programming-guide/polygon-tessellation-tessellators-and-quadrics-opengl-programming-part-2/
+
+ Odd,
+ NonZero,
+ Positive,
+ Negative,
+ ABS_GEQ_Two,
+ }
+
+ public interface ITessListener
+ {
+ void BeginRead();
+
+ /*** state needed for rendering callbacks (see render.c) ***/
+ void Combine(double c1, double c2, double c3, ref CombineParameters combinePars, out int outData);
+ void Begin(TriangleListType type);
+ void Vertext(int data);
+ void End();
+
+ //
+ void EdgeFlag(bool boundaryEdge);
+ bool NeedEdgeFlag { get; }
+ //
+ void Mesh(Mesh mesh);
+ bool NeedMash { get; }
+ }
+
+
+
+ WindingRuleType _windingRule; // rule for determining polygon interior
+ ProcessingState _processingState; /* what begin/end calls have we seen? */
+ HalfEdge _lastHalfEdge; /* lastEdge.Org is the most recent vertex */
+
+ //
+ internal Mesh _mesh; /* stores the input contours, and eventually the tessellation itself */
+ internal Dictionary _edgeDictionary; /* edge dictionary for sweep line */
+ internal MaxFirstList _vertexPriorityQue = new MaxFirstList();
+ internal ContourVertex currentSweepVertex; /* current sweep event being processed */
+
+
+
+ //----------------
+ ITessListener _tessListener;
+ bool _doEdgeCallback;
+ bool _doMeshCallback;
+
+ /*** state needed for rendering callbacks (see render.c) ***/
+ bool _boundaryOnly; /* Extract contours, not triangles */
+ Face _lonelyTriList;
+ /* list of triangles which could not be rendered as strips or fans */
+
+ //public delegate void CallBeginDelegate(TriangleListType type);
+ //public CallBeginDelegate callBegin;
+ //public delegate void CallEdgeFlagDelegate(bool boundaryEdge);
+ //public CallEdgeFlagDelegate callEdgeFlag;
+ //public delegate void CallVertexDelegate(int data);
+ //public CallVertexDelegate callVertex;
+ //public delegate void CallEndDelegate();
+ //public CallEndDelegate callEnd;
+ //public delegate void CallMeshDelegate(Mesh mesh);
+ //public CallMeshDelegate callMesh;
+
+ ////----------------
+ //public delegate void CallCombineDelegate(
+ // double c1, double c2, double c3, ref CombineParameters combinePars, out int outData);
+ //public CallCombineDelegate callCombine;
+ //----------------
+
+
+
+ //
+ /*** state needed to cache single-contour polygons for renderCache() */
+
+ bool _emptyCache; /* empty cache on next vertex() call */
+ int _cacheCount; /* number of cached vertices */
+ TessVertex2d[] _simpleVertexCache = new TessVertex2d[MAX_CACHE_SIZE]; /* the vertex data */
+ int[] _indexCached = new int[MAX_CACHE_SIZE];
+ //
+ public Tesselator()
+ {
+ /* Only initialize fields which can be changed by the api. Other fields
+ * are initialized where they are used.
+ */
+ _processingState = ProcessingState.Dormant;
+ _windingRule = Tesselator.WindingRuleType.NonZero;//default
+ _boundaryOnly = false;
+ }
+
+ ~Tesselator()
+ {
+ //TODO: review here...
+ RequireState(ProcessingState.Dormant);
+ }
+
+ public void SetListener(ITessListener listener)
+ {
+ _tessListener = listener;
+ _doEdgeCallback = listener.NeedEdgeFlag;
+ _doMeshCallback = listener.NeedMash;
+ }
+
+ bool EdgeCallBackSet => _doEdgeCallback;
+
+ public WindingRuleType WindingRule
+ {
+ get => _windingRule;
+ set => _windingRule = value;
+ }
+
+ public bool BoundaryOnly
+ {
+ get => _boundaryOnly;
+ set => _boundaryOnly = value;
+ }
+
+ public bool IsWindingInside(int numCrossings)
+ {
+ switch (_windingRule)
+ {
+ case Tesselator.WindingRuleType.Odd:
+ return (numCrossings & 1) != 0;
+ case Tesselator.WindingRuleType.NonZero:
+ return (numCrossings != 0);
+ case Tesselator.WindingRuleType.Positive:
+ return (numCrossings > 0);
+ case Tesselator.WindingRuleType.Negative:
+ return (numCrossings < 0);
+ case Tesselator.WindingRuleType.ABS_GEQ_Two:
+ return (numCrossings >= 2) || (numCrossings <= -2);
+ }
+ throw new Exception();
+ }
+
+ void CallBegin(TriangleListType triangleType)
+ {
+ _tessListener.Begin(triangleType);
+ //callBegin?.Invoke(triangleType);
+ }
+ void CallVertex(int vertexData)
+ {
+ _tessListener.Vertext(vertexData);
+ //callVertex?.Invoke(vertexData);
+ }
+ void CallEdgeFlag(bool edgeState)
+ {
+ _tessListener.EdgeFlag(edgeState);
+ //callEdgeFlag?.Invoke(edgeState);
+ }
+ void CallEnd()
+ {
+ _tessListener.End();
+ }
+
+ internal void CallCombine(double v0,
+ double v1, double v2,
+ ref CombineParameters combinePars,
+ out int outData)
+ {
+ outData = 0;
+ _tessListener.Combine(v0, v1, v2, ref combinePars, out outData);
+ }
+
+ void GotoState(ProcessingState newProcessingState)
+ {
+ while (_processingState != newProcessingState)
+ {
+ /* We change the current state one level at a time, to get to
+ * the desired state.
+ */
+ if (_processingState < newProcessingState)
+ {
+ switch (_processingState)
+ {
+ case ProcessingState.Dormant:
+ throw new Exception("MISSING_BEGIN_POLYGON");
+ case ProcessingState.InPolygon:
+ throw new Exception("MISSING_BEGIN_CONTOUR");
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (_processingState)
+ {
+ case ProcessingState.InContour:
+ throw new Exception("MISSING_END_CONTOUR");
+ case ProcessingState.InPolygon:
+ throw new Exception("MISSING_END_POLYGON");
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ void RequireState(ProcessingState state)
+ {
+ if (_processingState != state)
+ {
+ GotoState(state);
+ }
+ }
+
+ public virtual void BeginPolygon()
+ {
+ RequireState(ProcessingState.Dormant);
+ _processingState = ProcessingState.InPolygon;
+ _cacheCount = 0;
+ _emptyCache = false;
+ _mesh = null;
+ }
+
+ public void BeginContour()
+ {
+ RequireState(ProcessingState.InPolygon);
+ _processingState = ProcessingState.InContour;
+ _lastHalfEdge = null;
+ if (_cacheCount > 0)
+ {
+ // Just set a flag so we don't get confused by empty contours
+ _emptyCache = true;
+ }
+ }
+
+ bool InnerAddVertex(double x, double y, int data)
+ {
+ HalfEdge e;
+ e = _lastHalfEdge;
+ if (e == null)
+ {
+ /* Make a self-loop (one vertex, one edge). */
+ e = _mesh.MakeEdge();
+ Mesh.meshSplice(e, e._otherHalfOfThisEdge);
+ }
+ else
+ {
+ /* Create a new vertex and edge which immediately follow e
+ * in the ordering around the left face.
+ */
+ if (Mesh.meshSplitEdge(e) == null)
+ {
+ return false;
+ }
+ e = e._nextEdgeCCWAroundLeftFace;
+ }
+
+ /* The new vertex is now e.Org. */
+ e._originVertex._clientIndex = data;
+ e._originVertex._C_0 = x;
+ e._originVertex._C_1 = y;
+ /* 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._otherHalfOfThisEdge._winding = -1;
+ _lastHalfEdge = e;
+ return true;
+ }
+
+ void EmptyCache()
+ {
+ TessVertex2d[] vCaches = _simpleVertexCache;
+ int[] index_caches = _indexCached;
+ _mesh = new Mesh();
+ int count = _cacheCount;
+ for (int i = 0; i < count; i++)
+ {
+ TessVertex2d v = vCaches[i];
+ this.InnerAddVertex(v.x, v.y, index_caches[i]);
+ }
+ _cacheCount = 0;
+ _emptyCache = false;
+ }
+
+ void CacheVertex(double x, double y, double z, int data)
+ {
+ TessVertex2d v = new TessVertex2d();
+ v.x = x;
+ v.y = y;
+ _simpleVertexCache[_cacheCount] = v;
+ _indexCached[_cacheCount] = data;
+ ++_cacheCount;
+ }
+ void CacheVertex(double x, double y, int data)
+ {
+ TessVertex2d v = new TessVertex2d();
+ v.x = x;
+ v.y = y;
+ _simpleVertexCache[_cacheCount] = v;
+ _indexCached[_cacheCount] = data;
+ ++_cacheCount;
+ }
+
+ public void AddVertex(double x, double y, int data)
+ {
+ RequireState(ProcessingState.InContour);
+
+ if (_emptyCache)
+ {
+ EmptyCache();
+ _lastHalfEdge = null;
+ }
+
+ //....
+ if (x < -MAX_COORD || x > MAX_COORD ||
+ y < -MAX_COORD || y > MAX_COORD)
+ {
+ throw new Exception("Your coordinate exceeded -" + MAX_COORD.ToString() + ".");
+ }
+ //....
+ //
+ if (_mesh == null)
+ {
+ if (_cacheCount < MAX_CACHE_SIZE)
+ {
+ CacheVertex(x, y, data);
+ return;
+ }
+ EmptyCache();
+ }
+
+ InnerAddVertex(x, y, data);
+ }
+ public void AddVertex(double x, double y, double z, int data)
+ {
+ RequireState(ProcessingState.InContour);
+
+ if (_emptyCache)
+ {
+ EmptyCache();
+ _lastHalfEdge = null;
+ }
+
+ //....
+ if (x < -MAX_COORD || x > MAX_COORD ||
+ y < -MAX_COORD || y > MAX_COORD ||
+ z < -MAX_COORD || z > MAX_COORD)
+ {
+ throw new Exception("Your coordinate exceeded -" + MAX_COORD.ToString() + ".");
+ }
+ //....
+ //
+ if (_mesh == null)
+ {
+ if (_cacheCount < MAX_CACHE_SIZE)
+ {
+ CacheVertex(x, y, data);
+ return;
+ }
+ EmptyCache();
+ }
+
+ InnerAddVertex(x, y, data);
+ }
+
+ public void EndContour()
+ {
+ RequireState(ProcessingState.InContour);
+ _processingState = ProcessingState.InPolygon;
+ }
+ void CheckOrientation()
+ {
+ double area = 0;
+ Face curFace, faceHead = _mesh._faceHead;
+ ContourVertex vHead = _mesh._vertexHead;
+ HalfEdge curHalfEdge;
+ /* When we compute the normal automatically, we choose the orientation
+ * so that the sum of the signed areas of all contours is non-negative.
+ */
+ for (curFace = faceHead._nextFace; curFace != faceHead; curFace = curFace._nextFace)
+ {
+ curHalfEdge = curFace._halfEdgeThisIsLeftFaceOf;
+ if (curHalfEdge._winding <= 0)
+ {
+ continue;
+ }
+
+ do
+ {
+ area += (curHalfEdge._originVertex.x - curHalfEdge.DirectionVertex.x)
+ * (curHalfEdge._originVertex.y + curHalfEdge.DirectionVertex.y);
+ curHalfEdge = curHalfEdge._nextEdgeCCWAroundLeftFace;
+ } while (curHalfEdge != curFace._halfEdgeThisIsLeftFaceOf);
+ }
+
+ if (area < 0)
+ {
+ /* Reverse the orientation by flipping all the t-coordinates */
+ for (ContourVertex curVertex = vHead._nextVertex; curVertex != vHead; curVertex = curVertex._nextVertex)
+ {
+ curVertex.y = -curVertex.y;
+ }
+ }
+ }
+
+ void ProjectPolygon()
+ {
+ ContourVertex v, vHead = _mesh._vertexHead;
+ // Project the vertices onto the sweep plane
+ for (v = vHead._nextVertex; v != vHead; v = v._nextVertex)
+ {
+ v.x = v._C_0;
+ v.y = -v._C_1;
+ }
+
+ CheckOrientation();
+ }
+
+ public void EndPolygon()
+ {
+ RequireState(ProcessingState.InPolygon);
+ _processingState = ProcessingState.Dormant;
+ if (_mesh == null)
+ {
+ if (!this.EdgeCallBackSet && !_doMeshCallback)
+ {
+ /* Try some special code to make the easy cases go quickly
+ * (eg. convex polygons). This code does NOT handle multiple contours,
+ * intersections, edge flags, and of course it does not generate
+ * an explicit mesh either.
+ */
+ if (RenderCache())
+ {
+ return;
+ }
+ }
+
+ EmptyCache(); /* could've used a label*/
+ }
+
+ /* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+ ProjectPolygon();
+ /* __gl_computeInterior( this ) 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 this.windingRule.
+ * Each interior region is guaranteed to be monotone.
+ */
+ ActiveRegion.ComputeInterior(this);
+ bool rc = true;
+ /* 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 (_boundaryOnly)
+ {
+ rc = _mesh.SetWindingNumber(1, true);
+ }
+ else
+ {
+ rc = _mesh.TessellateInterior();
+ }
+
+ _mesh.CheckMesh();
+
+ //if (this.callBegin != null || this.callEnd != null
+ // || this.callVertex != null || this.callEdgeFlag != null)
+ //{
+ if (_boundaryOnly)
+ {
+ RenderBoundary(_mesh); /* output boundary contours */
+ }
+ else
+ {
+ RenderMesh(_mesh); /* output strips and fans */
+ }
+ //}
+
+ if (_doMeshCallback)
+ {
+ /* Throw away the exterior faces, so that all faces are interior.
+ * This way the user doesn't have to check the "inside" flag,
+ * and we don't need to even reveal its existence. It also leaves
+ * the freedom for an implementation to not generate the exterior
+ * faces in the first place.
+ */
+ _mesh.DiscardExterior();
+ _tessListener.Mesh(_mesh);/* user wants the mesh itself */
+ //callMesh(mesh); /* user wants the mesh itself */
+ _mesh = null;
+ return;
+ }
+ _mesh = null;
+ }
+
+ class FaceCount
+ {
+ public FaceCount(int _size, HalfEdge _eStart, RenderDelegate _render)
+ {
+ size = _size;
+ eStart = _eStart;
+ render = _render;
+ }
+
+ public int size; /* number of triangles used */
+ public HalfEdge eStart; /* edge where this primitive starts */
+ public delegate void RenderDelegate(Tesselator tess, HalfEdge edge, int data);
+ event RenderDelegate render;
+ // routine to render this primitive
+
+ public void CallRender(Tesselator tess, HalfEdge edge, int data)
+ {
+ render(tess, edge, data);
+ }
+ }
+
+ /************************ Strips and Fans decomposition ******************/
+
+ /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+ void RenderMesh(Mesh mesh)
+ {
+ Face f;
+ /* Make a list of separate triangles so we can render them all at once */
+ _lonelyTriList = null;
+ for (f = mesh._faceHead._nextFace; f != mesh._faceHead; f = f._nextFace)
+ {
+ f._marked = false;
+ }
+ for (f = mesh._faceHead._nextFace; f != mesh._faceHead; f = f._nextFace)
+ {
+ /* We examine all faces in an arbitrary order. Whenever we find
+ * an unprocessed face F, we output a group of faces including F
+ * whose size is maximum.
+ */
+ if (f._isInterior && !f._marked)
+ {
+ RenderMaximumFaceGroup(f);
+ if (!f._marked)
+ {
+ throw new System.Exception();
+ }
+ }
+ }
+ if (_lonelyTriList != null)
+ {
+ RenderLonelyTriangles(_lonelyTriList);
+ _lonelyTriList = null;
+ }
+ }
+
+
+ void RenderMaximumFaceGroup(Face fOrig)
+ {
+ /* We want to find the largest triangle fan or strip of unmarked faces
+ * which includes the given face fOrig. There are 3 possible fans
+ * passing through fOrig (one centered at each vertex), and 3 possible
+ * strips (one for each CCW permutation of the vertices). Our strategy
+ * is to try all of these, and take the primitive which uses the most
+ * triangles (a greedy approach).
+ */
+ HalfEdge e = fOrig._halfEdgeThisIsLeftFaceOf;
+ FaceCount max = new FaceCount(1, e, new FaceCount.RenderDelegate(RenderTriangle));
+ FaceCount newFace;
+ max.size = 1;
+ max.eStart = e;
+ if (!this.EdgeCallBackSet)
+ {
+ newFace = MaximumFan(e); if (newFace.size > max.size) { max = newFace; }
+ newFace = MaximumFan(e._nextEdgeCCWAroundLeftFace); if (newFace.size > max.size) { max = newFace; }
+ newFace = MaximumFan(e.Lprev); if (newFace.size > max.size) { max = newFace; }
+
+ newFace = MaximumStrip(e); if (newFace.size > max.size) { max = newFace; }
+ newFace = MaximumStrip(e._nextEdgeCCWAroundLeftFace); if (newFace.size > max.size) { max = newFace; }
+ newFace = MaximumStrip(e.Lprev); if (newFace.size > max.size) { max = newFace; }
+ }
+
+ max.CallRender(this, max.eStart, max.size);
+ }
+
+ FaceCount MaximumFan(HalfEdge eOrig)
+ {
+ /* eOrig.Lface is the face we want to render. We want to find the size
+ * of a maximal fan around eOrig.Org. To do this we just walk around
+ * the origin vertex as far as possible in both directions.
+ */
+ FaceCount newFace = new FaceCount(0, null, new FaceCount.RenderDelegate(RenderFan));
+ Face trail = null;
+ HalfEdge e;
+ for (e = eOrig; !e._leftFace.Marked(); e = e._nextEdgeCCWAroundOrigin)
+ {
+ Face.AddToTrail(ref e._leftFace, ref trail);
+ ++newFace.size;
+ }
+ for (e = eOrig; !e.rightFace.Marked(); e = e.Oprev)
+ {
+ Face f = e.rightFace;
+ Face.AddToTrail(ref f, ref trail);
+ e.rightFace = f;
+ ++newFace.size;
+ }
+ newFace.eStart = e;
+ Face.FreeTrail(ref trail);
+ return newFace;
+ }
+
+
+ static bool IsEven(int n)
+ {
+ return (((n) & 1) == 0);
+ }
+
+ FaceCount MaximumStrip(HalfEdge eOrig)
+ {
+ /* Here we are looking for a maximal strip that contains the vertices
+ * eOrig.Org, eOrig.Dst, eOrig.Lnext.Dst (in that order or the
+ * reverse, such that all triangles are oriented CCW).
+ *
+ * Again we walk forward and backward as far as possible. However for
+ * strips there is a twist: to get CCW orientations, there must be
+ * an *even* number of triangles in the strip on one side of eOrig.
+ * We walk the strip starting on a side with an even number of triangles;
+ * if both side have an odd number, we are forced to shorten one side.
+ */
+ FaceCount newFace = new FaceCount(0, null, RenderStrip);
+ int headSize = 0, tailSize = 0;
+ Face trail = null;
+ HalfEdge e, eTail, eHead;
+ for (e = eOrig; !e._leftFace.Marked(); ++tailSize, e = e._nextEdgeCCWAroundOrigin)
+ {
+ Face.AddToTrail(ref e._leftFace, ref trail);
+ ++tailSize;
+ e = e.Dprev;
+ if (e._leftFace.Marked()) break;
+ Face.AddToTrail(ref e._leftFace, ref trail);
+ }
+ eTail = e;
+ for (e = eOrig; !e.rightFace.Marked(); ++headSize, e = e.Dnext)
+ {
+ Face f = e.rightFace;
+ Face.AddToTrail(ref f, ref trail);
+ e.rightFace = f;
+ ++headSize;
+ e = e.Oprev;
+ if (e.rightFace.Marked()) break;
+ f = e.rightFace;
+ Face.AddToTrail(ref f, ref trail);
+ e.rightFace = f;
+ }
+ eHead = e;
+ newFace.size = tailSize + headSize;
+ if (IsEven(tailSize))
+ {
+ newFace.eStart = eTail._otherHalfOfThisEdge;
+ }
+ else if (IsEven(headSize))
+ {
+ newFace.eStart = eHead;
+ }
+ else
+ {
+ /* Both sides have odd length, we must shorten one of them. In fact,
+ * we must start from eHead to guarantee inclusion of eOrig.Lface.
+ */
+ --newFace.size;
+ newFace.eStart = eHead._nextEdgeCCWAroundOrigin;
+ }
+
+ Face.FreeTrail(ref trail);
+ return newFace;
+ }
+
+
+ void RenderTriangle(Tesselator tess, HalfEdge e, int size)
+ {
+ /* Just add the triangle to a triangle list, so we can render all
+ * the separate triangles at once.
+ */
+ if (size != 1)
+ {
+ throw new Exception();
+ }
+ Face.AddToTrail(ref e._leftFace, ref _lonelyTriList);
+ }
+
+
+ void RenderLonelyTriangles(Face f)
+ {
+ /* Now we render all the separate triangles which could not be
+ * grouped into a triangle fan or strip.
+ */
+ HalfEdge e;
+ bool newState = false;
+ bool edgeState = false; /* force edge state output for first vertex */
+ bool sentFirstEdge = false;
+ this.CallBegin(Tesselator.TriangleListType.Triangles);
+ for (; f != null; f = f._trail)
+ {
+ /* Loop once for each edge (there will always be 3 edges) */
+
+ e = f._halfEdgeThisIsLeftFaceOf;
+ do
+ {
+ if (this.EdgeCallBackSet)
+ {
+ /* Set the "edge state" to TRUE just before we output the
+ * first vertex of each edge on the polygon boundary.
+ */
+ newState = !e.rightFace._isInterior;
+ if (edgeState != newState || !sentFirstEdge)
+ {
+ sentFirstEdge = true;
+ edgeState = newState;
+ this.CallEdgeFlag(edgeState);
+ }
+ }
+
+ this.CallVertex(e._originVertex._clientIndex);
+ e = e._nextEdgeCCWAroundLeftFace;
+ } while (e != f._halfEdgeThisIsLeftFaceOf);
+ }
+
+ this.CallEnd();
+ }
+
+
+ static void RenderFan(Tesselator tess, HalfEdge e, int size)
+ {
+ /* Render as many CCW triangles as possible in a fan starting from
+ * edge "e". The fan *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ tess.CallBegin(Tesselator.TriangleListType.TriangleFan);
+ tess.CallVertex(e._originVertex._clientIndex);
+ tess.CallVertex(e.DirectionVertex._clientIndex);
+ while (!e._leftFace.Marked())
+ {
+ e._leftFace._marked = true;
+ --size;
+ e = e._nextEdgeCCWAroundOrigin;
+ tess.CallVertex(e.DirectionVertex._clientIndex);
+ }
+
+ if (size != 0)
+ {
+ throw new Exception();
+ }
+ tess.CallEnd();
+ }
+
+
+ static void RenderStrip(Tesselator tess, HalfEdge halfEdge, int size)
+ {
+ /* Render as many CCW triangles as possible in a strip starting from
+ * edge "e". The strip *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ tess.CallBegin(Tesselator.TriangleListType.TriangleStrip);
+ tess.CallVertex(halfEdge._originVertex._clientIndex);
+ tess.CallVertex(halfEdge.DirectionVertex._clientIndex);
+ while (!halfEdge._leftFace.Marked())
+ {
+ halfEdge._leftFace._marked = true;
+ --size;
+ halfEdge = halfEdge.Dprev;
+ tess.CallVertex(halfEdge._originVertex._clientIndex);
+ if (halfEdge._leftFace.Marked()) break;
+ halfEdge._leftFace._marked = true;
+ --size;
+ halfEdge = halfEdge._nextEdgeCCWAroundOrigin;
+ tess.CallVertex(halfEdge.DirectionVertex._clientIndex);
+ }
+
+ if (size != 0)
+ {
+ throw new Exception();
+ }
+ tess.CallEnd();
+ }
+
+
+ /************************ Boundary contour decomposition ******************/
+
+ /* Takes a mesh, and outputs one
+ * contour for each face marked "inside". The rendering output is
+ * provided as callbacks.
+ */
+ void RenderBoundary(Mesh mesh)
+ {
+ for (Face curFace = mesh._faceHead._nextFace; curFace != mesh._faceHead; curFace = curFace._nextFace)
+ {
+ if (curFace._isInterior)
+ {
+ this.CallBegin(Tesselator.TriangleListType.LineLoop);
+ HalfEdge curHalfEdge = curFace._halfEdgeThisIsLeftFaceOf;
+ do
+ {
+ this.CallVertex(curHalfEdge._originVertex._clientIndex);
+ curHalfEdge = curHalfEdge._nextEdgeCCWAroundLeftFace;
+ } while (curHalfEdge != curFace._halfEdgeThisIsLeftFaceOf);
+ this.CallEnd();
+ }
+ }
+ }
+
+
+ /************************ Quick-and-dirty decomposition ******************/
+
+ const int SIGN_INCONSISTENT = 2;
+ int ComputeNormal(ref double nx, ref double ny, ref double nz)
+ /*
+ * Check that each triangle in the fan from v0 has a
+ * consistent orientation with respect to norm3[]. If triangles are
+ * consistently oriented CCW, return 1; if CW, return -1; if all triangles
+ * are degenerate return 0; otherwise (no consistent orientation) return
+ * SIGN_INCONSISTENT.
+ */
+ {
+ var vCache = _simpleVertexCache;
+ TessVertex2d v0 = vCache[0];
+ int vcIndex;
+ double dot, xc, yc, xp, yp;
+ double n0;
+ double n1;
+ double n2;
+ int sign = 0;
+ /* Find the polygon normal. It is important to get a reasonable
+ * normal even when the polygon is self-intersecting (eg. a bowtie).
+ * Otherwise, the computed normal could be very tiny, but perpendicular
+ * to the true plane of the polygon due to numerical noise. Then all
+ * the triangles would appear to be degenerate and we would incorrectly
+ * decompose the polygon as a fan (or simply not render it at all).
+ *
+ * We use a sum-of-triangles normal algorithm rather than the more
+ * efficient sum-of-trapezoids method (used in CheckOrientation()
+ * in normal.c). This lets us explicitly reverse the signed area
+ * of some triangles to get a reasonable normal in the self-intersecting
+ * case.
+ */
+ vcIndex = 1;
+ var v = vCache[vcIndex];
+ xc = v.x - v0.x;
+ yc = v.y - v0.y;
+ int c_count = _cacheCount;
+ while (++vcIndex < c_count)
+ {
+ xp = xc; yp = yc;
+ v = vCache[vcIndex];
+ xc = v.x - v0.x;
+ yc = v.y - v0.y;
+ /* Compute (vp - v0) cross (vc - v0) */
+ n0 = 0;
+ n1 = 0;
+ n2 = xp * yc - yp * xc;
+ dot = n0 * nx + n1 * ny + n2 * nz;
+ if (dot != 0)
+ {
+ /* Check the new orientation for consistency with previous triangles */
+ if (dot > 0)
+ {
+ if (sign < 0)
+ {
+ return SIGN_INCONSISTENT;
+ }
+ sign = 1;
+ }
+ else
+ {
+ if (sign > 0)
+ {
+ return SIGN_INCONSISTENT;
+ }
+ sign = -1;
+ }
+ }
+ }
+
+ return sign;
+ }
+
+ /* Takes a single contour and tries to render it
+ * as a triangle fan. This handles convex polygons, as well as some
+ * non-convex polygons if we get lucky.
+ *
+ * Returns TRUE if the polygon was successfully rendered. The rendering
+ * output is provided as callbacks (see the api).
+ */
+ bool RenderCache()
+ {
+ int sign;
+ if (_cacheCount < 3)
+ {
+ /* Degenerate contour -- no output */
+ return true;
+ }
+ double normal_x = 0;
+ double normal_y = 0;
+ double normal_z = 1;
+ sign = this.ComputeNormal(ref normal_x, ref normal_y, ref normal_z);
+ if (sign == SIGN_INCONSISTENT)
+ {
+ // Fan triangles did not have a consistent orientation
+ return false;
+ }
+ if (sign == 0)
+ {
+ // All triangles were degenerate
+ return true;
+ }
+
+ /* Make sure we do the right thing for each winding rule */
+ switch (_windingRule)
+ {
+ case Tesselator.WindingRuleType.Odd:
+ case Tesselator.WindingRuleType.NonZero:
+ break;
+ case Tesselator.WindingRuleType.Positive:
+ if (sign < 0) return true;
+ break;
+ case Tesselator.WindingRuleType.Negative:
+ if (sign > 0) return true;
+ break;
+ case Tesselator.WindingRuleType.ABS_GEQ_Two:
+ return true;
+ }
+
+ this.CallBegin(this.BoundaryOnly ? Tesselator.TriangleListType.LineLoop
+ : (_cacheCount > 3) ? Tesselator.TriangleListType.TriangleFan
+ : Tesselator.TriangleListType.Triangles);
+ this.CallVertex(_indexCached[0]);
+ if (sign > 0)
+ {
+ int c_count = _cacheCount;
+ for (int vcIndex = 1; vcIndex < c_count; ++vcIndex)
+ {
+ this.CallVertex(_indexCached[vcIndex]);
+ }
+ }
+ else
+ {
+ for (int vcIndex = _cacheCount - 1; vcIndex > 0; --vcIndex)
+ {
+ this.CallVertex(_indexCached[vcIndex]);
+ }
+ }
+ this.CallEnd();
+ return true;
+ }
}
+
}
\ No newline at end of file
diff --git a/Demo/Shared/Tesselate/ActiveRegion.cs b/Demo/Shared/Tesselate/ActiveRegion.cs
index f7602bb8..8d7eac01 100644
--- a/Demo/Shared/Tesselate/ActiveRegion.cs
+++ b/Demo/Shared/Tesselate/ActiveRegion.cs
@@ -37,6 +37,8 @@
// C# Port port by: Lars Brubaker
// larsbrubaker@gmail.com
// Copyright (C) 2007
+// 2017, SGI (same license as above), WinterDev
+
**
*/
@@ -46,21 +48,23 @@
* sweep line crosses each vertex, we update the affected regions.
*/
+
+
using System;
namespace Tesselate
{
public class ActiveRegion
{
- public HalfEdge upperHalfEdge; /* upper edge, directed right to left */
- Dictionary.Node upperHalfEdgeDictNode; /* dictionary node corresponding to eUp */
- int windingNumber; /* used to determine which regions are
+ HalfEdge _upperHalfEdge; /* upper edge, directed right to left */
+ Dictionary.Node _upperHalfEdgeDictNode; /* dictionary node corresponding to eUp */
+ int _windingNumber; /* used to determine which regions are
* inside the polygon */
- bool inside; /* is this region inside the polygon? */
- bool sentinel; /* marks fake edges at t = +/-infinity */
- bool dirty; /* marks regions where the upper or lower
+ bool _inside; /* is this region inside the polygon? */
+ bool _sentinel; /* marks fake edges at t = +/-infinity */
+ bool _dirty; /* marks regions where the upper or lower
* edge has changed, but we haven't checked
* whether they intersect yet */
- bool fixUpperEdge; /* marks temporary edges introduced when
+ bool _fixUpperEdge; /* marks temporary edges introduced when
* we process a "right vertex" (one without
* any edges leaving to the right) */
public ActiveRegion()
@@ -93,14 +97,14 @@ public static int ComputeInterior(Tesselator tess)
RemoveDegenerateEdges(tess);
InitPriorityQue(tess);
InitEdgeDict(tess);
- while (!tess.vertexPriorityQue.IsEmpty)
+ while (!tess._vertexPriorityQue.IsEmpty)
{
- vertex = tess.vertexPriorityQue.DeleteMin();
+ vertex = tess._vertexPriorityQue.DeleteMin();
for (; ; )
{
- if (!tess.vertexPriorityQue.IsEmpty)
+ if (!tess._vertexPriorityQue.IsEmpty)
{
- vertexNext = tess.vertexPriorityQue.FindMin(); /* __gl_pqSortMinimum */
+ vertexNext = tess._vertexPriorityQue.FindMin(); /* __gl_pqSortMinimum */
}
else
{
@@ -121,8 +125,8 @@ public static int ComputeInterior(Tesselator tess)
* gap between them. This kind of error is especially obvious
* when using boundary extraction (GLU_TESS_BOUNDARY_ONLY).
*/
- vertexNext = tess.vertexPriorityQue.DeleteMin(); /* __gl_pqSortExtractMin*/
- SpliceMergeVertices(tess, vertex.edgeThisIsOriginOf, vertexNext.edgeThisIsOriginOf);
+ vertexNext = tess._vertexPriorityQue.DeleteMin(); /* __gl_pqSortExtractMin*/
+ SpliceMergeVertices(tess, vertex._edgeThisIsOriginOf, vertexNext._edgeThisIsOriginOf);
}
SweepEvent(tess, vertex);
}
@@ -130,16 +134,16 @@ public static int ComputeInterior(Tesselator tess)
/* Set tess.currentSweepVertex for debugging purposes */
/* __GL_DICTLISTKEY */
/* __GL_DICTLISTMIN */
- tess.currentSweepVertex = tess.edgeDictionary.GetMinNode().Key.upperHalfEdge.originVertex;
+ tess.currentSweepVertex = tess._edgeDictionary.GetMinNode().Key._upperHalfEdge._originVertex;
DoneEdgeDict(tess);
DonePriorityQ(tess);
- if (!RemoveDegenerateFaces(tess.mesh))
+ if (!RemoveDegenerateFaces(tess._mesh))
{
return 0;
}
- tess.mesh.CheckMesh();
+ tess._mesh.CheckMesh();
return 1;
}
@@ -184,8 +188,8 @@ public static int ComputeInterior(Tesselator tess)
static void AddWinding(HalfEdge eDst, HalfEdge eSrc)
{
- eDst.winding += eSrc.winding;
- eDst.otherHalfOfThisEdge.winding += eSrc.otherHalfOfThisEdge.winding;
+ eDst._winding += eSrc._winding;
+ eDst._otherHalfOfThisEdge._winding += eSrc._otherHalfOfThisEdge._winding;
}
public static bool EdgeLeq(Tesselator tess, ActiveRegion reg1, ActiveRegion reg2)
@@ -204,49 +208,49 @@ public static bool EdgeLeq(Tesselator tess, ActiveRegion reg1, ActiveRegion reg2
ContourVertex currentSweepVertex = tess.currentSweepVertex;
HalfEdge e1, e2;
double t1, t2;
- e1 = reg1.upperHalfEdge;
- e2 = reg2.upperHalfEdge;
- if (e1.directionVertex == currentSweepVertex)
+ e1 = reg1._upperHalfEdge;
+ e2 = reg2._upperHalfEdge;
+ if (e1.DirectionVertex == currentSweepVertex)
{
- if (e2.directionVertex == currentSweepVertex)
+ if (e2.DirectionVertex == currentSweepVertex)
{
/* Two edges right of the sweep line which meet at the sweep currentSweepVertex.
* Sort them by slope.
*/
- if (e1.originVertex.VertLeq(e2.originVertex))
+ if (e1._originVertex.VertLeq(e2._originVertex))
{
- return ContourVertex.EdgeSign(e2.directionVertex, e1.originVertex, e2.originVertex) <= 0;
+ return ContourVertex.EdgeSign(e2.DirectionVertex, e1._originVertex, e2._originVertex) <= 0;
}
- return ContourVertex.EdgeSign(e1.directionVertex, e2.originVertex, e1.originVertex) >= 0;
+ return ContourVertex.EdgeSign(e1.DirectionVertex, e2._originVertex, e1._originVertex) >= 0;
}
- return ContourVertex.EdgeSign(e2.directionVertex, currentSweepVertex, e2.originVertex) <= 0;
+ return ContourVertex.EdgeSign(e2.DirectionVertex, currentSweepVertex, e2._originVertex) <= 0;
}
- if (e2.directionVertex == currentSweepVertex)
+ if (e2.DirectionVertex == currentSweepVertex)
{
- return ContourVertex.EdgeSign(e1.directionVertex, currentSweepVertex, e1.originVertex) >= 0;
+ return ContourVertex.EdgeSign(e1.DirectionVertex, currentSweepVertex, e1._originVertex) >= 0;
}
/* General case - compute signed distance *from* e1, e2 to currentSweepVertex */
- t1 = ContourVertex.EdgeEval(e1.directionVertex, currentSweepVertex, e1.originVertex);
- t2 = ContourVertex.EdgeEval(e2.directionVertex, currentSweepVertex, e2.originVertex);
+ t1 = ContourVertex.EdgeEval(e1.DirectionVertex, currentSweepVertex, e1._originVertex);
+ t2 = ContourVertex.EdgeEval(e2.DirectionVertex, currentSweepVertex, e2._originVertex);
return (t1 >= t2);
}
static void DeleteRegion(ActiveRegion reg)
{
- if (reg.fixUpperEdge)
+ if (reg._fixUpperEdge)
{
/* It was created with zero winding number, so it better be
* deleted with zero winding number (ie. it better not get merged
* with a real edge).
*/
- if (reg.upperHalfEdge.winding != 0)
+ if (reg._upperHalfEdge._winding != 0)
{
throw new System.Exception();
}
}
- reg.upperHalfEdge.regionThisIsUpperEdgeOf = null;
- reg.upperHalfEdgeDictNode.Delete();
+ reg._upperHalfEdge._regionThisIsUpperEdgeOf = null;
+ reg._upperHalfEdgeDictNode.Delete();
reg = null;
}
@@ -256,42 +260,42 @@ static bool FixUpperEdge(ActiveRegion reg, HalfEdge newEdge)
* Replace an upper edge which needs fixing (see ConnectRightVertex).
*/
{
- if (!reg.fixUpperEdge)
+ if (!reg._fixUpperEdge)
{
throw new Exception();
}
- Mesh.DeleteHalfEdge(reg.upperHalfEdge);
- reg.fixUpperEdge = false;
- reg.upperHalfEdge = newEdge;
- newEdge.regionThisIsUpperEdgeOf = reg;
+ Mesh.DeleteHalfEdge(reg._upperHalfEdge);
+ reg._fixUpperEdge = false;
+ reg._upperHalfEdge = newEdge;
+ newEdge._regionThisIsUpperEdgeOf = reg;
return true;
}
ActiveRegion RegionAbove()
{
- return this.upperHalfEdgeDictNode.next.Key;
+ return _upperHalfEdgeDictNode.next.Key;
}
static ActiveRegion RegionBelow(ActiveRegion r)
{
- return r.upperHalfEdgeDictNode.prev.Key;
+ return r._upperHalfEdgeDictNode.prev.Key;
}
static ActiveRegion TopLeftRegion(ActiveRegion reg)
{
- ContourVertex org = reg.upperHalfEdge.originVertex;
+ ContourVertex org = reg._upperHalfEdge._originVertex;
HalfEdge e;
/* Find the region above the uppermost edge with the same origin */
do
{
reg = reg.RegionAbove();
- } while (reg.upperHalfEdge.originVertex == org);
+ } while (reg._upperHalfEdge._originVertex == org);
/* If the edge above was a temporary edge introduced by ConnectRightVertex,
* now is the time to fix it.
*/
- if (reg.fixUpperEdge)
+ if (reg._fixUpperEdge)
{
- e = Mesh.meshConnect(RegionBelow(reg).upperHalfEdge.otherHalfOfThisEdge, reg.upperHalfEdge.nextEdgeCCWAroundLeftFace);
+ e = Mesh.meshConnect(RegionBelow(reg)._upperHalfEdge._otherHalfOfThisEdge, reg._upperHalfEdge._nextEdgeCCWAroundLeftFace);
if (e == null)
{
return null;
@@ -307,12 +311,12 @@ static ActiveRegion TopLeftRegion(ActiveRegion reg)
static ActiveRegion TopRightRegion(ActiveRegion reg)
{
- ContourVertex dst = reg.upperHalfEdge.directionVertex;
+ ContourVertex dst = reg._upperHalfEdge.DirectionVertex;
/* Find the region above the uppermost edge with the same destination */
do
{
reg = reg.RegionAbove();
- } while (reg.upperHalfEdge.directionVertex == dst);
+ } while (reg._upperHalfEdge.DirectionVertex == dst);
return reg;
}
@@ -327,20 +331,20 @@ static ActiveRegion AddRegionBelow(Tesselator tess,
*/
{
ActiveRegion regNew = new ActiveRegion();
- regNew.upperHalfEdge = eNewUp;
+ regNew._upperHalfEdge = eNewUp;
/* __gl_dictListInsertBefore */
- regNew.upperHalfEdgeDictNode = tess.edgeDictionary.InsertBefore(regAbove.upperHalfEdgeDictNode, regNew);
- regNew.fixUpperEdge = false;
- regNew.sentinel = false;
- regNew.dirty = false;
- eNewUp.regionThisIsUpperEdgeOf = regNew;
+ regNew._upperHalfEdgeDictNode = tess._edgeDictionary.InsertBefore(regAbove._upperHalfEdgeDictNode, regNew);
+ regNew._fixUpperEdge = false;
+ regNew._sentinel = false;
+ regNew._dirty = false;
+ eNewUp._regionThisIsUpperEdgeOf = regNew;
return regNew;
}
static void ComputeWinding(Tesselator tess, ActiveRegion reg)
{
- reg.windingNumber = reg.RegionAbove().windingNumber + reg.upperHalfEdge.winding;
- reg.inside = tess.IsWindingInside(reg.windingNumber);
+ reg._windingNumber = reg.RegionAbove()._windingNumber + reg._upperHalfEdge._winding;
+ reg._inside = tess.IsWindingInside(reg._windingNumber);
}
@@ -353,10 +357,10 @@ static void FinishRegion(Tesselator tess, ActiveRegion reg)
* changing, this face may not have even existed until now).
*/
{
- HalfEdge e = reg.upperHalfEdge;
- Face f = e.leftFace;
- f.isInterior = reg.inside;
- f.halfEdgeThisIsLeftFaceOf = e; // optimization for mesh.TessellateMonoRegion()
+ HalfEdge e = reg._upperHalfEdge;
+ Face f = e._leftFace;
+ f._isInterior = reg._inside;
+ f._halfEdgeThisIsLeftFaceOf = e; // optimization for mesh.TessellateMonoRegion()
DeleteRegion(reg);
}
@@ -379,15 +383,15 @@ static HalfEdge FinishLeftRegions(Tesselator tess,
ActiveRegion reg, regPrev;
HalfEdge e, ePrev;
regPrev = regFirst;
- ePrev = regFirst.upperHalfEdge;
+ ePrev = regFirst._upperHalfEdge;
while (regPrev != regLast)
{
- regPrev.fixUpperEdge = false; /* placement was OK */
+ regPrev._fixUpperEdge = false; /* placement was OK */
reg = RegionBelow(regPrev);
- e = reg.upperHalfEdge;
- if (e.originVertex != ePrev.originVertex)
+ e = reg._upperHalfEdge;
+ if (e._originVertex != ePrev._originVertex)
{
- if (!reg.fixUpperEdge)
+ if (!reg._fixUpperEdge)
{
/* Remove the last left-going edge. Even though there are no further
* edges in the dictionary with this origin, there may be further
@@ -401,18 +405,18 @@ static HalfEdge FinishLeftRegions(Tesselator tess,
/* If the edge below was a temporary edge introduced by
* ConnectRightVertex, now is the time to fix it.
*/
- e = Mesh.meshConnect(ePrev.Lprev, e.otherHalfOfThisEdge);
+ e = Mesh.meshConnect(ePrev.Lprev, e._otherHalfOfThisEdge);
FixUpperEdge(reg, e);
}
/* Relink edges so that ePrev.Onext == e */
- if (ePrev.nextEdgeCCWAroundOrigin != e)
+ if (ePrev._nextEdgeCCWAroundOrigin != e)
{
Mesh.meshSplice(e.Oprev, e);
Mesh.meshSplice(ePrev, e);
}
FinishRegion(tess, regPrev); /* may change reg.eUp */
- ePrev = reg.upperHalfEdge;
+ ePrev = reg._upperHalfEdge;
regPrev = reg;
}
return ePrev;
@@ -440,41 +444,43 @@ static void AddRightEdges(Tesselator tess, ActiveRegion regUp,
e = eFirst;
do
{
- if (!e.originVertex.VertLeq(e.directionVertex))
+ if (!e._originVertex.VertLeq(e.DirectionVertex))
{
throw new Exception();
}
- AddRegionBelow(tess, regUp, e.otherHalfOfThisEdge);
- e = e.nextEdgeCCWAroundOrigin;
+ AddRegionBelow(tess, regUp, e._otherHalfOfThisEdge);
+ e = e._nextEdgeCCWAroundOrigin;
} while (e != eLast);
/* Walk *all* right-going edges from e.Org, in the dictionary order,
- * updating the winding numbers of each region, and re-linking the mesh
+ * updating the winding numbers of ea
+ *
+ * ch region, and re-linking the mesh
* edges to match the dictionary ordering (if necessary).
*/
if (eTopLeft == null)
{
- eTopLeft = RegionBelow(regUp).upperHalfEdge.Rprev;
+ eTopLeft = RegionBelow(regUp)._upperHalfEdge.Rprev;
}
regPrev = regUp;
ePrev = eTopLeft;
for (; ; )
{
reg = RegionBelow(regPrev);
- e = reg.upperHalfEdge.otherHalfOfThisEdge;
- if (e.originVertex != ePrev.originVertex) break;
- if (e.nextEdgeCCWAroundOrigin != ePrev)
+ e = reg._upperHalfEdge._otherHalfOfThisEdge;
+ if (e._originVertex != ePrev._originVertex) break;
+ if (e._nextEdgeCCWAroundOrigin != ePrev)
{
/* Unlink e from its current position, and relink below ePrev */
Mesh.meshSplice(e.Oprev, e);
Mesh.meshSplice(ePrev.Oprev, e);
}
/* Compute the winding number and "inside" flag for the new regions */
- reg.windingNumber = regPrev.windingNumber - e.winding;
- reg.inside = tess.IsWindingInside(reg.windingNumber);
+ reg._windingNumber = regPrev._windingNumber - e._winding;
+ reg._inside = tess.IsWindingInside(reg._windingNumber);
/* Check for two outgoing edges with same slope -- process these
* before any intersection tests (see example in __gl_computeInterior).
*/
- regPrev.dirty = true;
+ regPrev._dirty = true;
if (!firstTime && CheckForRightSplice(tess, regPrev))
{
AddWinding(e, ePrev);
@@ -485,8 +491,8 @@ static void AddRightEdges(Tesselator tess, ActiveRegion regUp,
regPrev = reg;
ePrev = e;
}
- regPrev.dirty = true;
- if (regPrev.windingNumber - e.winding != reg.windingNumber)
+ regPrev._dirty = true;
+ if (regPrev._windingNumber - e._winding != reg._windingNumber)
{
throw new Exception();
}
@@ -502,16 +508,17 @@ static void AddRightEdges(Tesselator tess, ActiveRegion regUp,
static void CallCombine(Tesselator tess, ContourVertex intersectionVertex, ref Tesselator.CombineParameters combinePars, bool needed)
{
/* Copy coord data in case the callback changes it. */
- double c0 = intersectionVertex.C_0;
- double c1 = intersectionVertex.C_1;
- double c2 = intersectionVertex.C_2;
- intersectionVertex.clientIndex = 0;
- tess.CallCombine(c0, c1, c2, ref combinePars, out intersectionVertex.clientIndex);
- if (intersectionVertex.clientIndex == 0)
+ double c0 = intersectionVertex._C_0;
+ double c1 = intersectionVertex._C_1;
+ double c2 = intersectionVertex._C_2;
+ intersectionVertex._clientIndex = 0;
+
+ tess.CallCombine(c0, c1, c2, ref combinePars, out intersectionVertex._clientIndex);
+ if (intersectionVertex._clientIndex == 0)
{
if (!needed)
{
- intersectionVertex.clientIndex = combinePars.d0;
+ intersectionVertex._clientIndex = combinePars.d0;
}
else
{
@@ -530,12 +537,17 @@ static void SpliceMergeVertices(Tesselator tess, HalfEdge e1, HalfEdge e2)
* e1.Org is kept, while e2.Org is discarded.
*/
{
+ //int[] data4 = new int[4];
+ //double[] weights4 = new double[] { 0.5f, 0.5f, 0, 0 };
+ //data4[0] = e1.originVertex.clientIndex;
+ //data4[1] = e2.originVertex.clientIndex;
+
var combinePars = new Tesselator.CombineParameters();
combinePars.w0 = 0.5f; combinePars.w1 = 0.5f;
- combinePars.d0 = e1.originVertex.clientIndex;
- combinePars.d1 = e2.originVertex.clientIndex;
+ combinePars.d0 = e1._originVertex._clientIndex;
+ combinePars.d1 = e2._originVertex._clientIndex;
- CallCombine(tess, e1.originVertex, ref combinePars, false);
+ CallCombine(tess, e1._originVertex, ref combinePars, false);
Mesh.meshSplice(e1, e2);
}
@@ -558,9 +570,9 @@ static void VertexWeights(ContourVertex isect, ContourVertex org, ContourVertex
double t2 = VertL1dist(dst, isect);
weights0 = 0.5 * t2 / (t1 + t2);
weights1 = 0.5 * t1 / (t1 + t2);
- isect.C_0 += weights0 * org.C_0 + weights1 * dst.C_0;
- isect.C_1 += weights0 * org.C_1 + weights1 * dst.C_1;
- isect.C_2 += weights0 * org.C_2 + weights1 * dst.C_2;
+ isect._C_0 += weights0 * org._C_0 + weights1 * dst._C_0;
+ isect._C_1 += weights0 * org._C_1 + weights1 * dst._C_1;
+ isect._C_2 += weights0 * org._C_2 + weights1 * dst._C_2;
}
@@ -573,14 +585,20 @@ static void GetIntersectData(Tesselator tess, ContourVertex isect,
* rendering callbacks.
*/
{
+ //int[] data4 = new int[4];
+ //double[] weights4 = new double[4];
+ //data4[0] = orgUp.clientIndex;
+ //data4[1] = dstUp.clientIndex;
+ //data4[2] = orgLo.clientIndex;
+ //data4[3] = dstLo.clientIndex;
var combinePars = new Tesselator.CombineParameters();
- combinePars.d0 = orgUp.clientIndex;
- combinePars.d1 = dstUp.clientIndex;
- combinePars.d2 = orgLo.clientIndex;
- combinePars.d3 = dstLo.clientIndex;
+ combinePars.d0 = orgUp._clientIndex;
+ combinePars.d1 = dstUp._clientIndex;
+ combinePars.d2 = orgLo._clientIndex;
+ combinePars.d3 = dstLo._clientIndex;
- isect.C_0 = isect.C_1 = isect.C_2 = 0;
+ isect._C_0 = isect._C_1 = isect._C_2 = 0;
VertexWeights(isect, orgUp, dstUp, out combinePars.w0, out combinePars.w1);
VertexWeights(isect, orgLo, dstLo, out combinePars.w2, out combinePars.w3);
CallCombine(tess, isect, ref combinePars, true);
@@ -614,41 +632,41 @@ static bool CheckForRightSplice(Tesselator tess, ActiveRegion regUp)
*/
{
ActiveRegion regLo = RegionBelow(regUp);
- HalfEdge eUp = regUp.upperHalfEdge;
- HalfEdge eLo = regLo.upperHalfEdge;
- if (eUp.originVertex.VertLeq(eLo.originVertex))
+ HalfEdge eUp = regUp._upperHalfEdge;
+ HalfEdge eLo = regLo._upperHalfEdge;
+ if (eUp._originVertex.VertLeq(eLo._originVertex))
{
- if (ContourVertex.EdgeSign(eLo.directionVertex, eUp.originVertex, eLo.originVertex) > 0)
+ if (ContourVertex.EdgeSign(eLo.DirectionVertex, eUp._originVertex, eLo._originVertex) > 0)
{
return false;
}
/* eUp.Org appears to be below eLo */
- if (!eUp.originVertex.VertEq(eLo.originVertex))
+ if (!eUp._originVertex.VertEq(eLo._originVertex))
{
/* Splice eUp.Org into eLo */
- Mesh.meshSplitEdge(eLo.otherHalfOfThisEdge);
+ Mesh.meshSplitEdge(eLo._otherHalfOfThisEdge);
Mesh.meshSplice(eUp, eLo.Oprev);
- regUp.dirty = regLo.dirty = true;
+ regUp._dirty = regLo._dirty = true;
}
- else if (eUp.originVertex != eLo.originVertex)
+ else if (eUp._originVertex != eLo._originVertex)
{
/* merge the two vertices, discarding eUp.Org */
- tess.vertexPriorityQue.Delete(eUp.originVertex.priorityQueueHandle);
+ tess._vertexPriorityQue.Delete(eUp._originVertex._priorityQueueHandle);
//pqDelete(tess.pq, eUp.Org.pqHandle); /* __gl_pqSortDelete */
SpliceMergeVertices(tess, eLo.Oprev, eUp);
}
}
else
{
- if (ContourVertex.EdgeSign(eUp.directionVertex, eLo.originVertex, eUp.originVertex) < 0)
+ if (ContourVertex.EdgeSign(eUp.DirectionVertex, eLo._originVertex, eUp._originVertex) < 0)
{
return false;
}
/* eLo.Org appears to be above eUp, so splice eLo.Org into eUp */
- regUp.RegionAbove().dirty = regUp.dirty = true;
- Mesh.meshSplitEdge(eUp.otherHalfOfThisEdge);
+ regUp.RegionAbove()._dirty = regUp._dirty = true;
+ Mesh.meshSplitEdge(eUp._otherHalfOfThisEdge);
Mesh.meshSplice(eLo.Oprev, eUp);
}
return true;
@@ -675,35 +693,35 @@ static bool CheckForLeftSplice(Tesselator tess, ActiveRegion regUp)
*/
{
ActiveRegion regLo = RegionBelow(regUp);
- HalfEdge eUp = regUp.upperHalfEdge;
- HalfEdge eLo = regLo.upperHalfEdge;
+ HalfEdge eUp = regUp._upperHalfEdge;
+ HalfEdge eLo = regLo._upperHalfEdge;
HalfEdge e;
- if (eUp.directionVertex.VertEq(eLo.directionVertex))
+ if (eUp.DirectionVertex.VertEq(eLo.DirectionVertex))
{
throw new Exception();
}
- if (eUp.directionVertex.VertLeq(eLo.directionVertex))
+ if (eUp.DirectionVertex.VertLeq(eLo.DirectionVertex))
{
- if (ContourVertex.EdgeSign(eUp.directionVertex, eLo.directionVertex, eUp.originVertex) < 0)
+ if (ContourVertex.EdgeSign(eUp.DirectionVertex, eLo.DirectionVertex, eUp._originVertex) < 0)
{
return false;
}
/* eLo.Dst is above eUp, so splice eLo.Dst into eUp */
- regUp.RegionAbove().dirty = regUp.dirty = true;
+ regUp.RegionAbove()._dirty = regUp._dirty = true;
e = Mesh.meshSplitEdge(eUp);
- Mesh.meshSplice(eLo.otherHalfOfThisEdge, e);
- e.leftFace.isInterior = regUp.inside;
+ Mesh.meshSplice(eLo._otherHalfOfThisEdge, e);
+ e._leftFace._isInterior = regUp._inside;
}
else
{
- if (ContourVertex.EdgeSign(eLo.directionVertex, eUp.directionVertex, eLo.originVertex) > 0) return false;
+ if (ContourVertex.EdgeSign(eLo.DirectionVertex, eUp.DirectionVertex, eLo._originVertex) > 0) return false;
/* eUp.Dst is below eLo, so splice eUp.Dst into eLo */
- regUp.dirty = regLo.dirty = true;
+ regUp._dirty = regLo._dirty = true;
e = Mesh.meshSplitEdge(eLo);
- Mesh.meshSplice(eUp.nextEdgeCCWAroundLeftFace, eLo.otherHalfOfThisEdge);
- e.rightFace.isInterior = regUp.inside;
+ Mesh.meshSplice(eUp._nextEdgeCCWAroundLeftFace, eLo._otherHalfOfThisEdge);
+ e.rightFace._isInterior = regUp._inside;
}
return true;
}
@@ -882,12 +900,12 @@ static bool CheckForIntersect(Tesselator tess, ActiveRegion regUp)
*/
{
ActiveRegion regLo = RegionBelow(regUp);
- HalfEdge eUp = regUp.upperHalfEdge;
- HalfEdge eLo = regLo.upperHalfEdge;
- ContourVertex orgUp = eUp.originVertex;
- ContourVertex orgLo = eLo.originVertex;
- ContourVertex dstUp = eUp.directionVertex;
- ContourVertex dstLo = eLo.directionVertex;
+ HalfEdge eUp = regUp._upperHalfEdge;
+ HalfEdge eLo = regLo._upperHalfEdge;
+ ContourVertex orgUp = eUp._originVertex;
+ ContourVertex orgLo = eLo._originVertex;
+ ContourVertex dstUp = eUp.DirectionVertex;
+ ContourVertex dstLo = eLo.DirectionVertex;
double tMinUp, tMaxLo;
ContourVertex isect = new ContourVertex();
ContourVertex orgMin;
@@ -908,7 +926,7 @@ static bool CheckForIntersect(Tesselator tess, ActiveRegion regUp)
{
throw new Exception();
}
- if (regUp.fixUpperEdge || regLo.fixUpperEdge)
+ if (regUp._fixUpperEdge || regLo._fixUpperEdge)
{
throw new Exception();
}
@@ -1002,10 +1020,10 @@ static bool CheckForIntersect(Tesselator tess, ActiveRegion regUp)
if (dstLo == tess.currentSweepVertex)
{
/* Splice dstLo into eUp, and process the new region(s) */
- Mesh.meshSplitEdge(eUp.otherHalfOfThisEdge);
- Mesh.meshSplice(eLo.otherHalfOfThisEdge, eUp);
+ Mesh.meshSplitEdge(eUp._otherHalfOfThisEdge);
+ Mesh.meshSplice(eLo._otherHalfOfThisEdge, eUp);
regUp = TopLeftRegion(regUp);
- eUp = RegionBelow(regUp).upperHalfEdge;
+ eUp = RegionBelow(regUp)._upperHalfEdge;
FinishLeftRegions(tess, RegionBelow(regUp), regLo);
AddRightEdges(tess, regUp, eUp.Oprev, eUp, eUp, true);
return true;
@@ -1013,14 +1031,14 @@ static bool CheckForIntersect(Tesselator tess, ActiveRegion regUp)
if (dstUp == tess.currentSweepVertex)
{
/* Splice dstUp into eLo, and process the new region(s) */
- Mesh.meshSplitEdge(eLo.otherHalfOfThisEdge);
- Mesh.meshSplice(eUp.nextEdgeCCWAroundLeftFace, eLo.Oprev);
+ Mesh.meshSplitEdge(eLo._otherHalfOfThisEdge);
+ Mesh.meshSplice(eUp._nextEdgeCCWAroundLeftFace, eLo.Oprev);
regLo = regUp;
regUp = TopRightRegion(regUp);
- e = RegionBelow(regUp).upperHalfEdge.Rprev;
- regLo.upperHalfEdge = eLo.Oprev;
+ e = RegionBelow(regUp)._upperHalfEdge.Rprev;
+ regLo._upperHalfEdge = eLo.Oprev;
eLo = FinishLeftRegions(tess, regLo, null);
- AddRightEdges(tess, regUp, eLo.nextEdgeCCWAroundOrigin, eUp.Rprev, e, true);
+ AddRightEdges(tess, regUp, eLo._nextEdgeCCWAroundOrigin, eUp.Rprev, e, true);
return true;
}
@@ -1030,17 +1048,17 @@ static bool CheckForIntersect(Tesselator tess, ActiveRegion regUp)
*/
if (ContourVertex.EdgeSign(dstUp, tess.currentSweepVertex, isect) >= 0)
{
- regUp.RegionAbove().dirty = regUp.dirty = true;
- Mesh.meshSplitEdge(eUp.otherHalfOfThisEdge);
- eUp.originVertex.x = tess.currentSweepVertex.x;
- eUp.originVertex.y = tess.currentSweepVertex.y;
+ regUp.RegionAbove()._dirty = regUp._dirty = true;
+ Mesh.meshSplitEdge(eUp._otherHalfOfThisEdge);
+ eUp._originVertex.x = tess.currentSweepVertex.x;
+ eUp._originVertex.y = tess.currentSweepVertex.y;
}
if (ContourVertex.EdgeSign(dstLo, tess.currentSweepVertex, isect) <= 0)
{
- regUp.dirty = regLo.dirty = true;
- Mesh.meshSplitEdge(eLo.otherHalfOfThisEdge);
- eLo.originVertex.x = tess.currentSweepVertex.x;
- eLo.originVertex.y = tess.currentSweepVertex.y;
+ regUp._dirty = regLo._dirty = true;
+ Mesh.meshSplitEdge(eLo._otherHalfOfThisEdge);
+ eLo._originVertex.x = tess.currentSweepVertex.x;
+ eLo._originVertex.y = tess.currentSweepVertex.y;
}
/* leave the rest for ConnectRightVertex */
return false;
@@ -1054,14 +1072,14 @@ static bool CheckForIntersect(Tesselator tess, ActiveRegion regUp)
* the mesh (ie. eUp.Lface) to be smaller than the faces in the
* unprocessed original contours (which will be eLo.Oprev.Lface).
*/
- Mesh.meshSplitEdge(eUp.otherHalfOfThisEdge);
- Mesh.meshSplitEdge(eLo.otherHalfOfThisEdge);
+ Mesh.meshSplitEdge(eUp._otherHalfOfThisEdge);
+ Mesh.meshSplitEdge(eLo._otherHalfOfThisEdge);
Mesh.meshSplice(eLo.Oprev, eUp);
- eUp.originVertex.x = isect.x;
- eUp.originVertex.y = isect.y;
- tess.vertexPriorityQue.Add(out eUp.originVertex.priorityQueueHandle, eUp.originVertex); /* __gl_pqSortInsert */
- GetIntersectData(tess, eUp.originVertex, orgUp, dstUp, orgLo, dstLo);
- regUp.RegionAbove().dirty = regUp.dirty = regLo.dirty = true;
+ eUp._originVertex.x = isect.x;
+ eUp._originVertex.y = isect.y;
+ tess._vertexPriorityQue.Add(out eUp._originVertex._priorityQueueHandle, eUp._originVertex); /* __gl_pqSortInsert */
+ GetIntersectData(tess, eUp._originVertex, orgUp, dstUp, orgLo, dstLo);
+ regUp.RegionAbove()._dirty = regUp._dirty = regLo._dirty = true;
return false;
}
@@ -1080,25 +1098,25 @@ static void WalkDirtyRegions(Tesselator tess, ActiveRegion regUp)
for (; ; )
{
/* Find the lowest dirty region (we walk from the bottom up). */
- while (regLo.dirty)
+ while (regLo._dirty)
{
regUp = regLo;
regLo = RegionBelow(regLo);
}
- if (!regUp.dirty)
+ if (!regUp._dirty)
{
regLo = regUp;
regUp = regUp.RegionAbove();
- if (regUp == null || !regUp.dirty)
+ if (regUp == null || !regUp._dirty)
{
/* We've walked all the dirty regions */
return;
}
}
- regUp.dirty = false;
- eUp = regUp.upperHalfEdge;
- eLo = regLo.upperHalfEdge;
- if (eUp.directionVertex != eLo.directionVertex)
+ regUp._dirty = false;
+ eUp = regUp._upperHalfEdge;
+ eLo = regLo._upperHalfEdge;
+ if (eUp.DirectionVertex != eLo.DirectionVertex)
{
/* Check that the edge ordering is obeyed at the Dst vertices. */
if (CheckForLeftSplice(tess, regUp))
@@ -1107,27 +1125,27 @@ static void WalkDirtyRegions(Tesselator tess, ActiveRegion regUp)
* we no longer need it (since these edges are needed only for
* vertices which otherwise have no right-going edges).
*/
- if (regLo.fixUpperEdge)
+ if (regLo._fixUpperEdge)
{
DeleteRegion(regLo);
Mesh.DeleteHalfEdge(eLo);
regLo = RegionBelow(regUp);
- eLo = regLo.upperHalfEdge;
+ eLo = regLo._upperHalfEdge;
}
- else if (regUp.fixUpperEdge)
+ else if (regUp._fixUpperEdge)
{
DeleteRegion(regUp);
Mesh.DeleteHalfEdge(eUp);
regUp = regLo.RegionAbove();
- eUp = regUp.upperHalfEdge;
+ eUp = regUp._upperHalfEdge;
}
}
}
- if (eUp.originVertex != eLo.originVertex)
+ if (eUp._originVertex != eLo._originVertex)
{
- if (eUp.directionVertex != eLo.directionVertex
- && !regUp.fixUpperEdge && !regLo.fixUpperEdge
- && (eUp.directionVertex == tess.currentSweepVertex || eLo.directionVertex == tess.currentSweepVertex))
+ if (eUp.DirectionVertex != eLo.DirectionVertex
+ && !regUp._fixUpperEdge && !regLo._fixUpperEdge
+ && (eUp.DirectionVertex == tess.currentSweepVertex || eLo.DirectionVertex == tess.currentSweepVertex))
{
/* When all else fails in CheckForIntersect(), it uses tess.currentSweepVertex
* as the intersection location. To make this possible, it requires
@@ -1151,7 +1169,7 @@ static void WalkDirtyRegions(Tesselator tess, ActiveRegion regUp)
CheckForRightSplice(tess, regUp);
}
}
- if (eUp.originVertex == eLo.originVertex && eUp.directionVertex == eLo.directionVertex)
+ if (eUp._originVertex == eLo._originVertex && eUp.DirectionVertex == eLo.DirectionVertex)
{
/* A degenerate loop consisting of only two edges -- delete it. */
AddWinding(eLo, eUp);
@@ -1197,12 +1215,12 @@ static void ConnectRightVertex(Tesselator tess, ActiveRegion regUp, HalfEdge eBo
*/
{
HalfEdge eNew;
- HalfEdge eTopLeft = eBottomLeft.nextEdgeCCWAroundOrigin;
+ HalfEdge eTopLeft = eBottomLeft._nextEdgeCCWAroundOrigin;
ActiveRegion regLo = RegionBelow(regUp);
- HalfEdge eUp = regUp.upperHalfEdge;
- HalfEdge eLo = regLo.upperHalfEdge;
+ HalfEdge eUp = regUp._upperHalfEdge;
+ HalfEdge eLo = regLo._upperHalfEdge;
bool degenerate = false;
- if (eUp.directionVertex != eLo.directionVertex)
+ if (eUp.DirectionVertex != eLo.DirectionVertex)
{
CheckForIntersect(tess, regUp);
}
@@ -1210,15 +1228,15 @@ static void ConnectRightVertex(Tesselator tess, ActiveRegion regUp, HalfEdge eBo
/* Possible new degeneracies: upper or lower edge of regUp may pass
* through vEvent, or may coincide with new intersection vertex
*/
- if (eUp.originVertex.VertEq(tess.currentSweepVertex))
+ if (eUp._originVertex.VertEq(tess.currentSweepVertex))
{
Mesh.meshSplice(eTopLeft.Oprev, eUp);
regUp = TopLeftRegion(regUp);
- eTopLeft = RegionBelow(regUp).upperHalfEdge;
+ eTopLeft = RegionBelow(regUp)._upperHalfEdge;
FinishLeftRegions(tess, RegionBelow(regUp), regLo);
degenerate = true;
}
- if (eLo.originVertex.VertEq(tess.currentSweepVertex))
+ if (eLo._originVertex.VertEq(tess.currentSweepVertex))
{
Mesh.meshSplice(eBottomLeft, eLo.Oprev);
eBottomLeft = FinishLeftRegions(tess, regLo, null);
@@ -1226,14 +1244,14 @@ static void ConnectRightVertex(Tesselator tess, ActiveRegion regUp, HalfEdge eBo
}
if (degenerate)
{
- AddRightEdges(tess, regUp, eBottomLeft.nextEdgeCCWAroundOrigin, eTopLeft, eTopLeft, true);
+ AddRightEdges(tess, regUp, eBottomLeft._nextEdgeCCWAroundOrigin, eTopLeft, eTopLeft, true);
return;
}
/* Non-degenerate situation -- need to add a temporary, fixable edge.
* Connect to the closer of eLo.Org, eUp.Org.
*/
- if (eLo.originVertex.VertLeq(eUp.originVertex))
+ if (eLo._originVertex.VertLeq(eUp._originVertex))
{
eNew = eLo.Oprev;
}
@@ -1245,8 +1263,8 @@ static void ConnectRightVertex(Tesselator tess, ActiveRegion regUp, HalfEdge eBo
/* Prevent cleanup, otherwise eNew might disappear before we've even
* had a chance to mark it as a temporary edge.
*/
- AddRightEdges(tess, regUp, eNew, eNew.nextEdgeCCWAroundOrigin, eNew.nextEdgeCCWAroundOrigin, false);
- eNew.otherHalfOfThisEdge.regionThisIsUpperEdgeOf.fixUpperEdge = true;
+ AddRightEdges(tess, regUp, eNew, eNew._nextEdgeCCWAroundOrigin, eNew._nextEdgeCCWAroundOrigin, false);
+ eNew._otherHalfOfThisEdge._regionThisIsUpperEdgeOf._fixUpperEdge = true;
WalkDirtyRegions(tess, regUp);
}
@@ -1259,27 +1277,27 @@ static void ConnectLeftDegenerate(Tesselator tess, ActiveRegion regUp, ContourVe
{
HalfEdge e, eTopLeft, eTopRight, eLast;
ActiveRegion reg;
- e = regUp.upperHalfEdge;
- if (e.originVertex.VertEq(vEvent))
+ e = regUp._upperHalfEdge;
+ if (e._originVertex.VertEq(vEvent))
{
/* e.Org is an unprocessed vertex - just combine them, and wait
* for e.Org to be pulled from the queue
*/
- SpliceMergeVertices(tess, e, vEvent.edgeThisIsOriginOf);
+ SpliceMergeVertices(tess, e, vEvent._edgeThisIsOriginOf);
return;
}
- if (!e.directionVertex.VertEq(vEvent))
+ if (!e.DirectionVertex.VertEq(vEvent))
{
/* General case -- splice vEvent into edge e which passes through it */
- Mesh.meshSplitEdge(e.otherHalfOfThisEdge);
- if (regUp.fixUpperEdge)
+ Mesh.meshSplitEdge(e._otherHalfOfThisEdge);
+ if (regUp._fixUpperEdge)
{
/* This edge was fixable -- delete unused portion of original edge */
- Mesh.DeleteHalfEdge(e.nextEdgeCCWAroundOrigin);
- regUp.fixUpperEdge = false;
+ Mesh.DeleteHalfEdge(e._nextEdgeCCWAroundOrigin);
+ regUp._fixUpperEdge = false;
}
- Mesh.meshSplice(vEvent.edgeThisIsOriginOf, e);
+ Mesh.meshSplice(vEvent._edgeThisIsOriginOf, e);
SweepEvent(tess, vEvent); /* recurse */
return;
}
@@ -1289,9 +1307,9 @@ static void ConnectLeftDegenerate(Tesselator tess, ActiveRegion regUp, ContourVe
*/
regUp = TopRightRegion(regUp);
reg = RegionBelow(regUp);
- eTopRight = reg.upperHalfEdge.otherHalfOfThisEdge;
- eTopLeft = eLast = eTopRight.nextEdgeCCWAroundOrigin;
- if (reg.fixUpperEdge)
+ eTopRight = reg._upperHalfEdge._otherHalfOfThisEdge;
+ eTopLeft = eLast = eTopRight._nextEdgeCCWAroundOrigin;
+ if (reg._fixUpperEdge)
{
/* Here e.Dst has only a single fixable edge going right.
* We can delete it since now we have some real right-going edges.
@@ -1304,13 +1322,13 @@ static void ConnectLeftDegenerate(Tesselator tess, ActiveRegion regUp, ContourVe
Mesh.DeleteHalfEdge(eTopRight);
eTopRight = eTopLeft.Oprev;
}
- Mesh.meshSplice(vEvent.edgeThisIsOriginOf, eTopRight);
+ Mesh.meshSplice(vEvent._edgeThisIsOriginOf, eTopRight);
if (!eTopLeft.EdgeGoesLeft())
{
/* e.Dst had no left-going edges -- indicate this to AddRightEdges() */
eTopLeft = null;
}
- AddRightEdges(tess, regUp, eTopRight.nextEdgeCCWAroundOrigin, eLast, eTopLeft, true);
+ AddRightEdges(tess, regUp, eTopRight._nextEdgeCCWAroundOrigin, eLast, eTopLeft, true);
}
static void ConnectLeftVertex(Tesselator tess, ContourVertex vEvent)
@@ -1336,15 +1354,15 @@ static void ConnectLeftVertex(Tesselator tess, ContourVertex vEvent)
/* assert( vEvent.anEdge.Onext.Onext == vEvent.anEdge ); */
/* Get a pointer to the active region containing vEvent */
- tmp.upperHalfEdge = vEvent.edgeThisIsOriginOf.otherHalfOfThisEdge;
+ tmp._upperHalfEdge = vEvent._edgeThisIsOriginOf._otherHalfOfThisEdge;
/* __GL_DICTLISTKEY */
/* __gl_dictListSearch */
- regUp = Dictionary.dictSearch(tess.edgeDictionary, tmp).Key;
+ regUp = Dictionary.dictSearch(tess._edgeDictionary, tmp).Key;
regLo = RegionBelow(regUp);
- eUp = regUp.upperHalfEdge;
- eLo = regLo.upperHalfEdge;
+ eUp = regUp._upperHalfEdge;
+ eLo = regLo._upperHalfEdge;
/* Try merging with U or L first */
- if (ContourVertex.EdgeSign(eUp.directionVertex, vEvent, eUp.originVertex) == 0)
+ if (ContourVertex.EdgeSign(eUp.DirectionVertex, vEvent, eUp._originVertex) == 0)
{
ConnectLeftDegenerate(tess, regUp, vEvent);
return;
@@ -1353,19 +1371,19 @@ static void ConnectLeftVertex(Tesselator tess, ContourVertex vEvent)
/* Connect vEvent to rightmost processed vertex of either chain.
* e.Dst is the vertex that we will connect to vEvent.
*/
- reg = eLo.directionVertex.VertLeq(eUp.directionVertex) ? regUp : regLo;
- if (regUp.inside || reg.fixUpperEdge)
+ reg = eLo.DirectionVertex.VertLeq(eUp.DirectionVertex) ? regUp : regLo;
+ if (regUp._inside || reg._fixUpperEdge)
{
if (reg == regUp)
{
- eNew = Mesh.meshConnect(vEvent.edgeThisIsOriginOf.otherHalfOfThisEdge, eUp.nextEdgeCCWAroundLeftFace);
+ eNew = Mesh.meshConnect(vEvent._edgeThisIsOriginOf._otherHalfOfThisEdge, eUp._nextEdgeCCWAroundLeftFace);
}
else
{
- HalfEdge tempHalfEdge = Mesh.meshConnect(eLo.Dnext, vEvent.edgeThisIsOriginOf);
- eNew = tempHalfEdge.otherHalfOfThisEdge;
+ HalfEdge tempHalfEdge = Mesh.meshConnect(eLo.Dnext, vEvent._edgeThisIsOriginOf);
+ eNew = tempHalfEdge._otherHalfOfThisEdge;
}
- if (reg.fixUpperEdge)
+ if (reg._fixUpperEdge)
{
FixUpperEdge(reg, eNew);
}
@@ -1380,7 +1398,7 @@ static void ConnectLeftVertex(Tesselator tess, ContourVertex vEvent)
/* The new vertex is in a region which does not belong to the polygon.
* We don''t need to connect this vertex to the rest of the mesh.
*/
- AddRightEdges(tess, regUp, vEvent.edgeThisIsOriginOf, vEvent.edgeThisIsOriginOf, null, true);
+ AddRightEdges(tess, regUp, vEvent._edgeThisIsOriginOf, vEvent._edgeThisIsOriginOf, null, true);
}
}
@@ -1398,11 +1416,11 @@ static void SweepEvent(Tesselator tess, ContourVertex vEvent)
* already in the dictionary. In this case we don't need to waste
* time searching for the location to insert new edges.
*/
- e = vEvent.edgeThisIsOriginOf;
- while (e.regionThisIsUpperEdgeOf == null)
+ e = vEvent._edgeThisIsOriginOf;
+ while (e._regionThisIsUpperEdgeOf == null)
{
- e = e.nextEdgeCCWAroundOrigin;
- if (e == vEvent.edgeThisIsOriginOf)
+ e = e._nextEdgeCCWAroundOrigin;
+ if (e == vEvent._edgeThisIsOriginOf)
{
/* All edges go right -- not incident to any processed edges */
ConnectLeftVertex(tess, vEvent);
@@ -1417,23 +1435,23 @@ static void SweepEvent(Tesselator tess, ContourVertex vEvent)
* to their winding number, and delete the edges from the dictionary.
* This takes care of all the left-going edges from vEvent.
*/
- regUp = TopLeftRegion(e.regionThisIsUpperEdgeOf);
+ regUp = TopLeftRegion(e._regionThisIsUpperEdgeOf);
reg = RegionBelow(regUp);
- eTopLeft = reg.upperHalfEdge;
+ eTopLeft = reg._upperHalfEdge;
eBottomLeft = FinishLeftRegions(tess, reg, null);
/* Next we process all the right-going edges from vEvent. This
* involves adding the edges to the dictionary, and creating the
* associated "active regions" which record information about the
* regions between adjacent dictionary edges.
*/
- if (eBottomLeft.nextEdgeCCWAroundOrigin == eTopLeft)
+ if (eBottomLeft._nextEdgeCCWAroundOrigin == eTopLeft)
{
/* No right-going edges -- add a temporary "fixable" edge */
ConnectRightVertex(tess, regUp, eBottomLeft);
}
else
{
- AddRightEdges(tess, regUp, eBottomLeft.nextEdgeCCWAroundOrigin, eTopLeft, eTopLeft, true);
+ AddRightEdges(tess, regUp, eBottomLeft._nextEdgeCCWAroundOrigin, eTopLeft, eTopLeft, true);
}
}
@@ -1443,7 +1461,7 @@ static void SweepEvent(Tesselator tess, ContourVertex vEvent)
* input contour and the maximum tolerance of 1.0, no merging will be
* done with coordinates larger than 3 * GLU_TESS_MAX_COORD).
*/
- static double SENTINEL_COORD = (4 * Tesselator.MAX_COORD);
+ const double SENTINEL_COORD = (4 * Tesselator.MAX_COORD);
static void AddSentinel(Tesselator tess, double t)
/*
* We add two sentinel edges above and below all other edges,
@@ -1452,19 +1470,19 @@ static void AddSentinel(Tesselator tess, double t)
{
HalfEdge halfEdge;
ActiveRegion activeRedion = new ActiveRegion();
- halfEdge = tess.mesh.MakeEdge();
- halfEdge.originVertex.x = SENTINEL_COORD;
- halfEdge.originVertex.y = t;
- halfEdge.directionVertex.x = -SENTINEL_COORD;
- halfEdge.directionVertex.y = t;
- tess.currentSweepVertex = halfEdge.directionVertex; /* initialize it */
- activeRedion.upperHalfEdge = halfEdge;
- activeRedion.windingNumber = 0;
- activeRedion.inside = false;
- activeRedion.fixUpperEdge = false;
- activeRedion.sentinel = true;
- activeRedion.dirty = false;
- activeRedion.upperHalfEdgeDictNode = tess.edgeDictionary.Insert(activeRedion); /* __gl_dictListInsertBefore */
+ halfEdge = tess._mesh.MakeEdge();
+ halfEdge._originVertex.x = SENTINEL_COORD;
+ halfEdge._originVertex.y = t;
+ halfEdge.DirectionVertex.x = -SENTINEL_COORD;
+ halfEdge.DirectionVertex.y = t;
+ tess.currentSweepVertex = halfEdge.DirectionVertex; /* initialize it */
+ activeRedion._upperHalfEdge = halfEdge;
+ activeRedion._windingNumber = 0;
+ activeRedion._inside = false;
+ activeRedion._fixUpperEdge = false;
+ activeRedion._sentinel = true;
+ activeRedion._dirty = false;
+ activeRedion._upperHalfEdgeDictNode = tess._edgeDictionary.Insert(activeRedion); /* __gl_dictListInsertBefore */
}
@@ -1475,7 +1493,7 @@ static void InitEdgeDict(Tesselator tess)
*/
{
/* __gl_dictListNewDict */
- tess.edgeDictionary = new Dictionary(tess);
+ tess._edgeDictionary = new Dictionary(tess);
AddSentinel(tess, -SENTINEL_COORD);
AddSentinel(tess, SENTINEL_COORD);
}
@@ -1487,16 +1505,16 @@ static void DoneEdgeDict(Tesselator tess)
int fixedEdges = 0;
/* __GL_DICTLISTKEY */
/* __GL_DICTLISTMIN */
- while ((reg = tess.edgeDictionary.GetMinNode().Key) != null)
+ while ((reg = tess._edgeDictionary.GetMinNode().Key) != null)
{
/*
* At the end of all processing, the dictionary should contain
* only the two sentinel edges, plus at most one "fixable" edge
* created by ConnectRightVertex().
*/
- if (!reg.sentinel)
+ if (!reg._sentinel)
{
- if (!reg.fixUpperEdge)
+ if (!reg._fixUpperEdge)
{
throw new System.Exception();
}
@@ -1505,48 +1523,48 @@ static void DoneEdgeDict(Tesselator tess)
throw new System.Exception();
}
}
- if (reg.windingNumber != 0)
+ if (reg._windingNumber != 0)
{
throw new Exception();
}
DeleteRegion(reg);
}
- tess.edgeDictionary = null;
+ tess._edgeDictionary = null;
}
static void RemoveDegenerateEdges(Tesselator tess)
{
// Remove zero-length edges, and contours with fewer than 3 vertices.
- HalfEdge edgeHead = tess.mesh.halfEdgeHead;
+ HalfEdge edgeHead = tess._mesh._halfEdgeHead;
HalfEdge nextHalfEdge;
- for (HalfEdge currentEdge = edgeHead.nextHalfEdge; currentEdge != edgeHead; currentEdge = nextHalfEdge)
+ for (HalfEdge currentEdge = edgeHead._nextHalfEdge; currentEdge != edgeHead; currentEdge = nextHalfEdge)
{
- nextHalfEdge = currentEdge.nextHalfEdge;
- HalfEdge nextEdgeCCWAroundLeftFace = currentEdge.nextEdgeCCWAroundLeftFace;
- if (currentEdge.originVertex.VertEq(currentEdge.directionVertex)
- && currentEdge.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundLeftFace != currentEdge)
+ nextHalfEdge = currentEdge._nextHalfEdge;
+ HalfEdge nextEdgeCCWAroundLeftFace = currentEdge._nextEdgeCCWAroundLeftFace;
+ if (currentEdge._originVertex.VertEq(currentEdge.DirectionVertex)
+ && currentEdge._nextEdgeCCWAroundLeftFace._nextEdgeCCWAroundLeftFace != currentEdge)
{
// Zero-length edge, contour has at least 3 edges
SpliceMergeVertices(tess, nextEdgeCCWAroundLeftFace, currentEdge); /* deletes e.Org */
Mesh.DeleteHalfEdge(currentEdge); /* e is a self-loop */
currentEdge = nextEdgeCCWAroundLeftFace;
- nextEdgeCCWAroundLeftFace = currentEdge.nextEdgeCCWAroundLeftFace;
+ nextEdgeCCWAroundLeftFace = currentEdge._nextEdgeCCWAroundLeftFace;
}
- if (nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundLeftFace == currentEdge)
+ if (nextEdgeCCWAroundLeftFace._nextEdgeCCWAroundLeftFace == currentEdge)
{
// Degenerate contour (one or two edges)
if (nextEdgeCCWAroundLeftFace != currentEdge)
{
- if (nextEdgeCCWAroundLeftFace == nextHalfEdge || nextEdgeCCWAroundLeftFace == nextHalfEdge.otherHalfOfThisEdge)
+ if (nextEdgeCCWAroundLeftFace == nextHalfEdge || nextEdgeCCWAroundLeftFace == nextHalfEdge._otherHalfOfThisEdge)
{
- nextHalfEdge = nextHalfEdge.nextHalfEdge;
+ nextHalfEdge = nextHalfEdge._nextHalfEdge;
}
Mesh.DeleteHalfEdge(nextEdgeCCWAroundLeftFace);
}
- if (currentEdge == nextHalfEdge || currentEdge == nextHalfEdge.otherHalfOfThisEdge) { nextHalfEdge = nextHalfEdge.nextHalfEdge; }
+ if (currentEdge == nextHalfEdge || currentEdge == nextHalfEdge._otherHalfOfThisEdge) { nextHalfEdge = nextHalfEdge._nextHalfEdge; }
Mesh.DeleteHalfEdge(currentEdge);
}
}
@@ -1558,18 +1576,18 @@ static void InitPriorityQue(Tesselator tess)
* order in which vertices cross the sweep line.
*/
{
- MaxFirstList priorityQue = tess.vertexPriorityQue = new MaxFirstList();
- ContourVertex vertexHead = tess.mesh.vertexHead;
- for (ContourVertex curVertex = vertexHead.nextVertex; curVertex != vertexHead; curVertex = curVertex.nextVertex)
+ MaxFirstList priorityQue = tess._vertexPriorityQue = new MaxFirstList();
+ ContourVertex vertexHead = tess._mesh._vertexHead;
+ for (ContourVertex curVertex = vertexHead._nextVertex; curVertex != vertexHead; curVertex = curVertex._nextVertex)
{
- priorityQue.Add(out curVertex.priorityQueueHandle, curVertex);
+ priorityQue.Add(out curVertex._priorityQueueHandle, curVertex);
}
}
static void DonePriorityQ(Tesselator tess)
{
- tess.vertexPriorityQue = null; /* __gl_pqSortDeletePriorityQ */
+ tess._vertexPriorityQue = null; /* __gl_pqSortDeletePriorityQ */
}
@@ -1591,19 +1609,19 @@ static bool RemoveDegenerateFaces(Mesh mesh)
{
Face f, fNext;
HalfEdge e;
- for (f = mesh.faceHead.nextFace; f != mesh.faceHead; f = fNext)
+ for (f = mesh._faceHead._nextFace; f != mesh._faceHead; f = fNext)
{
- fNext = f.nextFace;
- e = f.halfEdgeThisIsLeftFaceOf;
- if (e.nextEdgeCCWAroundLeftFace == e)
+ fNext = f._nextFace;
+ e = f._halfEdgeThisIsLeftFaceOf;
+ if (e._nextEdgeCCWAroundLeftFace == e)
{
throw new Exception();
}
- if (e.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundLeftFace == e)
+ if (e._nextEdgeCCWAroundLeftFace._nextEdgeCCWAroundLeftFace == e)
{
/* A face with only two edges */
- AddWinding(e.nextEdgeCCWAroundOrigin, e);
+ AddWinding(e._nextEdgeCCWAroundOrigin, e);
Mesh.DeleteHalfEdge(e);
}
}
diff --git a/Demo/Shared/Tesselate/ContourVertex.cs b/Demo/Shared/Tesselate/ContourVertex.cs
index 4f39c5b2..b113a7b0 100644
--- a/Demo/Shared/Tesselate/ContourVertex.cs
+++ b/Demo/Shared/Tesselate/ContourVertex.cs
@@ -40,23 +40,24 @@
**
*/
-using System;
+using System;
namespace Tesselate
{
public class ContourVertex : IComparable
{
- public ContourVertex nextVertex; /* next vertex (never null) */
- public ContourVertex prevVertex; /* previous vertex (never null) */
- public HalfEdge edgeThisIsOriginOf; /* a half-edge with this origin */
- public int clientIndex; /* client's data */
+ internal ContourVertex _nextVertex; /* next vertex (never null) */
+ internal ContourVertex _prevVertex; /* previous vertex (never null) */
+ internal HalfEdge _edgeThisIsOriginOf; /* a half-edge with this origin */
+ internal int _clientIndex; /* client's data */
/* Internal data (keep hidden) */
/* vertex location in 3D */
- internal double C_0;
- internal double C_1;
- internal double C_2;
- public double x, y; /* projection onto the sweep plane */
- public RefItem priorityQueueHandle; /* to allow deletion from priority queue */
+ internal double _C_0;
+ internal double _C_1;
+ internal double _C_2;
+ internal double x, y; /* projection onto the sweep plane */
+ internal RefItem _priorityQueueHandle; /* to allow deletion from priority queue */
+
public int CompareTo(ContourVertex otherVertex)
{
if (VertEq(otherVertex))
@@ -70,10 +71,8 @@ public int CompareTo(ContourVertex otherVertex)
return 1;
}
- public bool Equal2D(ContourVertex OtherVertex)
- {
- return (this.x == OtherVertex.x && this.y == OtherVertex.y);
- }
+ public bool Equal2D(ContourVertex OtherVertex) => (x == OtherVertex.x && y == OtherVertex.y);
+
public static double EdgeEval(ContourVertex u, ContourVertex v, ContourVertex w)
{
@@ -133,20 +132,12 @@ static public double EdgeSign(ContourVertex u, ContourVertex v, ContourVertex w)
return 0;
}
- public bool VertEq(ContourVertex v)
- {
- return ((this.x == v.x) && this.y == v.y);
- }
+ public bool VertEq(ContourVertex v) => ((x == v.x) && y == v.y);
- public bool VertLeq(ContourVertex v)
- {
- return ((this.x < v.x) || (this.x == v.x && this.y <= v.y));
- }
+ public bool VertLeq(ContourVertex v) => ((x < v.x) || (x == v.x && y <= v.y));
+
+ public bool TransLeq(ContourVertex v) => ((y < v.y) || (y == v.y && x <= v.x));
- public bool TransLeq(ContourVertex v)
- {
- return ((this.y < v.y) || (this.y == v.y && this.x <= v.x));
- }
public static bool VertCCW(ContourVertex u, ContourVertex v, ContourVertex w)
{
@@ -162,7 +153,7 @@ public static bool VertCCW(ContourVertex u, ContourVertex v, ContourVertex w)
#if DEBUG
public override string ToString()
{
- return this.C_0 + "," + this.C_1 + "," + this.C_2;
+ return _C_0 + "," + _C_1 + "," + _C_2;
}
#endif
}
diff --git a/Demo/Shared/Tesselate/Dictionary.cs b/Demo/Shared/Tesselate/Dictionary.cs
index 885d5dd3..43222353 100644
--- a/Demo/Shared/Tesselate/Dictionary.cs
+++ b/Demo/Shared/Tesselate/Dictionary.cs
@@ -42,41 +42,35 @@
using DictKey = Tesselate.ActiveRegion;
namespace Tesselate
{
- public class Dictionary
+ class Dictionary
{
- public Node head = new Node();
- public Tesselator tesseator;
+ Node _head = new Node();
+ Tesselator _tess;
public class Node
{
- DictKey key = new DictKey();
+ public DictKey Key = new DictKey();
public Node next;
public Node prev;
- public DictKey Key
- {
- get { return this.key; }
- set { this.key = value; }
- }
-
public void Delete()
{
this.next.prev = this.prev;
this.prev.next = this.next;
}
- };
+ }
public Dictionary(Tesselator tesselator)
{
Node nodeHead;
- nodeHead = this.head;
+ nodeHead = _head;
nodeHead.Key = null;
nodeHead.next = nodeHead;
nodeHead.prev = nodeHead;
- this.tesseator = tesselator;
+ _tess = tesselator;
}
public static void dictDeleteDict(Dictionary dict)
{
Node node, next;
- for (node = dict.head.next; node != dict.head; node = next)
+ for (node = dict._head.next; node != dict._head; node = next)
{
next = node.next;
node = null;
@@ -87,7 +81,7 @@ public static void dictDeleteDict(Dictionary dict)
public Dictionary.Node Insert(DictKey k)
{
- return this.InsertBefore(head, k);
+ return this.InsertBefore(_head, k);
}
public Node InsertBefore(Node node, DictKey key)
@@ -96,8 +90,8 @@ public Node InsertBefore(Node node, DictKey key)
do
{
node = node.prev;
- } while (node.Key != null &&
- !ActiveRegion.EdgeLeq(this.tesseator, node.Key, key));
+ } while (node.Key != null && !ActiveRegion.EdgeLeq(_tess, node.Key, key));
+
newNode = new Node();
newNode.Key = key;
newNode.next = node.next;
@@ -109,16 +103,16 @@ public Node InsertBefore(Node node, DictKey key)
public Dictionary.Node GetMinNode()
{
- return this.head.next;
+ return _head.next;
}
public static Node dictSearch(Dictionary dict, DictKey key)
{
- Node node = dict.head;
+ Node node = dict._head;
do
{
node = node.next;
- } while (node.Key != null && !ActiveRegion.EdgeLeq(dict.tesseator, key, node.Key));
+ } while (node.Key != null && !ActiveRegion.EdgeLeq(dict._tess, key, node.Key));
return node;
}
}
diff --git a/Demo/Shared/Tesselate/Face.cs b/Demo/Shared/Tesselate/Face.cs
index d6b0269c..d50c4e31 100644
--- a/Demo/Shared/Tesselate/Face.cs
+++ b/Demo/Shared/Tesselate/Face.cs
@@ -45,14 +45,16 @@ namespace Tesselate
{
public class Face
{
- public int indexDebug;
- public Face nextFace; /* next face (never null) */
- public Face prevFace; /* previous face (never null) */
- public HalfEdge halfEdgeThisIsLeftFaceOf; /* a half edge with this left face */
+#if DEBUG
+ public int dbugIndex;
+#endif
+ internal Face _nextFace; /* next face (never null) */
+ internal Face _prevFace; /* previous face (never null) */
+ internal HalfEdge _halfEdgeThisIsLeftFaceOf; /* a half edge with this left face */
/* Internal data (keep hidden) */
- public Face trail; /* "stack" for conversion to strips */
- public bool marked; /* flag for conversion to strips */
- public bool isInterior; /* this face is in the polygon interior */
+ internal Face _trail; /* "stack" for conversion to strips */
+ internal bool _marked; /* flag for conversion to strips */
+ internal bool _isInterior; /* this face is in the polygon interior */
/* Macros which keep track of faces we have marked temporarily, and allow
* us to backtrack when necessary. With triangle fans, this is not
* really necessary, since the only awkward case is a loop of triangles
@@ -60,24 +62,21 @@ public class Face
* more complicated, and we need a general tracking method like the
* one here.
*/
- public bool Marked()
- {
- return (!this.isInterior || this.marked);
- }
+ public bool Marked() => (!_isInterior || _marked);
public static void AddToTrail(ref Face f, ref Face t)
{
- f.trail = t;
+ f._trail = t;
t = f;
- f.marked = true;
+ f._marked = true;
}
static public void FreeTrail(ref Face t)
{
while (t != null)
{
- t.marked = false;
- t = t.trail;
+ t._marked = false;
+ t = t._trail;
}
}
@@ -115,56 +114,56 @@ internal bool TessellateMonoRegion()
* Since the sweep goes from left to right, face.anEdge should
* be close to the edge we want.
*/
- HalfEdge up = this.halfEdgeThisIsLeftFaceOf;
- if (up.nextEdgeCCWAroundLeftFace == up || up.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundLeftFace == up)
+ HalfEdge up = _halfEdgeThisIsLeftFaceOf;
+ if (up._nextEdgeCCWAroundLeftFace == up || up._nextEdgeCCWAroundLeftFace._nextEdgeCCWAroundLeftFace == up)
{
throw new Exception();
}
- for (; up.directionVertex.VertLeq(up.originVertex); up = up.Lprev)
+ for (; up.DirectionVertex.VertLeq(up._originVertex); up = up.Lprev)
;
- for (; up.originVertex.VertLeq(up.directionVertex); up = up.nextEdgeCCWAroundLeftFace)
+ for (; up._originVertex.VertLeq(up.DirectionVertex); up = up._nextEdgeCCWAroundLeftFace)
;
HalfEdge lo = up.Lprev;
- while (up.nextEdgeCCWAroundLeftFace != lo)
+ while (up._nextEdgeCCWAroundLeftFace != lo)
{
- if (up.directionVertex.VertLeq(lo.originVertex))
+ if (up.DirectionVertex.VertLeq(lo._originVertex))
{
/* 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.nextEdgeCCWAroundLeftFace != up && (lo.nextEdgeCCWAroundLeftFace.EdgeGoesLeft()
- || ContourVertex.EdgeSign(lo.originVertex, lo.directionVertex, lo.nextEdgeCCWAroundLeftFace.directionVertex) <= 0))
+ while (lo._nextEdgeCCWAroundLeftFace != up && (lo._nextEdgeCCWAroundLeftFace.EdgeGoesLeft()
+ || ContourVertex.EdgeSign(lo._originVertex, lo.DirectionVertex, lo._nextEdgeCCWAroundLeftFace.DirectionVertex) <= 0))
{
- HalfEdge tempHalfEdge = Mesh.meshConnect(lo.nextEdgeCCWAroundLeftFace, lo);
- lo = tempHalfEdge.otherHalfOfThisEdge;
+ HalfEdge tempHalfEdge = Mesh.meshConnect(lo._nextEdgeCCWAroundLeftFace, lo);
+ lo = tempHalfEdge._otherHalfOfThisEdge;
}
lo = lo.Lprev;
}
else
{
/* lo.Org is on the left. We can make CCW triangles from up.Dst. */
- while (lo.nextEdgeCCWAroundLeftFace != up && (up.Lprev.EdgeGoesRight()
- || ContourVertex.EdgeSign(up.directionVertex, up.originVertex, up.Lprev.originVertex) >= 0))
+ while (lo._nextEdgeCCWAroundLeftFace != up && (up.Lprev.EdgeGoesRight()
+ || ContourVertex.EdgeSign(up.DirectionVertex, up._originVertex, up.Lprev._originVertex) >= 0))
{
HalfEdge tempHalfEdge = Mesh.meshConnect(up, up.Lprev);
- up = tempHalfEdge.otherHalfOfThisEdge;
+ up = tempHalfEdge._otherHalfOfThisEdge;
}
- up = up.nextEdgeCCWAroundLeftFace;
+ up = up._nextEdgeCCWAroundLeftFace;
}
}
// Now lo.Org == up.Dst == the leftmost vertex. The remaining region
// can be tessellated in a fan from this leftmost vertex.
- if (lo.nextEdgeCCWAroundLeftFace == up)
+ if (lo._nextEdgeCCWAroundLeftFace == up)
{
throw new Exception();
}
- while (lo.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundLeftFace != up)
+ while (lo._nextEdgeCCWAroundLeftFace._nextEdgeCCWAroundLeftFace != up)
{
- HalfEdge tempHalfEdge = Mesh.meshConnect(lo.nextEdgeCCWAroundLeftFace, lo);
- lo = tempHalfEdge.otherHalfOfThisEdge;
+ HalfEdge tempHalfEdge = Mesh.meshConnect(lo._nextEdgeCCWAroundLeftFace, lo);
+ lo = tempHalfEdge._otherHalfOfThisEdge;
}
return true;
diff --git a/Demo/Shared/Tesselate/HalfEdge.cs b/Demo/Shared/Tesselate/HalfEdge.cs
index 9ec28599..ed10656c 100644
--- a/Demo/Shared/Tesselate/HalfEdge.cs
+++ b/Demo/Shared/Tesselate/HalfEdge.cs
@@ -44,33 +44,37 @@ namespace Tesselate
{
public class HalfEdge
{
+#if DEBUG
public int debugIndex;
- public bool isFirstHalfEdge;
- public HalfEdge nextHalfEdge; /* doubly-linked list (prev==Sym.next) */
- public HalfEdge otherHalfOfThisEdge; /* same edge, opposite direction */
- public HalfEdge nextEdgeCCWAroundOrigin; /* next edge CCW around origin */
- public HalfEdge nextEdgeCCWAroundLeftFace; /* next edge CCW around left face */
- public ContourVertex originVertex; /* origin vertex */
- public Face leftFace; /* left face */
+#endif
+ internal bool _isFirstHalfEdge;
+ internal HalfEdge _nextHalfEdge; /* doubly-linked list (prev==Sym.next) */
+ internal HalfEdge _otherHalfOfThisEdge; /* same edge, opposite direction */
+ internal HalfEdge _nextEdgeCCWAroundOrigin; /* next edge CCW around origin */
+ internal HalfEdge _nextEdgeCCWAroundLeftFace; /* next edge CCW around left face */
+ internal ContourVertex _originVertex; /* origin vertex */
+ internal Face _leftFace; /* left face */
/* Internal data (keep hidden) */
- public ActiveRegion regionThisIsUpperEdgeOf; /* a region with this upper edge (sweep.c) */
- public int winding; // change in winding number when crossing from the right face to the left face
- public Face rightFace { get { return otherHalfOfThisEdge.leftFace; } set { otherHalfOfThisEdge.leftFace = value; } }
- public HalfEdge Lprev { get { return nextEdgeCCWAroundOrigin.otherHalfOfThisEdge; } set { nextEdgeCCWAroundOrigin.otherHalfOfThisEdge = value; } }
- public HalfEdge Oprev { get { return otherHalfOfThisEdge.nextEdgeCCWAroundLeftFace; } }
- public ContourVertex directionVertex { get { return otherHalfOfThisEdge.originVertex; } set { otherHalfOfThisEdge.originVertex = value; } }
- public HalfEdge Dnext { get { return Rprev.otherHalfOfThisEdge; } }
- public HalfEdge Dprev { get { return nextEdgeCCWAroundLeftFace.otherHalfOfThisEdge; } }
- public HalfEdge Rprev { get { return otherHalfOfThisEdge.nextEdgeCCWAroundOrigin; } }
+ internal ActiveRegion _regionThisIsUpperEdgeOf; /* a region with this upper edge (sweep.c) */
+ internal int _winding; // change in winding number when crossing from the right face to the left face
+ internal Face rightFace { get => _otherHalfOfThisEdge._leftFace; set => _otherHalfOfThisEdge._leftFace = value; }
- public bool EdgeGoesLeft()
+ internal HalfEdge Lprev { get => _nextEdgeCCWAroundOrigin._otherHalfOfThisEdge; set => _nextEdgeCCWAroundOrigin._otherHalfOfThisEdge = value; }
+ internal HalfEdge Oprev => _otherHalfOfThisEdge._nextEdgeCCWAroundLeftFace;
+
+ internal ContourVertex DirectionVertex { get => _otherHalfOfThisEdge._originVertex; set => _otherHalfOfThisEdge._originVertex = value; }
+ internal HalfEdge Dnext => Rprev._otherHalfOfThisEdge;
+ internal HalfEdge Dprev => _nextEdgeCCWAroundLeftFace._otherHalfOfThisEdge;
+ internal HalfEdge Rprev => _otherHalfOfThisEdge._nextEdgeCCWAroundOrigin;
+
+ internal bool EdgeGoesLeft()
{
- return this.directionVertex.VertLeq(this.originVertex);
+ return this.DirectionVertex.VertLeq(_originVertex);
}
- public bool EdgeGoesRight()
+ internal bool EdgeGoesRight()
{
- return this.originVertex.VertLeq(this.directionVertex);
+ return _originVertex.VertLeq(this.DirectionVertex);
}
}
}
\ No newline at end of file
diff --git a/Demo/Shared/Tesselate/MaxFirstList.cs b/Demo/Shared/Tesselate/MaxFirstList.cs
index 1aa02e3e..63e6af6f 100644
--- a/Demo/Shared/Tesselate/MaxFirstList.cs
+++ b/Demo/Shared/Tesselate/MaxFirstList.cs
@@ -1,15 +1,17 @@
-//BSD, 2014-2017, WinterDev
+//BSD, 2014-present, WinterDev
using System;
using System.Collections.Generic;
namespace Tesselate
{
+
+ //TODO: review this again....
//-----
//design for our tess only
//not for general use.
//-----
- public class RefItem
- where T : IComparable
+ class RefItem
+ where T : IComparable
{
public RefItem(T data)
{
@@ -25,71 +27,67 @@ public override string ToString()
#endif
}
- public class MaxFirstList
- where T : IComparable
+ class MaxFirstList
+ where T : IComparable
{
- List> innerList = new List>();
- bool isSorted = false;
+ List> _innerList = new List>();
+ bool _isSorted = false;
public MaxFirstList()
{
}
- public bool IsEmpty
- {
- get
- {
- return innerList.Count == 0;
- }
- }
+ //
+ public bool IsEmpty => _innerList.Count == 0;
+ //
static int MaxFirstSort(RefItem t1, RefItem t2)
{
return t2.Data.CompareTo(t1.Data);
}
void SortData()
{
- innerList.Sort(MaxFirstSort);
- for (int i = innerList.Count - 1; i >= 0; --i)
+ _innerList.Sort(MaxFirstSort);
+ for (int i = _innerList.Count - 1; i >= 0; --i)
{
- innerList[i].NodeNumber = i;
+ _innerList[i].NodeNumber = i;
}
- isSorted = true;
+ _isSorted = true;
}
public T DeleteMin()
{
//find min and delete
- if (!isSorted)
+ if (!_isSorted)
{
SortData();
}
- int last = innerList.Count - 1;
- var tmp = innerList[last];
- innerList.RemoveAt(last);
+ int last = _innerList.Count - 1;
+ var tmp = _innerList[last];
+ _innerList.RemoveAt(last);
return tmp.Data;
}
public T FindMin()
{
- if (!isSorted)
+ if (!_isSorted)
{
SortData();
}
- return innerList[innerList.Count - 1].Data;
+ return _innerList[_innerList.Count - 1].Data;
}
public void Add(out RefItem refItem, T data)
{
RefItem item = new RefItem(data);
- innerList.Add(item);
- isSorted = false;
+ _innerList.Add(item);
+ _isSorted = false;
refItem = item;
}
public void Add(T data)
{
RefItem item = new RefItem(data);
- innerList.Add(item);
- isSorted = false;
+ _innerList.Add(item);
+ _isSorted = false;
}
int BinSearch(RefItem refItem, int begin, int end)
{
int pos = begin + ((end - begin) / 2);
- RefItem sample = innerList[pos];
+ RefItem sample = _innerList[pos];
if (refItem == sample)
{
}
@@ -123,24 +121,24 @@ public void Delete(RefItem refItem)
{
//delete specfic node
- if (isSorted)
+ if (_isSorted)
{
//use binary search to find node
//1. find middle point
int removeAt = refItem.NodeNumber;
- for (int i = innerList.Count - 1; i > removeAt; --i)
+ for (int i = _innerList.Count - 1; i > removeAt; --i)
{
- innerList[i].NodeNumber = i - 1;
+ _innerList[i].NodeNumber = i - 1;
}
- innerList.RemoveAt(removeAt);
+ _innerList.RemoveAt(removeAt);
}
else
{
- for (int i = innerList.Count - 1; i >= 0; --i)
+ for (int i = _innerList.Count - 1; i >= 0; --i)
{
- if (innerList[i] == refItem)
+ if (_innerList[i] == refItem)
{
- this.innerList.RemoveAt(i);
+ _innerList.RemoveAt(i);
break;
}
}
diff --git a/Demo/Shared/Tesselate/Tesselator.cs b/Demo/Shared/Tesselate/Tesselator.cs
deleted file mode 100644
index d70693a5..00000000
--- a/Demo/Shared/Tesselate/Tesselator.cs
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
-** License Applicability. Except to the extent portions of this file are
-** made subject to an alternative license as permitted in the SGI Free
-** Software License B, Version 1.1 (the "License"), the contents of this
-** file are subject only to the provisions of the License. You may not use
-** this file except in compliance with the License. You may obtain a copy
-** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
-** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
-**
-** http://oss.sgi.com/projects/FreeB
-**
-** Note that, as provided in the License, the Software is distributed on an
-** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
-** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
-** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
-** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
-**
-** Original Code. The Original Code is: OpenGL Sample Implementation,
-** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
-** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
-** Copyright in any portions created by third parties is as indicated
-** elsewhere herein. All Rights Reserved.
-**
-** Additional Notice Provisions: The application programming interfaces
-** established by SGI in conjunction with the Original Code are The
-** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
-** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
-** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
-** Window System(R) (Version 1.3), released October 19, 1998. This software
-** was created using the OpenGL(R) version 1.2.1 Sample Implementation
-** published by SGI, but has not been independently verified as being
-** compliant with the OpenGL(R) version 1.2.1 Specification.
-**
-*/
-/*
-** Author: Eric Veach, July 1994.
-// C# Port port by: Lars Brubaker
-// larsbrubaker@gmail.com
-// Copyright (C) 2007
-**
-*/
-//MIT,2014- present, WinterDev
-using System;
-namespace Tesselate
-{
- public class Tesselator
- {
- // The begin/end calls must be properly nested. We keep track of
- // the current state to enforce the ordering.
- enum ProcessingState
- {
- Dormant, InPolygon, InContour
- }
- // We cache vertex data for single-contour polygons so that we can
- // try a quick-and-dirty decomposition first.
- const int MAX_CACHE_SIZE = 100;
- internal const double MAX_COORD = 1.0e150;
-
- struct Vertex
- {
- public double x;
- public double y;
- }
-
-
- public struct CombineParameters
- {
- public int d0, d1, d2, d3;
- public double w0, w1, w2, w3;
- }
- public enum TriangleListType
- {
- LineLoop,
- Triangles,
- TriangleStrip,
- TriangleFan
- }
-
- public enum WindingRuleType
- {
- Odd,
- NonZero,
- Positive,
- Negative,
- ABS_GEQ_Two,
- }
-
- ProcessingState _processingState; /* what begin/end calls have we seen? */
- HalfEdge _lastHalfEdge; /* lastEdge.Org is the most recent vertex */
- public Mesh mesh; /* stores the input contours, and eventually the tessellation itself */
- WindingRuleType _windingRule; // rule for determining polygon interior
-
- public Dictionary edgeDictionary; /* edge dictionary for sweep line */
-
- internal MaxFirstList vertexPriorityQue = new MaxFirstList();
-
- public ContourVertex currentSweepVertex; /* current sweep event being processed */
-
- public delegate void CallCombineDelegate(
- double c1, double c2, double c3, ref CombineParameters combinePars, out int outData);
-
- public CallCombineDelegate callCombine;
- /*** state needed for rendering callbacks (see render.c) ***/
-
- bool _boundaryOnly; /* Extract contours, not triangles */
- Face _lonelyTriList;
- /* list of triangles which could not be rendered as strips or fans */
-
- public delegate void CallBeginDelegate(TriangleListType type);
- public CallBeginDelegate callBegin;
- public delegate void CallEdgeFlagDelegate(bool boundaryEdge);
- public CallEdgeFlagDelegate callEdgeFlag;
- public delegate void CallVertexDelegate(int data);
- public CallVertexDelegate callVertex;
- public delegate void CallEndDelegate();
- public CallEndDelegate callEnd;
- public delegate void CallMeshDelegate(Mesh mesh);
- public CallMeshDelegate callMesh;
- /*** state needed to cache single-contour polygons for renderCache() */
-
- bool _emptyCache; /* empty cache on next vertex() call */
- int _cacheCount; /* number of cached vertices */
- Vertex[] _simpleVertexCache = new Vertex[MAX_CACHE_SIZE]; /* the vertex data */
- int[] _indexCached = new int[MAX_CACHE_SIZE];
- public Tesselator()
- {
- /* Only initialize fields which can be changed by the api. Other fields
- * are initialized where they are used.
- */
- _processingState = ProcessingState.Dormant;
- _windingRule = Tesselator.WindingRuleType.Odd;//default
- _boundaryOnly = false;
- }
-
- ~Tesselator()
- {
- RequireState(ProcessingState.Dormant);
- }
-
- public bool EdgeCallBackSet => callEdgeFlag != null;
-
- public WindingRuleType WindingRule
- {
- get => _windingRule;
- set => _windingRule = value;
- }
-
- public bool BoundaryOnly
- {
- get => _boundaryOnly;
- set => _boundaryOnly = value;
- }
-
- public bool IsWindingInside(int numCrossings)
- {
- switch (_windingRule)
- {
- case Tesselator.WindingRuleType.Odd:
- return (numCrossings & 1) != 0;
- case Tesselator.WindingRuleType.NonZero:
- return (numCrossings != 0);
- case Tesselator.WindingRuleType.Positive:
- return (numCrossings > 0);
- case Tesselator.WindingRuleType.Negative:
- return (numCrossings < 0);
- case Tesselator.WindingRuleType.ABS_GEQ_Two:
- return (numCrossings >= 2) || (numCrossings <= -2);
- }
-
- throw new Exception();
- }
-
- public void CallBegin(TriangleListType triangleType)
- {
- callBegin?.Invoke(triangleType);
- }
- public void CallVertex(int vertexData)
- {
- callVertex?.Invoke(vertexData);
- }
- public void CallEdgeFlag(bool edgeState)
- {
- callEdgeFlag?.Invoke(edgeState);
- }
-
- public void CallEnd()
- {
- callEnd?.Invoke();
- }
-
- public void CallCombine(double v0,
- double v1, double v2,
- ref CombineParameters combinePars,
- out int outData)
- {
- outData = 0;
- callCombine?.Invoke(v0, v1, v2, ref combinePars, out outData);
- }
-
- void GotoState(ProcessingState newProcessingState)
- {
- while (_processingState != newProcessingState)
- {
- /* We change the current state one level at a time, to get to
- * the desired state.
- */
- if (_processingState < newProcessingState)
- {
- switch (_processingState)
- {
- case ProcessingState.Dormant:
- throw new Exception("MISSING_BEGIN_POLYGON");
- case ProcessingState.InPolygon:
- throw new Exception("MISSING_BEGIN_CONTOUR");
- default:
- break;
- }
- }
- else
- {
- switch (_processingState)
- {
- case ProcessingState.InContour:
- throw new Exception("MISSING_END_CONTOUR");
- case ProcessingState.InPolygon:
- throw new Exception("MISSING_END_POLYGON");
- default:
- break;
- }
- }
- }
- }
-
- void RequireState(ProcessingState state)
- {
- if (_processingState != state)
- {
- GotoState(state);
- }
- }
-
- public virtual void BeginPolygon()
- {
- RequireState(ProcessingState.Dormant);
- _processingState = ProcessingState.InPolygon;
- _cacheCount = 0;
- _emptyCache = false;
- mesh = null;
- }
-
- public void BeginContour()
- {
- RequireState(ProcessingState.InPolygon);
- _processingState = ProcessingState.InContour;
- _lastHalfEdge = null;
- if (_cacheCount > 0)
- {
- // Just set a flag so we don't get confused by empty contours
- _emptyCache = true;
- }
- }
-
- bool AddVertex(double x, double y, int data)
- {
- HalfEdge e;
- e = _lastHalfEdge;
- if (e == null)
- {
- /* Make a self-loop (one vertex, one edge). */
- e = this.mesh.MakeEdge();
- Mesh.meshSplice(e, e.otherHalfOfThisEdge);
- }
- else
- {
- /* Create a new vertex and edge which immediately follow e
- * in the ordering around the left face.
- */
- if (Mesh.meshSplitEdge(e) == null)
- {
- return false;
- }
- e = e.nextEdgeCCWAroundLeftFace;
- }
-
- /* The new vertex is now e.Org. */
- e.originVertex.clientIndex = data;
- e.originVertex.C_0 = x;
- e.originVertex.C_1 = y;
- /* 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.otherHalfOfThisEdge.winding = -1;
- _lastHalfEdge = e;
- return true;
- }
-
- void EmptyCache()
- {
- Vertex[] vCaches = _simpleVertexCache;
- int[] index_caches = _indexCached;
- this.mesh = new Mesh();
- int count = _cacheCount;
- for (int i = 0; i < count; i++)
- {
- Vertex v = vCaches[i];
- this.AddVertex(v.x, v.y, index_caches[i]);
- }
- _cacheCount = 0;
- _emptyCache = false;
- }
-
- void CacheVertex(double x, double y, double z, int data)
- {
- Vertex v = new Vertex();
- v.x = x;
- v.y = y;
- _simpleVertexCache[_cacheCount] = v;
- _indexCached[_cacheCount] = data;
- ++_cacheCount;
- }
- void CacheVertex(double x, double y, int data)
- {
- Vertex v = new Vertex();
- v.x = x;
- v.y = y;
- _simpleVertexCache[_cacheCount] = v;
- _indexCached[_cacheCount] = data;
- ++_cacheCount;
- }
- public void AddVertex(double x, double y, double z, int data)
- {
-
- RequireState(ProcessingState.InContour);
- if (_emptyCache)
- {
- EmptyCache();
- _lastHalfEdge = null;
- }
- //=============================
- //expand to 3 times
- double tmp = x;
- if (tmp < -MAX_COORD)
- {
- throw new Exception("Your coordinate exceeded -" + MAX_COORD.ToString() + ".");
- }
- if (tmp > MAX_COORD)
- {
- throw new Exception("Your coordinate exceeded " + MAX_COORD.ToString() + ".");
- }
-
- //=============================
- tmp = y;
- if (tmp < -MAX_COORD)
- {
- throw new Exception("Your coordinate exceeded -" + MAX_COORD.ToString() + ".");
- }
- if (tmp > MAX_COORD)
- {
- throw new Exception("Your coordinate exceeded " + MAX_COORD.ToString() + ".");
- }
- //=============================
- tmp = z;
- if (tmp < -MAX_COORD)
- {
- throw new Exception("Your coordinate exceeded -" + MAX_COORD.ToString() + ".");
- }
- if (tmp > MAX_COORD)
- {
- throw new Exception("Your coordinate exceeded " + MAX_COORD.ToString() + ".");
- }
- //=============================
-
-
- if (mesh == null)
- {
- if (_cacheCount < MAX_CACHE_SIZE)
- {
- CacheVertex(x, y, data);
- return;
- }
- EmptyCache();
- }
- AddVertex(x, y, data);
- }
-
- public void EndContour()
- {
- RequireState(ProcessingState.InContour);
- _processingState = ProcessingState.InPolygon;
- }
-
- void CheckOrientation()
- {
- double area = 0;
- Face curFace, faceHead = this.mesh.faceHead;
- ContourVertex vHead = this.mesh.vertexHead;
- HalfEdge curHalfEdge;
- /* When we compute the normal automatically, we choose the orientation
- * so that the sum of the signed areas of all contours is non-negative.
- */
- for (curFace = faceHead.nextFace; curFace != faceHead; curFace = curFace.nextFace)
- {
- curHalfEdge = curFace.halfEdgeThisIsLeftFaceOf;
- if (curHalfEdge.winding <= 0)
- {
- continue;
- }
-
- do
- {
- area += (curHalfEdge.originVertex.x - curHalfEdge.directionVertex.x)
- * (curHalfEdge.originVertex.y + curHalfEdge.directionVertex.y);
- curHalfEdge = curHalfEdge.nextEdgeCCWAroundLeftFace;
- } while (curHalfEdge != curFace.halfEdgeThisIsLeftFaceOf);
- }
-
- if (area < 0)
- {
- /* Reverse the orientation by flipping all the t-coordinates */
- for (ContourVertex curVertex = vHead.nextVertex; curVertex != vHead; curVertex = curVertex.nextVertex)
- {
- curVertex.y = -curVertex.y;
- }
- }
- }
-
- void ProjectPolygon()
- {
- ContourVertex v, vHead = this.mesh.vertexHead;
- // Project the vertices onto the sweep plane
- for (v = vHead.nextVertex; v != vHead; v = v.nextVertex)
- {
- v.x = v.C_0;
- v.y = -v.C_1;
- }
-
- CheckOrientation();
- }
-
- public void EndPolygon()
- {
- RequireState(ProcessingState.InPolygon);
- _processingState = ProcessingState.Dormant;
- if (this.mesh == null)
- {
- if (!this.EdgeCallBackSet && this.callMesh == null)
- {
- /* Try some special code to make the easy cases go quickly
- * (eg. convex polygons). This code does NOT handle multiple contours,
- * intersections, edge flags, and of course it does not generate
- * an explicit mesh either.
- */
- if (RenderCache())
- {
- return;
- }
- }
-
- EmptyCache(); /* could've used a label*/
- }
-
- /* Determine the polygon normal and project vertices onto the plane
- * of the polygon.
- */
- ProjectPolygon();
- /* __gl_computeInterior( this ) 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 this.windingRule.
- * Each interior region is guaranteed to be monotone.
- */
- ActiveRegion.ComputeInterior(this);
- bool rc = true;
- /* 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 (_boundaryOnly)
- {
- rc = this.mesh.SetWindingNumber(1, true);
- }
- else
- {
- rc = this.mesh.TessellateInterior();
- }
-
- this.mesh.CheckMesh();
- if (this.callBegin != null || this.callEnd != null
- || this.callVertex != null || this.callEdgeFlag != null)
- {
- if (_boundaryOnly)
- {
- RenderBoundary(mesh); /* output boundary contours */
- }
- else
- {
- RenderMesh(mesh); /* output strips and fans */
- }
- }
- if (this.callMesh != null)
- {
- /* Throw away the exterior faces, so that all faces are interior.
- * This way the user doesn't have to check the "inside" flag,
- * and we don't need to even reveal its existence. It also leaves
- * the freedom for an implementation to not generate the exterior
- * faces in the first place.
- */
- mesh.DiscardExterior();
- callMesh(mesh); /* user wants the mesh itself */
- this.mesh = null;
- return;
- }
- this.mesh = null;
- }
-
- class FaceCount
- {
- public FaceCount(int _size, HalfEdge _eStart, RenderDelegate _render)
- {
- size = _size;
- eStart = _eStart;
- render = _render;
- }
-
- public int size; /* number of triangles used */
- public HalfEdge eStart; /* edge where this primitive starts */
- public delegate void RenderDelegate(Tesselator tess, HalfEdge edge, int data);
- event RenderDelegate render;
- // routine to render this primitive
-
- public void CallRender(Tesselator tess, HalfEdge edge, int data)
- {
- render(tess, edge, data);
- }
- }
-
- /************************ Strips and Fans decomposition ******************/
-
- /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
- * fans, strips, and separate triangles. A substantial effort is made
- * to use as few rendering primitives as possible (ie. to make the fans
- * and strips as large as possible).
- *
- * The rendering output is provided as callbacks (see the api).
- */
- public void RenderMesh(Mesh mesh)
- {
- Face f;
- /* Make a list of separate triangles so we can render them all at once */
- _lonelyTriList = null;
- for (f = mesh.faceHead.nextFace; f != mesh.faceHead; f = f.nextFace)
- {
- f.marked = false;
- }
- for (f = mesh.faceHead.nextFace; f != mesh.faceHead; f = f.nextFace)
- {
- /* We examine all faces in an arbitrary order. Whenever we find
- * an unprocessed face F, we output a group of faces including F
- * whose size is maximum.
- */
- if (f.isInterior && !f.marked)
- {
- RenderMaximumFaceGroup(f);
- if (!f.marked)
- {
- throw new System.Exception();
- }
- }
- }
- if (_lonelyTriList != null)
- {
- RenderLonelyTriangles(_lonelyTriList);
- _lonelyTriList = null;
- }
- }
-
-
- void RenderMaximumFaceGroup(Face fOrig)
- {
- /* We want to find the largest triangle fan or strip of unmarked faces
- * which includes the given face fOrig. There are 3 possible fans
- * passing through fOrig (one centered at each vertex), and 3 possible
- * strips (one for each CCW permutation of the vertices). Our strategy
- * is to try all of these, and take the primitive which uses the most
- * triangles (a greedy approach).
- */
- HalfEdge e = fOrig.halfEdgeThisIsLeftFaceOf;
- FaceCount max = new FaceCount(1, e, new FaceCount.RenderDelegate(RenderTriangle));
- FaceCount newFace;
- max.size = 1;
- max.eStart = e;
- if (!this.EdgeCallBackSet)
- {
- newFace = MaximumFan(e); if (newFace.size > max.size) { max = newFace; }
- newFace = MaximumFan(e.nextEdgeCCWAroundLeftFace); if (newFace.size > max.size) { max = newFace; }
- newFace = MaximumFan(e.Lprev); if (newFace.size > max.size) { max = newFace; }
-
- newFace = MaximumStrip(e); if (newFace.size > max.size) { max = newFace; }
- newFace = MaximumStrip(e.nextEdgeCCWAroundLeftFace); if (newFace.size > max.size) { max = newFace; }
- newFace = MaximumStrip(e.Lprev); if (newFace.size > max.size) { max = newFace; }
- }
-
- max.CallRender(this, max.eStart, max.size);
- }
-
- FaceCount MaximumFan(HalfEdge eOrig)
- {
- /* eOrig.Lface is the face we want to render. We want to find the size
- * of a maximal fan around eOrig.Org. To do this we just walk around
- * the origin vertex as far as possible in both directions.
- */
- FaceCount newFace = new FaceCount(0, null, new FaceCount.RenderDelegate(RenderFan));
- Face trail = null;
- HalfEdge e;
- for (e = eOrig; !e.leftFace.Marked(); e = e.nextEdgeCCWAroundOrigin)
- {
- Face.AddToTrail(ref e.leftFace, ref trail);
- ++newFace.size;
- }
- for (e = eOrig; !e.rightFace.Marked(); e = e.Oprev)
- {
- Face f = e.rightFace;
- Face.AddToTrail(ref f, ref trail);
- e.rightFace = f;
- ++newFace.size;
- }
- newFace.eStart = e;
- Face.FreeTrail(ref trail);
- return newFace;
- }
-
-
- static bool IsEven(int n)
- {
- return (((n) & 1) == 0);
- }
-
- FaceCount MaximumStrip(HalfEdge eOrig)
- {
- /* Here we are looking for a maximal strip that contains the vertices
- * eOrig.Org, eOrig.Dst, eOrig.Lnext.Dst (in that order or the
- * reverse, such that all triangles are oriented CCW).
- *
- * Again we walk forward and backward as far as possible. However for
- * strips there is a twist: to get CCW orientations, there must be
- * an *even* number of triangles in the strip on one side of eOrig.
- * We walk the strip starting on a side with an even number of triangles;
- * if both side have an odd number, we are forced to shorten one side.
- */
- FaceCount newFace = new FaceCount(0, null, RenderStrip);
- int headSize = 0, tailSize = 0;
- Face trail = null;
- HalfEdge e, eTail, eHead;
- for (e = eOrig; !e.leftFace.Marked(); ++tailSize, e = e.nextEdgeCCWAroundOrigin)
- {
- Face.AddToTrail(ref e.leftFace, ref trail);
- ++tailSize;
- e = e.Dprev;
- if (e.leftFace.Marked()) break;
- Face.AddToTrail(ref e.leftFace, ref trail);
- }
- eTail = e;
- for (e = eOrig; !e.rightFace.Marked(); ++headSize, e = e.Dnext)
- {
- Face f = e.rightFace;
- Face.AddToTrail(ref f, ref trail);
- e.rightFace = f;
- ++headSize;
- e = e.Oprev;
- if (e.rightFace.Marked()) break;
- f = e.rightFace;
- Face.AddToTrail(ref f, ref trail);
- e.rightFace = f;
- }
- eHead = e;
- newFace.size = tailSize + headSize;
- if (IsEven(tailSize))
- {
- newFace.eStart = eTail.otherHalfOfThisEdge;
- }
- else if (IsEven(headSize))
- {
- newFace.eStart = eHead;
- }
- else
- {
- /* Both sides have odd length, we must shorten one of them. In fact,
- * we must start from eHead to guarantee inclusion of eOrig.Lface.
- */
- --newFace.size;
- newFace.eStart = eHead.nextEdgeCCWAroundOrigin;
- }
-
- Face.FreeTrail(ref trail);
- return newFace;
- }
-
-
- void RenderTriangle(Tesselator tess, HalfEdge e, int size)
- {
- /* Just add the triangle to a triangle list, so we can render all
- * the separate triangles at once.
- */
- if (size != 1)
- {
- throw new Exception();
- }
- Face.AddToTrail(ref e.leftFace, ref _lonelyTriList);
- }
-
-
- void RenderLonelyTriangles(Face f)
- {
- /* Now we render all the separate triangles which could not be
- * grouped into a triangle fan or strip.
- */
- HalfEdge e;
- bool newState = false;
- bool edgeState = false; /* force edge state output for first vertex */
- bool sentFirstEdge = false;
- this.CallBegin(Tesselator.TriangleListType.Triangles);
- for (; f != null; f = f.trail)
- {
- /* Loop once for each edge (there will always be 3 edges) */
-
- e = f.halfEdgeThisIsLeftFaceOf;
- do
- {
- if (this.EdgeCallBackSet)
- {
- /* Set the "edge state" to TRUE just before we output the
- * first vertex of each edge on the polygon boundary.
- */
- newState = !e.rightFace.isInterior;
- if (edgeState != newState || !sentFirstEdge)
- {
- sentFirstEdge = true;
- edgeState = newState;
- this.CallEdgeFlag(edgeState);
- }
- }
-
- this.CallVertex(e.originVertex.clientIndex);
- e = e.nextEdgeCCWAroundLeftFace;
- } while (e != f.halfEdgeThisIsLeftFaceOf);
- }
-
- this.CallEnd();
- }
-
-
- static void RenderFan(Tesselator tess, HalfEdge e, int size)
- {
- /* Render as many CCW triangles as possible in a fan starting from
- * edge "e". The fan *should* contain exactly "size" triangles
- * (otherwise we've goofed up somewhere).
- */
- tess.CallBegin(Tesselator.TriangleListType.TriangleFan);
- tess.CallVertex(e.originVertex.clientIndex);
- tess.CallVertex(e.directionVertex.clientIndex);
- while (!e.leftFace.Marked())
- {
- e.leftFace.marked = true;
- --size;
- e = e.nextEdgeCCWAroundOrigin;
- tess.CallVertex(e.directionVertex.clientIndex);
- }
-
- if (size != 0)
- {
- throw new Exception();
- }
- tess.CallEnd();
- }
-
-
- static void RenderStrip(Tesselator tess, HalfEdge halfEdge, int size)
- {
- /* Render as many CCW triangles as possible in a strip starting from
- * edge "e". The strip *should* contain exactly "size" triangles
- * (otherwise we've goofed up somewhere).
- */
- tess.CallBegin(Tesselator.TriangleListType.TriangleStrip);
- tess.CallVertex(halfEdge.originVertex.clientIndex);
- tess.CallVertex(halfEdge.directionVertex.clientIndex);
- while (!halfEdge.leftFace.Marked())
- {
- halfEdge.leftFace.marked = true;
- --size;
- halfEdge = halfEdge.Dprev;
- tess.CallVertex(halfEdge.originVertex.clientIndex);
- if (halfEdge.leftFace.Marked()) break;
- halfEdge.leftFace.marked = true;
- --size;
- halfEdge = halfEdge.nextEdgeCCWAroundOrigin;
- tess.CallVertex(halfEdge.directionVertex.clientIndex);
- }
-
- if (size != 0)
- {
- throw new Exception();
- }
- tess.CallEnd();
- }
-
-
- /************************ Boundary contour decomposition ******************/
-
- /* Takes a mesh, and outputs one
- * contour for each face marked "inside". The rendering output is
- * provided as callbacks.
- */
- public void RenderBoundary(Mesh mesh)
- {
- for (Face curFace = mesh.faceHead.nextFace; curFace != mesh.faceHead; curFace = curFace.nextFace)
- {
- if (curFace.isInterior)
- {
- this.CallBegin(Tesselator.TriangleListType.LineLoop);
- HalfEdge curHalfEdge = curFace.halfEdgeThisIsLeftFaceOf;
- do
- {
- this.CallVertex(curHalfEdge.originVertex.clientIndex);
- curHalfEdge = curHalfEdge.nextEdgeCCWAroundLeftFace;
- } while (curHalfEdge != curFace.halfEdgeThisIsLeftFaceOf);
- this.CallEnd();
- }
- }
- }
-
-
- /************************ Quick-and-dirty decomposition ******************/
-
- const int SIGN_INCONSISTENT = 2;
- int ComputeNormal(ref double nx, ref double ny, ref double nz)
- /*
- * Check that each triangle in the fan from v0 has a
- * consistent orientation with respect to norm3[]. If triangles are
- * consistently oriented CCW, return 1; if CW, return -1; if all triangles
- * are degenerate return 0; otherwise (no consistent orientation) return
- * SIGN_INCONSISTENT.
- */
- {
- var vCache = _simpleVertexCache;
- Vertex v0 = vCache[0];
- int vcIndex;
- double dot, xc, yc, xp, yp;
- double n0;
- double n1;
- double n2;
- int sign = 0;
- /* Find the polygon normal. It is important to get a reasonable
- * normal even when the polygon is self-intersecting (eg. a bowtie).
- * Otherwise, the computed normal could be very tiny, but perpendicular
- * to the true plane of the polygon due to numerical noise. Then all
- * the triangles would appear to be degenerate and we would incorrectly
- * decompose the polygon as a fan (or simply not render it at all).
- *
- * We use a sum-of-triangles normal algorithm rather than the more
- * efficient sum-of-trapezoids method (used in CheckOrientation()
- * in normal.c). This lets us explicitly reverse the signed area
- * of some triangles to get a reasonable normal in the self-intersecting
- * case.
- */
- vcIndex = 1;
- var v = vCache[vcIndex];
- xc = v.x - v0.x;
- yc = v.y - v0.y;
- int c_count = _cacheCount;
- while (++vcIndex < c_count)
- {
- xp = xc; yp = yc;
- v = vCache[vcIndex];
- xc = v.x - v0.x;
- yc = v.y - v0.y;
- /* Compute (vp - v0) cross (vc - v0) */
- n0 = 0;
- n1 = 0;
- n2 = xp * yc - yp * xc;
- dot = n0 * nx + n1 * ny + n2 * nz;
- if (dot != 0)
- {
- /* Check the new orientation for consistency with previous triangles */
- if (dot > 0)
- {
- if (sign < 0)
- {
- return SIGN_INCONSISTENT;
- }
- sign = 1;
- }
- else
- {
- if (sign > 0)
- {
- return SIGN_INCONSISTENT;
- }
- sign = -1;
- }
- }
- }
-
- return sign;
- }
-
- /* Takes a single contour and tries to render it
- * as a triangle fan. This handles convex polygons, as well as some
- * non-convex polygons if we get lucky.
- *
- * Returns TRUE if the polygon was successfully rendered. The rendering
- * output is provided as callbacks (see the api).
- */
- public bool RenderCache()
- {
- int sign;
- if (_cacheCount < 3)
- {
- /* Degenerate contour -- no output */
- return true;
- }
- double normal_x = 0;
- double normal_y = 0;
- double normal_z = 1;
- sign = this.ComputeNormal(ref normal_x, ref normal_y, ref normal_z);
- if (sign == SIGN_INCONSISTENT)
- {
- // Fan triangles did not have a consistent orientation
- return false;
- }
- if (sign == 0)
- {
- // All triangles were degenerate
- return true;
- }
-
- /* Make sure we do the right thing for each winding rule */
- switch (_windingRule)
- {
- case Tesselator.WindingRuleType.Odd:
- case Tesselator.WindingRuleType.NonZero:
- break;
- case Tesselator.WindingRuleType.Positive:
- if (sign < 0) return true;
- break;
- case Tesselator.WindingRuleType.Negative:
- if (sign > 0) return true;
- break;
- case Tesselator.WindingRuleType.ABS_GEQ_Two:
- return true;
- }
-
- this.CallBegin(this.BoundaryOnly ? Tesselator.TriangleListType.LineLoop
- : (_cacheCount > 3) ? Tesselator.TriangleListType.TriangleFan
- : Tesselator.TriangleListType.Triangles);
- this.CallVertex(_indexCached[0]);
- if (sign > 0)
- {
- int c_count = _cacheCount;
- for (int vcIndex = 1; vcIndex < c_count; ++vcIndex)
- {
- this.CallVertex(_indexCached[vcIndex]);
- }
- }
- else
- {
- for (int vcIndex = _cacheCount - 1; vcIndex > 0; --vcIndex)
- {
- this.CallVertex(_indexCached[vcIndex]);
- }
- }
- this.CallEnd();
- return true;
- }
- }
-}
diff --git a/Demo/Shared/Tesselate/mesh.cs b/Demo/Shared/Tesselate/mesh.cs
index eb2d3a1d..134fc0ad 100644
--- a/Demo/Shared/Tesselate/mesh.cs
+++ b/Demo/Shared/Tesselate/mesh.cs
@@ -189,40 +189,40 @@ namespace Tesselate
public class Mesh
{
- public ContourVertex vertexHead = new ContourVertex(); /* dummy header for vertex list */
- public Face faceHead = new Face(); /* dummy header for face list */
- public HalfEdge halfEdgeHead = new HalfEdge(); /* dummy header for edge list */
- HalfEdge otherHalfOfThisEdgeHead = new HalfEdge(); /* and its symmetric counterpart */
+ internal ContourVertex _vertexHead = new ContourVertex(); /* dummy header for vertex list */
+ internal Face _faceHead = new Face(); /* dummy header for face list */
+ internal HalfEdge _halfEdgeHead = new HalfEdge(); /* dummy header for edge list */
+ HalfEdge _otherHalfOfThisEdgeHead = new HalfEdge(); /* and its symmetric counterpart */
/* Creates a new mesh with no edges, no vertices,
* and no loops (what we usually call a "face").
*/
public Mesh()
{
- HalfEdge otherHalfOfThisEdge = this.otherHalfOfThisEdgeHead;
- vertexHead.nextVertex = vertexHead.prevVertex = vertexHead;
- vertexHead.edgeThisIsOriginOf = null;
- vertexHead.clientIndex = 0;
- faceHead.nextFace = faceHead.prevFace = faceHead;
- faceHead.halfEdgeThisIsLeftFaceOf = null;
- faceHead.trail = null;
- faceHead.marked = false;
- faceHead.isInterior = false;
- halfEdgeHead.nextHalfEdge = halfEdgeHead;
- halfEdgeHead.otherHalfOfThisEdge = otherHalfOfThisEdge;
- halfEdgeHead.nextEdgeCCWAroundOrigin = null;
- halfEdgeHead.nextEdgeCCWAroundLeftFace = null;
- halfEdgeHead.originVertex = null;
- halfEdgeHead.leftFace = null;
- halfEdgeHead.winding = 0;
- halfEdgeHead.regionThisIsUpperEdgeOf = null;
- otherHalfOfThisEdge.nextHalfEdge = otherHalfOfThisEdge;
- otherHalfOfThisEdge.otherHalfOfThisEdge = halfEdgeHead;
- otherHalfOfThisEdge.nextEdgeCCWAroundOrigin = null;
- otherHalfOfThisEdge.nextEdgeCCWAroundLeftFace = null;
- otherHalfOfThisEdge.originVertex = null;
- otherHalfOfThisEdge.leftFace = null;
- otherHalfOfThisEdge.winding = 0;
- otherHalfOfThisEdge.regionThisIsUpperEdgeOf = null;
+ HalfEdge otherHalfOfThisEdge = _otherHalfOfThisEdgeHead;
+ _vertexHead._nextVertex = _vertexHead._prevVertex = _vertexHead;
+ _vertexHead._edgeThisIsOriginOf = null;
+ _vertexHead._clientIndex = 0;
+ _faceHead._nextFace = _faceHead._prevFace = _faceHead;
+ _faceHead._halfEdgeThisIsLeftFaceOf = null;
+ _faceHead._trail = null;
+ _faceHead._marked = false;
+ _faceHead._isInterior = false;
+ _halfEdgeHead._nextHalfEdge = _halfEdgeHead;
+ _halfEdgeHead._otherHalfOfThisEdge = otherHalfOfThisEdge;
+ _halfEdgeHead._nextEdgeCCWAroundOrigin = null;
+ _halfEdgeHead._nextEdgeCCWAroundLeftFace = null;
+ _halfEdgeHead._originVertex = null;
+ _halfEdgeHead._leftFace = null;
+ _halfEdgeHead._winding = 0;
+ _halfEdgeHead._regionThisIsUpperEdgeOf = null;
+ otherHalfOfThisEdge._nextHalfEdge = otherHalfOfThisEdge;
+ otherHalfOfThisEdge._otherHalfOfThisEdge = _halfEdgeHead;
+ otherHalfOfThisEdge._nextEdgeCCWAroundOrigin = null;
+ otherHalfOfThisEdge._nextEdgeCCWAroundLeftFace = null;
+ otherHalfOfThisEdge._originVertex = null;
+ otherHalfOfThisEdge._leftFace = null;
+ otherHalfOfThisEdge._winding = 0;
+ otherHalfOfThisEdge._regionThisIsUpperEdgeOf = null;
}
/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
@@ -231,32 +231,37 @@ public Mesh()
* the new face *before* fNext so that algorithms which walk the face
* list will not see the newly created faces.
*/
- static int faceIndex = 0;
+
+#if DEBUG
+ static int s_dbugFaceIndexTotal = 0;
+#endif
static void MakeFace(Face newFace, HalfEdge eOrig, Face fNext)
{
HalfEdge e;
Face fPrev;
Face fNew = newFace;
- fNew.indexDebug = faceIndex++;
+#if DEBUG
+ fNew.dbugIndex = s_dbugFaceIndexTotal++;
+#endif
// insert in circular doubly-linked list before fNext
- fPrev = fNext.prevFace;
- fNew.prevFace = fPrev;
- fPrev.nextFace = fNew;
- fNew.nextFace = fNext;
- fNext.prevFace = fNew;
- fNew.halfEdgeThisIsLeftFaceOf = eOrig;
- fNew.trail = null;
- fNew.marked = false;
+ fPrev = fNext._prevFace;
+ fNew._prevFace = fPrev;
+ fPrev._nextFace = fNew;
+ fNew._nextFace = fNext;
+ fNext._prevFace = fNew;
+ fNew._halfEdgeThisIsLeftFaceOf = 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.isInterior = fNext.isInterior;
+ fNew._isInterior = fNext._isInterior;
// fix other edges on this face loop
e = eOrig;
do
{
- e.leftFace = fNew;
- e = e.nextEdgeCCWAroundLeftFace;
+ e._leftFace = fNew;
+ e = e._nextEdgeCCWAroundLeftFace;
} while (e != eOrig);
}
@@ -268,10 +273,10 @@ public HalfEdge MakeEdge()
ContourVertex newVertex2 = new ContourVertex();
Face newFace = new Face();
HalfEdge e;
- e = MakeEdge(this.halfEdgeHead);
- MakeVertex(newVertex1, e, this.vertexHead);
- MakeVertex(newVertex2, e.otherHalfOfThisEdge, this.vertexHead);
- MakeFace(newFace, e, this.faceHead);
+ e = MakeEdge(_halfEdgeHead);
+ MakeVertex(newVertex1, e, _vertexHead);
+ MakeVertex(newVertex2, e._otherHalfOfThisEdge, _vertexHead);
+ MakeFace(newFace, e, _faceHead);
return e;
}
@@ -287,21 +292,21 @@ static void MakeVertex(ContourVertex newVertex, HalfEdge eOrig, ContourVertex vN
ContourVertex vPrev;
ContourVertex vNew = newVertex;
/* insert in circular doubly-linked list before vNext */
- vPrev = vNext.prevVertex;
- vNew.prevVertex = vPrev;
- vPrev.nextVertex = vNew;
- vNew.nextVertex = vNext;
- vNext.prevVertex = vNew;
- vNew.edgeThisIsOriginOf = eOrig;
- vNew.clientIndex = 0;
+ vPrev = vNext._prevVertex;
+ vNew._prevVertex = vPrev;
+ vPrev._nextVertex = vNew;
+ vNew._nextVertex = vNext;
+ vNext._prevVertex = vNew;
+ vNew._edgeThisIsOriginOf = eOrig;
+ vNew._clientIndex = 0;
/* leave coords, s, t undefined */
/* fix other edges on this vertex loop */
e = eOrig;
do
{
- e.originVertex = vNew;
- e = e.nextEdgeCCWAroundOrigin;
+ e._originVertex = vNew;
+ e = e._nextEdgeCCWAroundOrigin;
} while (e != eOrig);
}
@@ -310,20 +315,20 @@ static void MakeVertex(ContourVertex newVertex, HalfEdge eOrig, ContourVertex vN
*/
static void KillVertex(ContourVertex vDel, ContourVertex newOrg)
{
- HalfEdge e, eStart = vDel.edgeThisIsOriginOf;
+ HalfEdge e, eStart = vDel._edgeThisIsOriginOf;
ContourVertex vPrev, vNext;
/* change the origin of all affected edges */
e = eStart;
do
{
- e.originVertex = newOrg;
- e = e.nextEdgeCCWAroundOrigin;
+ e._originVertex = newOrg;
+ e = e._nextEdgeCCWAroundOrigin;
} while (e != eStart);
/* delete from circular doubly-linked list */
- vPrev = vDel.prevVertex;
- vNext = vDel.nextVertex;
- vNext.prevVertex = vPrev;
- vPrev.nextVertex = vNext;
+ vPrev = vDel._prevVertex;
+ vNext = vDel._nextVertex;
+ vNext._prevVertex = vPrev;
+ vPrev._nextVertex = vNext;
}
/* KillFace( fDel ) destroys a face and removes it from the global face
@@ -331,20 +336,20 @@ static void KillVertex(ContourVertex vDel, ContourVertex newOrg)
*/
static void KillFace(Face fDel, Face newLface)
{
- HalfEdge e, eStart = fDel.halfEdgeThisIsLeftFaceOf;
+ HalfEdge e, eStart = fDel._halfEdgeThisIsLeftFaceOf;
Face fPrev, fNext;
/* change the left face of all affected edges */
e = eStart;
do
{
- e.leftFace = newLface;
- e = e.nextEdgeCCWAroundLeftFace;
+ e._leftFace = newLface;
+ e = e._nextEdgeCCWAroundLeftFace;
} while (e != eStart);
/* delete from circular doubly-linked list */
- fPrev = fDel.prevFace;
- fNext = fDel.nextFace;
- fNext.prevFace = fPrev;
- fPrev.nextFace = fNext;
+ fPrev = fDel._prevFace;
+ fNext = fDel._nextFace;
+ fNext._prevFace = fPrev;
+ fPrev._nextFace = fNext;
}
/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
@@ -355,12 +360,12 @@ static void KillFace(Face fDel, Face newLface)
*/
static void Splice(HalfEdge a, HalfEdge b)
{
- HalfEdge aOnext = a.nextEdgeCCWAroundOrigin;
- HalfEdge bOnext = b.nextEdgeCCWAroundOrigin;
- aOnext.otherHalfOfThisEdge.nextEdgeCCWAroundLeftFace = b;
- bOnext.otherHalfOfThisEdge.nextEdgeCCWAroundLeftFace = a;
- a.nextEdgeCCWAroundOrigin = bOnext;
- b.nextEdgeCCWAroundOrigin = aOnext;
+ HalfEdge aOnext = a._nextEdgeCCWAroundOrigin;
+ HalfEdge bOnext = b._nextEdgeCCWAroundOrigin;
+ aOnext._otherHalfOfThisEdge._nextEdgeCCWAroundLeftFace = b;
+ bOnext._otherHalfOfThisEdge._nextEdgeCCWAroundLeftFace = a;
+ a._nextEdgeCCWAroundOrigin = bOnext;
+ b._nextEdgeCCWAroundOrigin = aOnext;
}
/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
@@ -391,17 +396,17 @@ public static void meshSplice(HalfEdge eOrg, HalfEdge eDst)
bool joiningLoops = false;
bool joiningVertices = false;
if (eOrg == eDst) return;
- if (eDst.originVertex != eOrg.originVertex)
+ if (eDst._originVertex != eOrg._originVertex)
{
/* We are merging two disjoint vertices -- destroy eDst.Org */
joiningVertices = true;
- KillVertex(eDst.originVertex, eOrg.originVertex);
+ KillVertex(eDst._originVertex, eOrg._originVertex);
}
- if (eDst.leftFace != eOrg.leftFace)
+ if (eDst._leftFace != eOrg._leftFace)
{
/* We are connecting two disjoint loops -- destroy eDst.Lface */
joiningLoops = true;
- KillFace(eDst.leftFace, eOrg.leftFace);
+ KillFace(eDst._leftFace, eOrg._leftFace);
}
/* Change the edge structure */
@@ -412,8 +417,8 @@ public static void meshSplice(HalfEdge eOrg, HalfEdge eDst)
/* We split one vertex into two -- the new vertex is eDst.Org.
* Make sure the old vertex points to a valid half-edge.
*/
- MakeVertex(newVertex, eDst, eOrg.originVertex);
- eOrg.originVertex.edgeThisIsOriginOf = eOrg;
+ MakeVertex(newVertex, eDst, eOrg._originVertex);
+ eOrg._originVertex._edgeThisIsOriginOf = eOrg;
}
if (!joiningLoops)
{
@@ -421,8 +426,8 @@ public static void meshSplice(HalfEdge eOrg, HalfEdge eDst)
/* We split one loop into two -- the new loop is eDst.Lface.
* Make sure the old face points to a valid half-edge.
*/
- MakeFace(newFace, eDst, eOrg.leftFace);
- eOrg.leftFace.halfEdgeThisIsLeftFaceOf = eOrg;
+ MakeFace(newFace, eDst, eOrg._leftFace);
+ eOrg._leftFace._halfEdgeThisIsLeftFaceOf = eOrg;
}
}
@@ -433,16 +438,16 @@ static void KillEdge(HalfEdge eDel)
{
HalfEdge ePrev, eNext;
/* Half-edges are allocated in pairs, see EdgePair above */
- if (eDel.otherHalfOfThisEdge.isFirstHalfEdge)
+ if (eDel._otherHalfOfThisEdge._isFirstHalfEdge)
{
- eDel = eDel.otherHalfOfThisEdge;
+ eDel = eDel._otherHalfOfThisEdge;
}
/* delete from circular doubly-linked list */
- eNext = eDel.nextHalfEdge;
- ePrev = eDel.otherHalfOfThisEdge.nextHalfEdge;
- eNext.otherHalfOfThisEdge.nextHalfEdge = ePrev;
- ePrev.otherHalfOfThisEdge.nextHalfEdge = eNext;
+ eNext = eDel._nextHalfEdge;
+ ePrev = eDel._otherHalfOfThisEdge._nextHalfEdge;
+ eNext._otherHalfOfThisEdge._nextHalfEdge = ePrev;
+ ePrev._otherHalfOfThisEdge._nextHalfEdge = eNext;
}
/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
@@ -457,47 +462,47 @@ static void KillEdge(HalfEdge eDel)
*/
public static void DeleteHalfEdge(HalfEdge edgeToDelete)
{
- HalfEdge otherHalfOfEdgeToDelete = edgeToDelete.otherHalfOfThisEdge;
+ HalfEdge otherHalfOfEdgeToDelete = edgeToDelete._otherHalfOfThisEdge;
bool joiningLoops = false;
// First step: disconnect the origin vertex eDel.Org. We make all
// changes to get a consistent mesh in this "intermediate" state.
- if (edgeToDelete.leftFace != edgeToDelete.rightFace)
+ if (edgeToDelete._leftFace != edgeToDelete.rightFace)
{
// We are joining two loops into one -- remove the left face
joiningLoops = true;
- KillFace(edgeToDelete.leftFace, edgeToDelete.rightFace);
+ KillFace(edgeToDelete._leftFace, edgeToDelete.rightFace);
}
- if (edgeToDelete.nextEdgeCCWAroundOrigin == edgeToDelete)
+ if (edgeToDelete._nextEdgeCCWAroundOrigin == edgeToDelete)
{
- KillVertex(edgeToDelete.originVertex, null);
+ KillVertex(edgeToDelete._originVertex, null);
}
else
{
// Make sure that eDel.Org and eDel.Rface point to valid half-edges
- edgeToDelete.rightFace.halfEdgeThisIsLeftFaceOf = edgeToDelete.Oprev;
- edgeToDelete.originVertex.edgeThisIsOriginOf = edgeToDelete.nextEdgeCCWAroundOrigin;
+ edgeToDelete.rightFace._halfEdgeThisIsLeftFaceOf = edgeToDelete.Oprev;
+ edgeToDelete._originVertex._edgeThisIsOriginOf = edgeToDelete._nextEdgeCCWAroundOrigin;
Splice(edgeToDelete, edgeToDelete.Oprev);
if (!joiningLoops)
{
Face newFace = new Face();
// We are splitting one loop into two -- create a new loop for eDel.
- MakeFace(newFace, edgeToDelete, edgeToDelete.leftFace);
+ MakeFace(newFace, edgeToDelete, edgeToDelete._leftFace);
}
}
// Claim: the mesh is now in a consistent state, except that eDel.Org
// may have been deleted. Now we disconnect eDel.Dst.
- if (otherHalfOfEdgeToDelete.nextEdgeCCWAroundOrigin == otherHalfOfEdgeToDelete)
+ if (otherHalfOfEdgeToDelete._nextEdgeCCWAroundOrigin == otherHalfOfEdgeToDelete)
{
- KillVertex(otherHalfOfEdgeToDelete.originVertex, null);
- KillFace(otherHalfOfEdgeToDelete.leftFace, null);
+ KillVertex(otherHalfOfEdgeToDelete._originVertex, null);
+ KillFace(otherHalfOfEdgeToDelete._leftFace, null);
}
else
{
// Make sure that eDel.Dst and eDel.Lface point to valid half-edges
- edgeToDelete.leftFace.halfEdgeThisIsLeftFaceOf = otherHalfOfEdgeToDelete.Oprev;
- otherHalfOfEdgeToDelete.originVertex.edgeThisIsOriginOf = otherHalfOfEdgeToDelete.nextEdgeCCWAroundOrigin;
+ edgeToDelete._leftFace._halfEdgeThisIsLeftFaceOf = otherHalfOfEdgeToDelete.Oprev;
+ otherHalfOfEdgeToDelete._originVertex._edgeThisIsOriginOf = otherHalfOfEdgeToDelete._nextEdgeCCWAroundOrigin;
Splice(otherHalfOfEdgeToDelete, otherHalfOfEdgeToDelete.Oprev);
}
@@ -513,16 +518,16 @@ static HalfEdge meshAddEdgeVertex(HalfEdge eOrg)
{
HalfEdge eNewSym;
HalfEdge eNew = MakeEdge(eOrg);
- eNewSym = eNew.otherHalfOfThisEdge;
+ eNewSym = eNew._otherHalfOfThisEdge;
/* Connect the new edge appropriately */
- Splice(eNew, eOrg.nextEdgeCCWAroundLeftFace);
+ Splice(eNew, eOrg._nextEdgeCCWAroundLeftFace);
/* Set the vertex and face information */
- eNew.originVertex = eOrg.directionVertex;
+ eNew._originVertex = eOrg.DirectionVertex;
{
ContourVertex newVertex = new ContourVertex();
- MakeVertex(newVertex, eNewSym, eNew.originVertex);
+ MakeVertex(newVertex, eNewSym, eNew._originVertex);
}
- eNew.leftFace = eNewSym.leftFace = eOrg.leftFace;
+ eNew._leftFace = eNewSym._leftFace = eOrg._leftFace;
return eNew;
}
@@ -534,16 +539,16 @@ public static HalfEdge meshSplitEdge(HalfEdge eOrg)
{
HalfEdge eNew;
HalfEdge tempHalfEdge = meshAddEdgeVertex(eOrg);
- eNew = tempHalfEdge.otherHalfOfThisEdge;
+ eNew = tempHalfEdge._otherHalfOfThisEdge;
/* Disconnect eOrg from eOrg.Dst and connect it to eNew.Org */
- Splice(eOrg.otherHalfOfThisEdge, eOrg.otherHalfOfThisEdge.Oprev);
- Splice(eOrg.otherHalfOfThisEdge, eNew);
+ Splice(eOrg._otherHalfOfThisEdge, eOrg._otherHalfOfThisEdge.Oprev);
+ Splice(eOrg._otherHalfOfThisEdge, eNew);
/* Set the vertex and face information */
- eOrg.directionVertex = eNew.originVertex;
- eNew.directionVertex.edgeThisIsOriginOf = eNew.otherHalfOfThisEdge; /* may have pointed to eOrg.Sym */
+ eOrg.DirectionVertex = eNew._originVertex;
+ eNew.DirectionVertex._edgeThisIsOriginOf = eNew._otherHalfOfThisEdge; /* may have pointed to eOrg.Sym */
eNew.rightFace = eOrg.rightFace;
- eNew.winding = eOrg.winding; /* copy old winding information */
- eNew.otherHalfOfThisEdge.winding = eOrg.otherHalfOfThisEdge.winding;
+ eNew._winding = eOrg._winding; /* copy old winding information */
+ eNew._otherHalfOfThisEdge._winding = eOrg._otherHalfOfThisEdge._winding;
return eNew;
}
@@ -574,35 +579,35 @@ static HalfEdge MakeEdge(HalfEdge eNext)
HalfEdge ePrev;
EdgePair pair = new EdgePair();
/* Make sure eNext points to the first edge of the edge pair */
- if (eNext.otherHalfOfThisEdge.isFirstHalfEdge)
+ if (eNext._otherHalfOfThisEdge._isFirstHalfEdge)
{
- eNext = eNext.otherHalfOfThisEdge;
+ eNext = eNext._otherHalfOfThisEdge;
}
/* Insert in circular doubly-linked list before eNext.
* Note that the prev pointer is stored in Sym.next.
*/
- ePrev = eNext.otherHalfOfThisEdge.nextHalfEdge;
- pair.eSym.nextHalfEdge = ePrev;
- ePrev.otherHalfOfThisEdge.nextHalfEdge = pair.e;
- pair.e.nextHalfEdge = eNext;
- eNext.otherHalfOfThisEdge.nextHalfEdge = pair.eSym;
- pair.e.isFirstHalfEdge = true;
- pair.e.otherHalfOfThisEdge = pair.eSym;
- pair.e.nextEdgeCCWAroundOrigin = pair.e;
- pair.e.nextEdgeCCWAroundLeftFace = pair.eSym;
- pair.e.originVertex = null;
- pair.e.leftFace = null;
- pair.e.winding = 0;
- pair.e.regionThisIsUpperEdgeOf = null;
- pair.eSym.isFirstHalfEdge = false;
- pair.eSym.otherHalfOfThisEdge = pair.e;
- pair.eSym.nextEdgeCCWAroundOrigin = pair.eSym;
- pair.eSym.nextEdgeCCWAroundLeftFace = pair.e;
- pair.eSym.originVertex = null;
- pair.eSym.leftFace = null;
- pair.eSym.winding = 0;
- pair.eSym.regionThisIsUpperEdgeOf = null;
+ ePrev = eNext._otherHalfOfThisEdge._nextHalfEdge;
+ pair.eSym._nextHalfEdge = ePrev;
+ ePrev._otherHalfOfThisEdge._nextHalfEdge = pair.e;
+ pair.e._nextHalfEdge = eNext;
+ eNext._otherHalfOfThisEdge._nextHalfEdge = pair.eSym;
+ pair.e._isFirstHalfEdge = true;
+ pair.e._otherHalfOfThisEdge = pair.eSym;
+ pair.e._nextEdgeCCWAroundOrigin = pair.e;
+ pair.e._nextEdgeCCWAroundLeftFace = pair.eSym;
+ pair.e._originVertex = null;
+ pair.e._leftFace = null;
+ pair.e._winding = 0;
+ pair.e._regionThisIsUpperEdgeOf = null;
+ pair.eSym._isFirstHalfEdge = false;
+ pair.eSym._otherHalfOfThisEdge = pair.e;
+ pair.eSym._nextEdgeCCWAroundOrigin = pair.eSym;
+ pair.eSym._nextEdgeCCWAroundLeftFace = pair.e;
+ pair.eSym._originVertex = null;
+ pair.eSym._leftFace = null;
+ pair.eSym._winding = 0;
+ pair.eSym._regionThisIsUpperEdgeOf = null;
return pair.e;
}
@@ -621,28 +626,28 @@ public static HalfEdge meshConnect(HalfEdge eOrg, HalfEdge eDst)
HalfEdge eNewSym;
bool joiningLoops = false;
HalfEdge eNew = MakeEdge(eOrg);
- eNewSym = eNew.otherHalfOfThisEdge;
- if (eDst.leftFace != eOrg.leftFace)
+ eNewSym = eNew._otherHalfOfThisEdge;
+ if (eDst._leftFace != eOrg._leftFace)
{
/* We are connecting two disjoint loops -- destroy eDst.Lface */
joiningLoops = true;
- KillFace(eDst.leftFace, eOrg.leftFace);
+ KillFace(eDst._leftFace, eOrg._leftFace);
}
/* Connect the new edge appropriately */
- Splice(eNew, eOrg.nextEdgeCCWAroundLeftFace);
+ Splice(eNew, eOrg._nextEdgeCCWAroundLeftFace);
Splice(eNewSym, eDst);
/* Set the vertex and face information */
- eNew.originVertex = eOrg.directionVertex;
- eNewSym.originVertex = eDst.originVertex;
- eNew.leftFace = eNewSym.leftFace = eOrg.leftFace;
+ eNew._originVertex = eOrg.DirectionVertex;
+ eNewSym._originVertex = eDst._originVertex;
+ eNew._leftFace = eNewSym._leftFace = eOrg._leftFace;
/* Make sure the old face points to a valid half-edge */
- eOrg.leftFace.halfEdgeThisIsLeftFaceOf = eNewSym;
+ eOrg._leftFace._halfEdgeThisIsLeftFaceOf = eNewSym;
if (!joiningLoops)
{
Face newFace = new Face();
/* We split one loop into two -- the new loop is eNew.Lface */
- MakeFace(newFace, eNew, eOrg.leftFace);
+ MakeFace(newFace, eNew, eOrg._leftFace);
}
return eNew;
}
@@ -652,35 +657,35 @@ public static HalfEdge meshConnect(HalfEdge eOrg, HalfEdge eDst)
*/
Mesh meshUnion(Mesh mesh1, Mesh mesh2)
{
- Face f1 = mesh1.faceHead;
- ContourVertex v1 = mesh1.vertexHead;
- HalfEdge e1 = mesh1.halfEdgeHead;
- Face f2 = mesh2.faceHead;
- ContourVertex v2 = mesh2.vertexHead;
- HalfEdge e2 = mesh2.halfEdgeHead;
+ Face f1 = mesh1._faceHead;
+ ContourVertex v1 = mesh1._vertexHead;
+ HalfEdge e1 = mesh1._halfEdgeHead;
+ Face f2 = mesh2._faceHead;
+ ContourVertex v2 = mesh2._vertexHead;
+ HalfEdge e2 = mesh2._halfEdgeHead;
/* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
- if (f2.nextFace != f2)
+ if (f2._nextFace != f2)
{
- f1.prevFace.nextFace = f2.nextFace;
- f2.nextFace.prevFace = f1.prevFace;
- f2.prevFace.nextFace = f1;
- f1.prevFace = f2.prevFace;
+ f1._prevFace._nextFace = f2._nextFace;
+ f2._nextFace._prevFace = f1._prevFace;
+ f2._prevFace._nextFace = f1;
+ f1._prevFace = f2._prevFace;
}
- if (v2.nextVertex != v2)
+ if (v2._nextVertex != v2)
{
- v1.prevVertex.nextVertex = v2.nextVertex;
- v2.nextVertex.prevVertex = v1.prevVertex;
- v2.prevVertex.nextVertex = v1;
- v1.prevVertex = v2.prevVertex;
+ v1._prevVertex._nextVertex = v2._nextVertex;
+ v2._nextVertex._prevVertex = v1._prevVertex;
+ v2._prevVertex._nextVertex = v1;
+ v1._prevVertex = v2._prevVertex;
}
- if (e2.nextHalfEdge != e2)
+ if (e2._nextHalfEdge != e2)
{
- e1.otherHalfOfThisEdge.nextHalfEdge.otherHalfOfThisEdge.nextHalfEdge = e2.nextHalfEdge;
- e2.nextHalfEdge.otherHalfOfThisEdge.nextHalfEdge = e1.otherHalfOfThisEdge.nextHalfEdge;
- e2.otherHalfOfThisEdge.nextHalfEdge.otherHalfOfThisEdge.nextHalfEdge = e1;
- e1.otherHalfOfThisEdge.nextHalfEdge = e2.otherHalfOfThisEdge.nextHalfEdge;
+ e1._otherHalfOfThisEdge._nextHalfEdge._otherHalfOfThisEdge._nextHalfEdge = e2._nextHalfEdge;
+ e2._nextHalfEdge._otherHalfOfThisEdge._nextHalfEdge = e1._otherHalfOfThisEdge._nextHalfEdge;
+ e2._otherHalfOfThisEdge._nextHalfEdge._otherHalfOfThisEdge._nextHalfEdge = e1;
+ e1._otherHalfOfThisEdge._nextHalfEdge = e2._otherHalfOfThisEdge._nextHalfEdge;
}
mesh2 = null;
@@ -696,49 +701,49 @@ Mesh meshUnion(Mesh mesh1, Mesh mesh2)
*/
public static void meshZapFace(Face fZap)
{
- HalfEdge eStart = fZap.halfEdgeThisIsLeftFaceOf;
+ HalfEdge eStart = fZap._halfEdgeThisIsLeftFaceOf;
HalfEdge e, eNext, eSym;
Face fPrev, fNext;
/* walk around face, deleting edges whose right face is also null */
- eNext = eStart.nextEdgeCCWAroundLeftFace;
+ eNext = eStart._nextEdgeCCWAroundLeftFace;
do
{
e = eNext;
- eNext = e.nextEdgeCCWAroundLeftFace;
- e.leftFace = null;
+ eNext = e._nextEdgeCCWAroundLeftFace;
+ e._leftFace = null;
if (e.rightFace == null)
{
/* delete the edge -- see __gl_MeshDelete above */
- if (e.nextEdgeCCWAroundOrigin == e)
+ if (e._nextEdgeCCWAroundOrigin == e)
{
- KillVertex(e.originVertex, null);
+ KillVertex(e._originVertex, null);
}
else
{
/* Make sure that e.Org points to a valid half-edge */
- e.originVertex.edgeThisIsOriginOf = e.nextEdgeCCWAroundOrigin;
+ e._originVertex._edgeThisIsOriginOf = e._nextEdgeCCWAroundOrigin;
Splice(e, e.Oprev);
}
- eSym = e.otherHalfOfThisEdge;
- if (eSym.nextEdgeCCWAroundOrigin == eSym)
+ eSym = e._otherHalfOfThisEdge;
+ if (eSym._nextEdgeCCWAroundOrigin == eSym)
{
- KillVertex(eSym.originVertex, null);
+ KillVertex(eSym._originVertex, null);
}
else
{
/* Make sure that eSym.Org points to a valid half-edge */
- eSym.originVertex.edgeThisIsOriginOf = eSym.nextEdgeCCWAroundOrigin;
+ eSym._originVertex._edgeThisIsOriginOf = eSym._nextEdgeCCWAroundOrigin;
Splice(eSym, eSym.Oprev);
}
KillEdge(e);
}
} while (e != eStart);
/* delete from circular doubly-linked list */
- fPrev = fZap.prevFace;
- fNext = fZap.nextFace;
- fNext.prevFace = fPrev;
- fPrev.nextFace = fNext;
+ fPrev = fZap._prevFace;
+ fNext = fZap._nextFace;
+ fNext._prevFace = fPrev;
+ fPrev._nextFace = fNext;
fZap = null;
}
@@ -746,125 +751,125 @@ public static void meshZapFace(Face fZap)
*/
public void CheckMesh()
{
- Face fHead = this.faceHead;
- ContourVertex vHead = this.vertexHead;
- HalfEdge eHead = this.halfEdgeHead;
+ Face fHead = _faceHead;
+ ContourVertex vHead = _vertexHead;
+ HalfEdge eHead = _halfEdgeHead;
Face f, fPrev;
ContourVertex v, vPrev;
HalfEdge e, ePrev;
fPrev = fHead;
- for (fPrev = fHead; (f = fPrev.nextFace) != fHead; fPrev = f)
+ for (fPrev = fHead; (f = fPrev._nextFace) != fHead; fPrev = f)
{
- if (f.prevFace != fPrev)
+ if (f._prevFace != fPrev)
{
throw new Exception();
}
- e = f.halfEdgeThisIsLeftFaceOf;
+ e = f._halfEdgeThisIsLeftFaceOf;
do
{
- if (e.otherHalfOfThisEdge == e)
+ if (e._otherHalfOfThisEdge == e)
{
throw new Exception();
}
- if (e.otherHalfOfThisEdge.otherHalfOfThisEdge != e)
+ if (e._otherHalfOfThisEdge._otherHalfOfThisEdge != e)
{
throw new Exception();
}
- if (e.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundOrigin.otherHalfOfThisEdge != e)
+ if (e._nextEdgeCCWAroundLeftFace._nextEdgeCCWAroundOrigin._otherHalfOfThisEdge != e)
{
throw new Exception();
}
- if (e.nextEdgeCCWAroundOrigin.otherHalfOfThisEdge.nextEdgeCCWAroundLeftFace != e)
+ if (e._nextEdgeCCWAroundOrigin._otherHalfOfThisEdge._nextEdgeCCWAroundLeftFace != e)
{
throw new Exception();
}
- if (e.leftFace != f)
+ if (e._leftFace != f)
{
throw new Exception();
}
- e = e.nextEdgeCCWAroundLeftFace;
- } while (e != f.halfEdgeThisIsLeftFaceOf);
+ e = e._nextEdgeCCWAroundLeftFace;
+ } while (e != f._halfEdgeThisIsLeftFaceOf);
}
- if (f.prevFace != fPrev || f.halfEdgeThisIsLeftFaceOf != null)
+ if (f._prevFace != fPrev || f._halfEdgeThisIsLeftFaceOf != null)
{
throw new Exception();
}
vPrev = vHead;
- for (vPrev = vHead; (v = vPrev.nextVertex) != vHead; vPrev = v)
+ for (vPrev = vHead; (v = vPrev._nextVertex) != vHead; vPrev = v)
{
- if (v.prevVertex != vPrev)
+ if (v._prevVertex != vPrev)
{
throw new Exception();
}
- e = v.edgeThisIsOriginOf;
+ e = v._edgeThisIsOriginOf;
do
{
- if (e.otherHalfOfThisEdge == e)
+ if (e._otherHalfOfThisEdge == e)
{
throw new Exception();
}
- if (e.otherHalfOfThisEdge.otherHalfOfThisEdge != e)
+ if (e._otherHalfOfThisEdge._otherHalfOfThisEdge != e)
{
throw new Exception();
}
- if (e.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundOrigin.otherHalfOfThisEdge != e)
+ if (e._nextEdgeCCWAroundLeftFace._nextEdgeCCWAroundOrigin._otherHalfOfThisEdge != e)
{
throw new Exception();
}
- if (e.nextEdgeCCWAroundOrigin.otherHalfOfThisEdge.nextEdgeCCWAroundLeftFace != e)
+ if (e._nextEdgeCCWAroundOrigin._otherHalfOfThisEdge._nextEdgeCCWAroundLeftFace != e)
{
throw new Exception();
}
- if (e.originVertex != v)
+ if (e._originVertex != v)
{
throw new Exception();
}
- e = e.nextEdgeCCWAroundOrigin;
- } while (e != v.edgeThisIsOriginOf);
+ e = e._nextEdgeCCWAroundOrigin;
+ } while (e != v._edgeThisIsOriginOf);
}
- if (v.prevVertex != vPrev || v.edgeThisIsOriginOf != null || v.clientIndex != 0)
+ if (v._prevVertex != vPrev || v._edgeThisIsOriginOf != null || v._clientIndex != 0)
{
throw new Exception();
}
ePrev = eHead;
- for (ePrev = eHead; (e = ePrev.nextHalfEdge) != eHead; ePrev = e)
+ for (ePrev = eHead; (e = ePrev._nextHalfEdge) != eHead; ePrev = e)
{
- if (e.otherHalfOfThisEdge.nextHalfEdge != ePrev.otherHalfOfThisEdge)
+ if (e._otherHalfOfThisEdge._nextHalfEdge != ePrev._otherHalfOfThisEdge)
{
throw new Exception();
}
- if (e.otherHalfOfThisEdge == e)
+ if (e._otherHalfOfThisEdge == e)
{
throw new Exception();
}
- if (e.otherHalfOfThisEdge.otherHalfOfThisEdge != e)
+ if (e._otherHalfOfThisEdge._otherHalfOfThisEdge != e)
{
throw new Exception();
}
- if (e.originVertex == null)
+ if (e._originVertex == null)
{
throw new Exception();
}
- if (e.directionVertex == null)
+ if (e.DirectionVertex == null)
{
throw new Exception();
}
- if (e.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundOrigin.otherHalfOfThisEdge != e)
+ if (e._nextEdgeCCWAroundLeftFace._nextEdgeCCWAroundOrigin._otherHalfOfThisEdge != e)
{
throw new Exception();
}
- if (e.nextEdgeCCWAroundOrigin.otherHalfOfThisEdge.nextEdgeCCWAroundLeftFace != e)
+ if (e._nextEdgeCCWAroundOrigin._otherHalfOfThisEdge._nextEdgeCCWAroundLeftFace != e)
{
throw new Exception();
}
}
- if (e.otherHalfOfThisEdge.nextHalfEdge != ePrev.otherHalfOfThisEdge
- || e.otherHalfOfThisEdge != this.otherHalfOfThisEdgeHead
- || e.otherHalfOfThisEdge.otherHalfOfThisEdge != e
- || e.originVertex != null || e.directionVertex != null
- || e.leftFace != null || e.rightFace != null)
+ if (e._otherHalfOfThisEdge._nextHalfEdge != ePrev._otherHalfOfThisEdge
+ || e._otherHalfOfThisEdge != _otherHalfOfThisEdgeHead
+ || e._otherHalfOfThisEdge._otherHalfOfThisEdge != e
+ || e._originVertex != null || e.DirectionVertex != null
+ || e._leftFace != null || e.rightFace != null)
{
throw new Exception();
}
@@ -881,20 +886,20 @@ public void CheckMesh()
public bool SetWindingNumber(int value, bool keepOnlyBoundary)
{
HalfEdge e, eNext;
- for (e = this.halfEdgeHead.nextHalfEdge; e != this.halfEdgeHead; e = eNext)
+ for (e = _halfEdgeHead._nextHalfEdge; e != _halfEdgeHead; e = eNext)
{
- eNext = e.nextHalfEdge;
- if (e.rightFace.isInterior != e.leftFace.isInterior)
+ eNext = e._nextHalfEdge;
+ if (e.rightFace._isInterior != e._leftFace._isInterior)
{
/* This is a boundary edge (one side is interior, one is exterior). */
- e.winding = (e.leftFace.isInterior) ? value : -value;
+ e._winding = (e._leftFace._isInterior) ? value : -value;
}
else
{
/* Both regions are interior, or both are exterior. */
if (!keepOnlyBoundary)
{
- e.winding = 0;
+ e._winding = 0;
}
else
{
@@ -914,11 +919,11 @@ public bool SetWindingNumber(int value, bool keepOnlyBoundary)
public void DiscardExterior()
{
Face f, next;
- for (f = this.faceHead.nextFace; f != this.faceHead; f = next)
+ for (f = _faceHead._nextFace; f != _faceHead; f = next)
{
/* Since f will be destroyed, save its next pointer. */
- next = f.nextFace;
- if (!f.isInterior)
+ next = f._nextFace;
+ if (!f._isInterior)
{
Mesh.meshZapFace(f);
}
@@ -932,11 +937,11 @@ public void DiscardExterior()
public bool TessellateInterior()
{
Face f, next;
- for (f = this.faceHead.nextFace; f != this.faceHead; f = next)
+ for (f = _faceHead._nextFace; f != _faceHead; f = next)
{
/* Make sure we don''t try to tessellate the new triangles. */
- next = f.nextFace;
- if (f.isInterior)
+ next = f._nextFace;
+ if (f._isInterior)
{
if (!f.TessellateMonoRegion())
{
diff --git a/Demo/Windows/GlyphTess.WinForms/Form1.cs b/Demo/Windows/GlyphTess.WinForms/Form1.cs
index cb9d8137..e05ddc94 100644
--- a/Demo/Windows/GlyphTess.WinForms/Form1.cs
+++ b/Demo/Windows/GlyphTess.WinForms/Form1.cs
@@ -11,7 +11,7 @@
using DrawingGL;
using DrawingGL.Text;
//
-
+using Tesselate;
namespace Test_WinForm_TessGlyph
{
@@ -187,8 +187,8 @@ void DrawOutput()
{
//extra coord (newly created)
TessVertex2d extraVertex = tempVertexList[index - orgVertexCount];
- vtx[n] = (float)extraVertex.m_X;
- vtx[n + 1] = (float)extraVertex.m_Y;
+ vtx[n] = (float)extraVertex.x;
+ vtx[n + 1] = (float)extraVertex.y;
}
else
{
diff --git a/Demo/Windows/GlyphTess.WinForms/GlyphTess.WinForms.csproj b/Demo/Windows/GlyphTess.WinForms/GlyphTess.WinForms.csproj
index 87b06239..cf350c20 100644
--- a/Demo/Windows/GlyphTess.WinForms/GlyphTess.WinForms.csproj
+++ b/Demo/Windows/GlyphTess.WinForms/GlyphTess.WinForms.csproj
@@ -78,9 +78,6 @@
Tess\mesh.cs
-
- Tess\Tesselator.cs
-
Form