sector triangulator changes

This commit is contained in:
codeimp 2008-10-07 05:50:39 +00:00
parent 2dd337cffa
commit 46935a6132
16 changed files with 285 additions and 167 deletions

View file

@ -117,7 +117,7 @@
<Compile Include="Geometry\LinedefsTracePath.cs" />
<Compile Include="Geometry\LinedefAngleSorter.cs" />
<Compile Include="Geometry\Tools.cs" />
<Compile Include="Geometry\Triangulator.cs" />
<Compile Include="Geometry\Triangulation.cs" />
<Compile Include="Geometry\EarClipVertex.cs" />
<Compile Include="Geometry\Line2D.cs" />
<Compile Include="Geometry\EarClipPolygon.cs" />

View file

@ -153,7 +153,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
*/
// Render the geometry
renderer.RenderGeometry(s.Vertices, null, true);
renderer.RenderGeometry(s.FlatVertices, null, true);
}
if(selecting) RenderMultiSelection();

View file

@ -596,7 +596,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
// Make polygon
LinedefTracePath tracepath = new LinedefTracePath(pathlines);
EarClipPolygon pathpoly = tracepath.MakePolygon();
EarClipPolygon pathpoly = tracepath.MakePolygon(true);
// Check if the front of the line is outside the polygon
if(!pathpoly.Intersect(ld.GetSidePoint(true)))
@ -611,7 +611,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
// Make polygon
tracepath = new LinedefTracePath(pathlines);
pathpoly = tracepath.MakePolygon();
pathpoly = tracepath.MakePolygon(true);
// Check if the back of the line is inside the polygon
if(pathpoly.Intersect(ld.GetSidePoint(false)))

View file

@ -295,8 +295,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Quickly flash this sector to indicate it was created
General.Map.IsChanged = true;
General.Map.Map.Update();
flashpolygon = new FlatVertex[s.Vertices.Length];
s.Vertices.CopyTo(flashpolygon, 0);
flashpolygon = new FlatVertex[s.FlatVertices.Length];
s.FlatVertices.CopyTo(flashpolygon, 0);
flashintensity = 1.0f;
flashstarttime = (double)General.Clock.GetCurrentTime();
General.Interface.SetProcessorState(true);
@ -344,8 +344,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Quickly flash this sector to indicate it was created
General.Map.IsChanged = true;
General.Map.Map.Update();
flashpolygon = new FlatVertex[s.Vertices.Length];
s.Vertices.CopyTo(flashpolygon, 0);
flashpolygon = new FlatVertex[s.FlatVertices.Length];
s.FlatVertices.CopyTo(flashpolygon, 0);
flashintensity = 1.0f;
flashstarttime = (double)General.Clock.GetCurrentTime();
General.Interface.SetProcessorState(true);

View file

@ -54,6 +54,9 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Highlighted item
private Sector highlighted;
// Labels
private ICollection<Vector2D> labelpos;
#endregion
@ -138,6 +141,18 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
renderer.Finish();
}
// Render labels
if(renderer.StartOverlay(true))
{
if(labelpos != null)
{
foreach(Vector2D v in labelpos)
renderer.RenderRectangleFilled(new RectangleF(v.x - 5, v.y - 5, 10, 10), General.Colors.Indication, true);
}
renderer.Finish();
}
// Do not show things
if(renderer.StartThings(true))
{
@ -160,15 +175,31 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Set new highlight
highlighted = s;
// Get label positions
if(s != null) labelpos = Tools.FindLabelPositions(s);
// Render highlighted item
if((highlighted != null) && !highlighted.IsDisposed)
renderer.PlotSector(highlighted, General.Colors.Highlight);
// Done
renderer.Finish();
renderer.Present();
}
// Render labels
if(renderer.StartOverlay(true))
{
if(labelpos != null)
{
foreach(Vector2D v in labelpos)
renderer.RenderRectangleFilled(new RectangleF(v.x - 5, v.y - 5, 10, 10), General.Colors.Indication, true);
}
renderer.Finish();
}
renderer.Present();
// Show highlight info
if((highlighted != null) && !highlighted.IsDisposed)
General.Interface.ShowSectorInfo(highlighted);
@ -271,83 +302,28 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Item highlighted?
if((highlighted != null) && !highlighted.IsDisposed)
{
// Edit button is used?
if(General.Interface.CheckActionActive(null, "classicedit"))
// Get a triangulator and bind events
Triangulation t = Triangulation.Create(highlighted);
// Start with a clear display
if(renderer.StartPlotter(true))
{
// Anything selected?
selected = General.Map.Map.GetSelectedSectors(true);
if(selected.Count > 0)
// Render lines and vertices
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
renderer.PlotVerticesSet(General.Map.Map.Vertices);
// Go for all triangle vertices
for(int i = 0; i < t.Vertices.Length; i += 3)
{
// Remove highlight
Highlight(null);
// Clear selection
General.Map.Map.ClearSelectedSectors();
General.Map.Map.ClearSelectedLinedefs();
General.Interface.RedrawDisplay();
// Get a triangulator and bind events
Triangulator t = new Triangulator();
t.OnShowLine = new Triangulator.ShowLine(ShowLine);
t.OnShowPolygon = new Triangulator.ShowPolygon(ShowPolygon);
t.OnShowPoint = new Triangulator.ShowPoint(ShowPoint);
t.OnShowEarClip = new Triangulator.ShowEarClip(ShowEarClip);
// Triangulate this now!
triangles = t.PerformTriangulation(General.GetByIndex<Sector>(selected, 0));
// Start with a clear display
if(renderer.StartPlotter(true))
{
// Render lines and vertices
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
renderer.PlotVerticesSet(General.Map.Map.Vertices);
// Go for all triangle vertices
for(int i = 0; i < triangles.Count; i += 3)
{
renderer.PlotLine(triangles[i + 0], triangles[i + 1], General.Colors.Selection);
renderer.PlotLine(triangles[i + 1], triangles[i + 2], General.Colors.Selection);
renderer.PlotLine(triangles[i + 2], triangles[i + 0], General.Colors.Selection);
}
// Done
renderer.Finish();
renderer.Present();
Thread.Sleep(200);
}
renderer.PlotLine(t.Vertices[i + 0], t.Vertices[i + 1], General.Colors.Selection);
renderer.PlotLine(t.Vertices[i + 1], t.Vertices[i + 2], General.Colors.Selection);
renderer.PlotLine(t.Vertices[i + 2], t.Vertices[i + 0], General.Colors.Selection);
}
}
else
{
// Get a triangulator and bind events
Triangulator t = new Triangulator();
// Triangulate the whole map!
triangles = new TriangleList();
foreach(Sector s in General.Map.Map.Sectors)
triangles.AddRange(t.PerformTriangulation(s));
// Start with a clear display
if(renderer.StartPlotter(true))
{
// Render lines and vertices
renderer.PlotLinedefSet(General.Map.Map.Linedefs);
renderer.PlotVerticesSet(General.Map.Map.Vertices);
// Go for all triangle vertices
for(int i = 0; i < triangles.Count; i += 3)
{
renderer.PlotLine(triangles[i + 0], triangles[i + 1], General.Colors.Selection);
renderer.PlotLine(triangles[i + 1], triangles[i + 2], General.Colors.Selection);
renderer.PlotLine(triangles[i + 2], triangles[i + 0], General.Colors.Selection);
}
// Done
renderer.Finish();
renderer.Present();
Thread.Sleep(200);
}
// Done
renderer.Finish();
renderer.Present();
Thread.Sleep(200);
}
}
}

View file

@ -64,8 +64,8 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture);
// Make vertices
verts = new WorldVertex[s.Vertices.Length];
for(int i = 0; i < s.Vertices.Length; i++)
verts = new WorldVertex[s.Triangles.Vertices.Length];
for(int i = 0; i < s.Triangles.Vertices.Length; i++)
{
// Use sector brightness for color shading
PixelColor pc = new PixelColor(255, unchecked((byte)s.Brightness), unchecked((byte)s.Brightness), unchecked((byte)s.Brightness));
@ -75,18 +75,18 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Grid aligned texture coordinates
if(base.Texture.IsImageLoaded)
{
verts[i].u = s.Vertices[i].x / base.Texture.ScaledWidth;
verts[i].v = s.Vertices[i].y / base.Texture.ScaledHeight;
verts[i].u = s.Triangles.Vertices[i].x / base.Texture.ScaledWidth;
verts[i].v = s.Triangles.Vertices[i].y / base.Texture.ScaledHeight;
}
else
{
verts[i].u = s.Vertices[i].x / 64;
verts[i].v = s.Vertices[i].y / 64;
verts[i].u = s.Triangles.Vertices[i].x / 64;
verts[i].v = s.Triangles.Vertices[i].y / 64;
}
// Vertex coordinates
verts[i].x = s.Vertices[i].x;
verts[i].y = s.Vertices[i].y;
verts[i].x = s.Triangles.Vertices[i].x;
verts[i].y = s.Triangles.Vertices[i].y;
verts[i].z = (float)s.CeilHeight;
}

View file

@ -63,8 +63,8 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
base.Texture = General.Map.Data.GetFlatImage(s.LongFloorTexture);
// Make vertices
verts = new WorldVertex[s.Vertices.Length];
for(int i = 0; i < s.Vertices.Length; i++)
verts = new WorldVertex[s.Triangles.Vertices.Length];
for(int i = 0; i < s.Triangles.Vertices.Length; i++)
{
// Use sector brightness for color shading
PixelColor pc = new PixelColor(255, unchecked((byte)s.Brightness), unchecked((byte)s.Brightness), unchecked((byte)s.Brightness));
@ -74,18 +74,18 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Grid aligned texture coordinates
if(base.Texture.IsImageLoaded)
{
verts[i].u = s.Vertices[i].x / base.Texture.ScaledWidth;
verts[i].v = s.Vertices[i].y / base.Texture.ScaledHeight;
verts[i].u = s.Triangles.Vertices[i].x / base.Texture.ScaledWidth;
verts[i].v = s.Triangles.Vertices[i].y / base.Texture.ScaledHeight;
}
else
{
verts[i].u = s.Vertices[i].x / 64;
verts[i].v = s.Vertices[i].y / 64;
verts[i].u = s.Triangles.Vertices[i].x / 64;
verts[i].v = s.Triangles.Vertices[i].y / 64;
}
// Vertex coordinates
verts[i].x = s.Vertices[i].x;
verts[i].y = s.Vertices[i].y;
verts[i].x = s.Triangles.Vertices[i].x;
verts[i].y = s.Triangles.Vertices[i].y;
verts[i].z = (float)s.FloorHeight;
}

View file

@ -112,9 +112,6 @@ namespace CodeImp.DoomBuilder
// States
private static bool debugbuild;
// Tools
private static Triangulator earclipper;
// Command line arguments
private static string[] cmdargs;
private static string autoloadfile = null;
@ -144,7 +141,6 @@ namespace CodeImp.DoomBuilder
internal static PluginManager Plugins { get { return plugins; } }
public static Clock Clock { get { return clock; } }
public static bool DebugBuild { get { return debugbuild; } }
internal static Triangulator EarClipper { get { return earclipper; } }
internal static TypesManager Types { get { return types; } }
internal static string AutoLoadFile { get { return autoloadfile; } }
internal static string AutoLoadMap { get { return autoloadmap; } }
@ -506,9 +502,6 @@ namespace CodeImp.DoomBuilder
mainwindow.Show();
mainwindow.Update();
// Create tools
earclipper = new Triangulator();
// Start Direct3D
General.WriteLogLine("Starting Direct3D graphics driver...");
try { D3DDevice.Startup(); }

View file

@ -38,6 +38,9 @@ namespace CodeImp.DoomBuilder.Geometry
// Position
private Vector2D pos;
// Along a sidedef?
private Sidedef sidedef;
// Lists
private LinkedListNode<EarClipVertex> vertslink;
private LinkedListNode<EarClipVertex> reflexlink;
@ -51,26 +54,40 @@ namespace CodeImp.DoomBuilder.Geometry
internal LinkedListNode<EarClipVertex> MainListNode { get { return vertslink; } }
public bool IsReflex { get { return (reflexlink != null); } }
public bool IsEarTip { get { return (eartiplink != null); } }
internal Sidedef Sidedef { get { return sidedef; } set { sidedef = value; } }
#endregion
#region ================== Constructor / Disposer
// Constructor
// Copy constructor
internal EarClipVertex(EarClipVertex v)
{
// Initialize
this.pos = v.pos;
this.sidedef = v.sidedef;
// We have no destructor
GC.SuppressFinalize(this);
}
// Copy constructor
internal EarClipVertex(EarClipVertex v, Sidedef sidedef)
{
// Initialize
this.pos = v.pos;
this.sidedef = sidedef;
// We have no destructor
GC.SuppressFinalize(this);
}
// Constructor
internal EarClipVertex(Vector2D v)
internal EarClipVertex(Vector2D v, Sidedef sidedef)
{
// Initialize
this.pos = v;
this.sidedef = sidedef;
// We have no destructor
GC.SuppressFinalize(this);
@ -82,6 +99,7 @@ namespace CodeImp.DoomBuilder.Geometry
reflexlink = null;
eartiplink = null;
vertslink = null;
sidedef = null;
}
#endregion

View file

@ -83,9 +83,12 @@ namespace CodeImp.DoomBuilder.Geometry
ay = CalculateRelativeAngle(baseline, y);
// Compare results
/*
if(ax < ay) return 1;
else if(ax > ay) return -1;
else return 0;
*/
return Math.Sign(ax - ay);
}
}
}

View file

@ -97,15 +97,18 @@ namespace CodeImp.DoomBuilder.Geometry
}
// This makes a polygon from the path
public EarClipPolygon MakePolygon()
public EarClipPolygon MakePolygon(bool startfront)
{
EarClipPolygon p = new EarClipPolygon();
bool forward = true;
bool forward = startfront;
// Any sides at all?
if(base.Count > 0)
{
p.AddLast(new EarClipVertex(base[0].Start.Position));
if(forward)
p.AddLast(new EarClipVertex(base[0].Start.Position, base[0].Front));
else
p.AddLast(new EarClipVertex(base[0].End.Position, base[0].Back));
// Add all lines, but the first
for(int i = 1; i < base.Count; i++)
@ -117,9 +120,9 @@ namespace CodeImp.DoomBuilder.Geometry
// Add next vertex
if(forward)
p.AddLast(new EarClipVertex(base[i].Start.Position));
p.AddLast(new EarClipVertex(base[i].Start.Position, base[0].Front));
else
p.AddLast(new EarClipVertex(base[i].End.Position));
p.AddLast(new EarClipVertex(base[i].End.Position, base[0].Back));
}
}

View file

@ -85,9 +85,12 @@ namespace CodeImp.DoomBuilder.Geometry
ay = CalculateRelativeAngle(baseside, y);
// Compare results
/*
if(ax < ay) return 1;
else if(ax > ay) return -1;
else return 0;
*/
return Math.Sign(ax - ay);
}
}
}

View file

@ -96,9 +96,9 @@ namespace CodeImp.DoomBuilder.Geometry
{
// On front or back?
if(base[i].IsFront)
p.AddLast(new EarClipVertex(base[i].Line.End.Position));
p.AddLast(new EarClipVertex(base[i].Line.End.Position, base[i]));
else
p.AddLast(new EarClipVertex(base[i].Line.Start.Position));
p.AddLast(new EarClipVertex(base[i].Line.Start.Position, base[i]));
}
}

View file

@ -208,7 +208,7 @@ namespace CodeImp.DoomBuilder.Geometry
{
// Make polygon
LinedefTracePath tracepath = new LinedefTracePath(innerlines);
EarClipPolygon innerpoly = tracepath.MakePolygon();
EarClipPolygon innerpoly = tracepath.MakePolygon(true);
// Check if the front of the line is outside the polygon
if(!innerpoly.Intersect(foundline.GetSidePoint(foundlinefront)))
@ -240,7 +240,7 @@ namespace CodeImp.DoomBuilder.Geometry
{
// Make polygon
LinedefTracePath tracepath = new LinedefTracePath(pathlines);
EarClipPolygon poly = tracepath.MakePolygon();
EarClipPolygon poly = tracepath.MakePolygon(true);
// Check if the front of the line is inside the polygon
if(poly.Intersect(line.GetSidePoint(front)))
@ -621,13 +621,100 @@ namespace CodeImp.DoomBuilder.Geometry
#region ================== Sector Labels
// This finds the ideal label position for a sector
public static Vector2D FindLabelPosition(Sector s, float resolution)
// This finds the ideal label positions for a sector
public static ICollection<Vector2D> FindLabelPositions(Sector s)
{
Vector2D foundpoint = new Vector2D();
float founddist = 0.0f;
List<Vector2D> positions = new List<Vector2D>(2);
return foundpoint;
// Do we have a triangulation?
Triangulation triangles = s.Triangles;
if(triangles != null)
{
// Go for all islands
for(int island = 0; island < triangles.IslandVertices.Length; island++)
{
Dictionary<Sidedef, Linedef> sides = new Dictionary<Sidedef, Linedef>(triangles.IslandVertices[island] >> 1);
List<Line2D> candidatelines = new List<Line2D>(triangles.IslandVertices[island] >> 1);
float founddistance = float.MinValue;
Vector2D foundposition = new Vector2D();
// Make candidate lines that are not along sidedefs
// We do this before testing the candidate against the sidedefs so that
// we can collect the relevant sidedefs first in the same run
for(int i = 0; i < triangles.Vertices.Length; i += 3)
{
Vector2D v1 = triangles.Vertices[i + 2];
for(int k = 0; k < 3; k++)
{
Vector2D v2 = triangles.Vertices[i + k];
Sidedef sd = triangles.Sidedefs[i + k];
// Not along a sidedef? Then this line is across the sector
// and guaranteed to be inside the sector!
if(sd == null)
{
// Make the line
candidatelines.Add(new Line2D(v1, v2));
}
else
{
// This sidedefs is part of this island and must be checked against
sides[sd] = sd.Line;
}
// Next
v1 = v2;
}
}
// Any candidate lines found at all?
if(candidatelines.Count > 0)
{
// Start with the first line
foreach(Line2D sourceline in candidatelines)
{
// Get center point
Vector2D candidateposition = sourceline.GetCoordinatesAt(0.5f);
// Check distance against other lines
float smallestdist = int.MaxValue;
foreach(KeyValuePair<Sidedef, Linedef> sd in sides)
{
// Check the distance
float distance = sd.Value.DistanceToSq(candidateposition, true);
smallestdist = Math.Min(smallestdist, distance);
}
// Keep this candidate if it is better than previous
if(smallestdist > founddistance)
{
foundposition = candidateposition;
founddistance = smallestdist;
}
}
// No cceptable line found, just use the first!
positions.Add(foundposition);
}
else
{
// No candidate lines found. Just return the center point.
//RectangleF rect = s.CreateBBox();
//return new Vector2D(rect.X + (rect.Width * 0.5f), rect.Y + (rect.Height * 0.5f));
positions.Add(new Vector2D());
}
}
}
else
{
// No triangulation was made. Just return the center point.
//RectangleF rect = s.CreateBBox();
//return new Vector2D(rect.X + (rect.Width * 0.5f), rect.Y + (rect.Height * 0.5f));
positions.Add(new Vector2D());
}
// Done
return positions;
}
#endregion

View file

@ -35,8 +35,7 @@ namespace CodeImp.DoomBuilder.Geometry
/// Responsible for creating sector polygons.
/// Performs triangulation of sectors by using ear clipping.
/// </summary>
/// See: http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
public sealed class Triangulator
public sealed class Triangulation
{
#region ================== Delegates
@ -62,32 +61,46 @@ namespace CodeImp.DoomBuilder.Geometry
#region ================== Variables
// Number of vertices per island
private int[] islandvertices;
// Vertices that result from the triangulation, 3 per triangle.
private Vector2D[] vertices;
// These sidedefs match with the vertices. If a vertex is not the start
// along a sidedef, this list contains a null entry for that vertex.
private Sidedef[] sidedefs;
#endregion
#region ================== Properties
public int[] IslandVertices { get { return islandvertices; } }
public Vector2D[] Vertices { get { return vertices; } }
public Sidedef[] Sidedefs { get { return sidedefs; } }
#endregion
#region ================== Constructor / Disposer
// Constructor
public Triangulator()
// I don't like using constructors that do more than simple initialization work
public static Triangulation Create(Sector sector)
{
// Initialize
// We have no destructor
GC.SuppressFinalize(this);
return new Triangulation(sector);
}
#endregion
#region ================== Methods
// This triangulates a sector and stores it
public TriangleList PerformTriangulation(Sector sector)
// Constructor
private Triangulation(Sector s)
{
// Initialize
TriangleList triangles = new TriangleList();
List<EarClipPolygon> polys;
List<int> islandslist = new List<int>();
List<Vector2D> verticeslist = new List<Vector2D>();
List<Sidedef> sidedefslist = new List<Sidedef>();
// We have no destructor
GC.SuppressFinalize(this);
/*
* This process is divided into several steps:
@ -104,20 +117,23 @@ namespace CodeImp.DoomBuilder.Geometry
*/
// TRACING
polys = DoTrace(sector);
polys = DoTrace(s);
// CUTTING
DoCutting(polys);
// EAR-CLIPPING
foreach(EarClipPolygon p in polys) triangles.AddRange(DoEarClip(p));
foreach(EarClipPolygon p in polys)
islandslist.Add(DoEarClip(p, verticeslist, sidedefslist));
// Return result
return triangles;
// Make arrays
islandvertices = islandslist.ToArray();
vertices = verticeslist.ToArray();
sidedefs = sidedefslist.ToArray();
}
#endregion
#region ================== Tracing
// This traces sector lines to create a polygon tree
@ -489,10 +505,10 @@ namespace CodeImp.DoomBuilder.Geometry
if(insertbefore != null)
{
// Find the position where we have to split the outer polygon
split = new EarClipVertex(starttoright.GetCoordinatesAt(foundu));
split = new EarClipVertex(starttoright.GetCoordinatesAt(foundu), null);
// Insert manual split vertices
p.AddBefore(insertbefore, new EarClipVertex(split));
p.AddBefore(insertbefore, new EarClipVertex(split, null));
// Start inserting from the start (do I make sense this time?)
v1 = start;
@ -505,8 +521,9 @@ namespace CodeImp.DoomBuilder.Geometry
while(v1 != start);
// Insert manual split vertices
p.AddBefore(insertbefore, new EarClipVertex(start.Value));
p.AddBefore(insertbefore, new EarClipVertex(split));
Sidedef sd = (insertbefore.Previous == null) ? insertbefore.List.Last.Value.Sidedef : insertbefore.Previous.Value.Sidedef;
p.AddBefore(insertbefore, new EarClipVertex(start.Value, null));
p.AddBefore(insertbefore, new EarClipVertex(split, sd));
}
}
@ -516,15 +533,16 @@ namespace CodeImp.DoomBuilder.Geometry
// This clips a polygon and returns the triangles
// The polygon may not have any holes or islands
private TriangleList DoEarClip(EarClipPolygon poly)
/// See: http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
private int DoEarClip(EarClipPolygon poly, List<Vector2D> verticeslist, List<Sidedef> sidedefslist)
{
LinkedList<EarClipVertex> verts = new LinkedList<EarClipVertex>();
List<EarClipVertex> convexes = new List<EarClipVertex>(poly.Count);
LinkedList<EarClipVertex> reflexes = new LinkedList<EarClipVertex>();
LinkedList<EarClipVertex> eartips = new LinkedList<EarClipVertex>();
TriangleList result = new TriangleList();
EarClipVertex v, v1, v2;
EarClipVertex[] t, t1, t2;
int countvertices = 0;
// Go for all vertices to fill list
foreach(EarClipVertex vec in poly)
@ -564,7 +582,7 @@ namespace CodeImp.DoomBuilder.Geometry
// Go for all convex vertices to see if they are ear tips
foreach(EarClipVertex cv in convexes)
{
// Add when this a valid ear
// Add when this is a valid ear
t = GetTriangle(cv);
if(CheckValidEar(t, reflexes)) cv.AddEarTip(eartips);
}
@ -577,7 +595,8 @@ namespace CodeImp.DoomBuilder.Geometry
t = GetTriangle(v);
// Add ear as triangle
result.Add(t);
AddTriangleToList(t, verticeslist, sidedefslist, (verts.Count > 3));
countvertices += 3;
// Remove this ear from all lists
v.Remove();
@ -619,9 +638,9 @@ namespace CodeImp.DoomBuilder.Geometry
// Dispose remaining vertices
foreach(EarClipVertex ecv in verts) ecv.Dispose();
// Return result
return result;
// Return the number of vertices in the result
return countvertices;
}
// This checks if a given ear is a valid (no intersections from reflex vertices)
@ -666,6 +685,21 @@ namespace CodeImp.DoomBuilder.Geometry
(Line2D.GetSideOfLine(t[2].Position, t[0].Position, p) < 0.00001f);
}
// This adds an array of vertices
private void AddTriangleToList(EarClipVertex[] triangle, List<Vector2D> verticeslist, List<Sidedef> sidedefslist, bool last)
{
// Create triangle
verticeslist.Add(triangle[0].Position);
sidedefslist.Add(triangle[0].Sidedef);
verticeslist.Add(triangle[1].Position);
sidedefslist.Add(triangle[1].Sidedef);
verticeslist.Add(triangle[2].Position);
if(last) sidedefslist.Add(null); else sidedefslist.Add(triangle[2].Sidedef);
// Modify the first earclipvertex of this triangle, it no longer lies along a sidedef
triangle[0].Sidedef = null;
}
#endregion
}
}

View file

@ -72,8 +72,8 @@ namespace CodeImp.DoomBuilder.Map
// Triangulation
private bool updateneeded;
private bool triangulationneeded;
private TriangleList triverts;
private FlatVertex[] vertices;
private Triangulation triangles;
private FlatVertex[] flatvertices;
#endregion
@ -96,7 +96,8 @@ namespace CodeImp.DoomBuilder.Map
public bool Marked { get { return marked; } set { marked = value; } }
public bool UpdateNeeded { get { return updateneeded; } set { updateneeded |= value; triangulationneeded |= value; } }
public Sector Clone { get { return clone; } set { clone = value; } }
public FlatVertex[] Vertices { get { return vertices; } }
public Triangulation Triangles { get { return triangles; } }
public FlatVertex[] FlatVertices { get { return flatvertices; } }
#endregion
@ -214,10 +215,10 @@ namespace CodeImp.DoomBuilder.Map
if(updateneeded)
{
// Triangulate again?
if(triangulationneeded || (triverts == null))
if(triangulationneeded || (triangles == null))
{
// Triangulate sector
triverts = General.EarClipper.PerformTriangulation(this);
triangles = Triangulation.Create(this);
}
// Brightness color (alpha is opaque)
@ -228,15 +229,15 @@ namespace CodeImp.DoomBuilder.Map
int brightint = brightcolor.ToInt();
// Make vertices
vertices = new FlatVertex[triverts.Count];
for(int i = 0; i < triverts.Count; i++)
flatvertices = new FlatVertex[triangles.Vertices.Length];
for(int i = 0; i < triangles.Vertices.Length; i++)
{
vertices[i].x = triverts[i].x;
vertices[i].y = triverts[i].y;
vertices[i].z = 1.0f;
vertices[i].c = brightint;
vertices[i].u = triverts[i].x;
vertices[i].v = triverts[i].y;
flatvertices[i].x = triangles.Vertices[i].x;
flatvertices[i].y = triangles.Vertices[i].y;
flatvertices[i].z = 1.0f;
flatvertices[i].c = brightint;
flatvertices[i].u = triangles.Vertices[i].x;
flatvertices[i].v = triangles.Vertices[i].y;
}
// Updated
@ -249,7 +250,7 @@ namespace CodeImp.DoomBuilder.Map
#region ================== Methods
// This creates a bounding box rectangle
// This requires the sector polygon to be up-to-date!
// This requires the sector triangulation to be up-to-date!
public RectangleF CreateBBox()
{
// Setup
@ -259,7 +260,7 @@ namespace CodeImp.DoomBuilder.Map
float bottom = float.MinValue;
// Go for vertices
foreach(FlatVertex v in vertices)
foreach(Vector2D v in triangles.Vertices)
{
// Update rect
if(v.x < left) left = v.x;