diff --git a/Subsurface/DebugConsole.cs b/Subsurface/DebugConsole.cs
index 6bac7d957..40490aa07 100644
--- a/Subsurface/DebugConsole.cs
+++ b/Subsurface/DebugConsole.cs
@@ -204,6 +204,9 @@ namespace Subsurface
Hull.EditWater = !Hull.EditWater;
}
break;
+ case "generatelevel":
+ Game1.Level = new Level(Game1.localRandom.Next(), 20, 5000, 5000);
+ break;
case "fowenabled":
case "fow":
case "drawfow":
diff --git a/Subsurface/Game1.cs b/Subsurface/Game1.cs
index 233a22910..0dc69062c 100644
--- a/Subsurface/Game1.cs
+++ b/Subsurface/Game1.cs
@@ -30,6 +30,8 @@ namespace Subsurface
public static EditMapScreen EditMapScreen;
public static EditCharacterScreen EditCharacterScreen;
+ public static Level Level;
+
public static GameSession GameSession;
public static GameClient Client;
diff --git a/Subsurface/Map/Level.cs b/Subsurface/Map/Level.cs
new file mode 100644
index 000000000..039baa400
--- /dev/null
+++ b/Subsurface/Map/Level.cs
@@ -0,0 +1,135 @@
+using FarseerPhysics;
+using FarseerPhysics.Common;
+using FarseerPhysics.Dynamics;
+using FarseerPhysics.Factories;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using Voronoi2;
+
+namespace Subsurface
+{
+ class Level
+ {
+ private int seed;
+
+ List
bodies;
+ List cells;
+
+ public Level(int seed, int siteCount, int width, int height)
+ {
+ this.seed = seed;
+
+ Voronoi voronoi = new Voronoi(1.0);
+
+ List sites = new List();
+ Random rand = new Random(seed);
+
+ for (int i = 0; i < siteCount; i++)
+ {
+ sites.Add(new PointF((float)(rand.NextDouble() * width), (float)(rand.NextDouble() * width)));
+ }
+
+ List graphEdges = MakeVoronoiGraph(sites, voronoi, width, height);
+
+ cells = new List();
+ foreach (GraphEdge ge in graphEdges)
+ {
+ for (int i = 0; i<2; i++)
+ {
+ int site = (i==0) ? ge.site1 : ge.site2;
+ VoronoiCell cell = cells.Find(c => c.site == site);
+ if (cell == null)
+ {
+ cell = new VoronoiCell(site);
+ cells.Add(cell);
+ }
+ if (!cell.edges.Contains(ge)) cell.edges.Add(ge);
+ }
+ }
+
+
+ bodies = new List();
+ foreach (VoronoiCell cell in cells)
+ {
+ //List of vectors defining my custom poly
+ List vlist = new List();
+ foreach (GraphEdge ge in cell.edges)
+ {
+ if (vlist.Contains(ge.point1)) continue;
+ vlist.Add(ge.point1);
+ }
+
+ if (vlist.Count < 2) continue;
+
+ for (int i = 0; i < vlist.Count; i++ )
+ {
+ vlist[i] = ConvertUnits.ToSimUnits(vlist[i]);
+ }
+
+
+ //get farseer 'vertices' from vectors
+ Vertices _shapevertices = new Vertices(vlist);
+ //_shapevertices.Sort(less);
+
+ //feed vertices array to BodyFactory.CreatePolygon to get a new farseer polygonal body
+ Body _newBody = BodyFactory.CreatePolygon(Game1.world, _shapevertices, 15);
+ _newBody.BodyType = BodyType.Static;
+ _newBody.CollisionCategories = Physics.CollisionWall;
+
+ bodies.Add(_newBody);
+ }
+ }
+
+
+ public int Compare(Vector2 a, Vector2 b, Vector2 center)
+ {
+ if (a.X - center.X >= 0 && b.X - center.X < 0) return 1;
+ if (a.X - center.X < 0 && b.X - center.X >= 0) return -1;
+ if (a.X - center.X == 0 && b.X - center.X == 0)
+ {
+ if (a.Y - center.Y >= 0 || b.Y - center.Y >= 0) return Math.Sign(a.Y - b.Y);
+ return Math.Sign(b.Y-a.Y);
+ }
+
+ // compute the cross product of vectors (center -> a) x (center -> b)
+ float det = (a.X - center.X) * (b.Y - center.Y) - (b.X - center.X) * (a.Y - center.Y);
+ if (det < 0) return 1;
+ if (det > 0) return -1;
+
+ // points a and b are on the same line from the center
+ // check which point is closer to the center
+ float d1 = (a.X - center.X) * (a.X - center.X) + (a.Y - center.Y) * (a.Y - center.Y);
+ float d2 = (b.X - center.X) * (b.X - center.X) + (b.Y - center.Y) * (b.Y - center.Y);
+ return Math.Sign(d1 - d2);
+ }
+
+ List MakeVoronoiGraph(List sites, Voronoi voronoi, int width, int height)
+ {
+ double[] xVal = new double[sites.Count];
+ double[] yVal = new double[sites.Count];
+ for (int i = 0; i < sites.Count; i++)
+ {
+ xVal[i] = sites[i].X;
+ yVal[i] = sites[i].Y;
+ }
+ return voronoi.generateVoronoi(xVal, yVal, 0, width, 0, height);
+ }
+
+ public void Render(SpriteBatch spriteBatch)
+ {
+ foreach (VoronoiCell cell in cells)
+ {
+ for (int i = 0; i
+ /// Description of Voronoi.
+ ///
+ public class Voronoi
+ {
+ // ************* Private members ******************
+ double borderMinX, borderMaxX, borderMinY, borderMaxY;
+ int siteidx;
+ double xmin, xmax, ymin, ymax, deltax, deltay;
+ int nvertices;
+ int nedges;
+ int nsites;
+ Site[] sites;
+ Site bottomsite;
+ int sqrt_nsites;
+ double minDistanceBetweenSites;
+ int PQcount;
+ int PQmin;
+ int PQhashsize;
+ Halfedge[] PQhash;
+
+ const int LE = 0;
+ const int RE = 1;
+
+ int ELhashsize;
+ Halfedge[] ELhash;
+ Halfedge ELleftend, ELrightend;
+ List allEdges;
+
+
+ // ************* Public methods ******************
+ // ******************************************
+
+ // constructor
+ public Voronoi ( double minDistanceBetweenSites )
+ {
+ siteidx = 0;
+ sites = null;
+
+ allEdges = null;
+ this.minDistanceBetweenSites = minDistanceBetweenSites;
+ }
+
+ /**
+ *
+ * @param xValuesIn Array of X values for each site.
+ * @param yValuesIn Array of Y values for each site. Must be identical length to yValuesIn
+ * @param minX The minimum X of the bounding box around the voronoi
+ * @param maxX The maximum X of the bounding box around the voronoi
+ * @param minY The minimum Y of the bounding box around the voronoi
+ * @param maxY The maximum Y of the bounding box around the voronoi
+ * @return
+ */
+ // تستدعى هذه العملية لإنشاء مخطط فورونوي
+ public List generateVoronoi ( double[] xValuesIn, double[] yValuesIn, double minX, double maxX, double minY, double maxY )
+ {
+ sort(xValuesIn, yValuesIn, xValuesIn.Length);
+
+ // Check bounding box inputs - if mins are bigger than maxes, swap them
+ double temp = 0;
+ if ( minX > maxX )
+ {
+ temp = minX;
+ minX = maxX;
+ maxX = temp;
+ }
+ if ( minY > maxY )
+ {
+ temp = minY;
+ minY = maxY;
+ maxY = temp;
+ }
+
+ borderMinX = minX;
+ borderMinY = minY;
+ borderMaxX = maxX;
+ borderMaxY = maxY;
+
+ siteidx = 0;
+ voronoi_bd ();
+ return allEdges;
+ }
+
+
+ /*********************************************************
+ * Private methods - implementation details
+ ********************************************************/
+
+ private void sort ( double[] xValuesIn, double[] yValuesIn, int count )
+ {
+ sites = null;
+ allEdges = new List();
+
+ nsites = count;
+ nvertices = 0;
+ nedges = 0;
+
+ double sn = (double)nsites + 4;
+ sqrt_nsites = (int) Math.Sqrt ( sn );
+
+ // Copy the inputs so we don't modify the originals
+ double[] xValues = new double[count];
+ double[] yValues = new double[count];
+ for (int i = 0; i < count; i++)
+ {
+ xValues[i] = xValuesIn[i];
+ yValues[i] = yValuesIn[i];
+ }
+ sortNode ( xValues, yValues, count );
+ }
+
+ private void qsort ( Site[] sites )
+ {
+ List listSites = new List( sites.Length );
+ for ( int i = 0; i < sites.Length; i++ )
+ {
+ listSites.Add ( sites[i] );
+ }
+
+ listSites.Sort ( new SiteSorterYX () );
+
+ // Copy back into the array
+ for (int i=0; i < sites.Length; i++)
+ {
+ sites[i] = listSites[i];
+ }
+ }
+
+ private void sortNode ( double[] xValues, double[] yValues, int numPoints )
+ {
+ nsites = numPoints;
+ sites = new Site[nsites];
+ xmin = xValues[0];
+ ymin = yValues[0];
+ xmax = xValues[0];
+ ymax = yValues[0];
+
+ for ( int i = 0; i < nsites; i++ )
+ {
+ sites[i] = new Site();
+ sites[i].coord.setPoint ( xValues[i], yValues[i] );
+ sites[i].sitenbr = i;
+
+ if ( xValues[i] < xmin )
+ xmin = xValues[i];
+ else if ( xValues[i] > xmax )
+ xmax = xValues[i];
+
+ if ( yValues[i] < ymin )
+ ymin = yValues[i];
+ else if ( yValues[i] > ymax )
+ ymax = yValues[i];
+ }
+
+ qsort ( sites );
+ deltax = xmax - xmin;
+ deltay = ymax - ymin;
+ }
+
+ private Site nextone ()
+ {
+ Site s;
+ if ( siteidx < nsites )
+ {
+ s = sites[siteidx];
+ siteidx++;
+ return s;
+ }
+ return null;
+ }
+
+ private Edge bisect ( Site s1, Site s2 )
+ {
+ double dx, dy, adx, ady;
+ Edge newedge;
+
+ newedge = new Edge();
+
+ newedge.reg[0] = s1;
+ newedge.reg[1] = s2;
+
+ newedge.ep [0] = null;
+ newedge.ep[1] = null;
+
+ dx = s2.coord.x - s1.coord.x;
+ dy = s2.coord.y - s1.coord.y;
+
+ adx = dx > 0 ? dx : -dx;
+ ady = dy > 0 ? dy : -dy;
+ newedge.c = (double)(s1.coord.x * dx + s1.coord.y * dy + (dx * dx + dy* dy) * 0.5);
+
+ if ( adx > ady )
+ {
+ newedge.a = 1.0;
+ newedge.b = dy / dx;
+ newedge.c /= dx;
+ }
+ else
+ {
+ newedge.a = dx / dy;
+ newedge.b = 1.0;
+ newedge.c /= dy;
+ }
+
+ newedge.edgenbr = nedges;
+ nedges++;
+
+ return newedge;
+ }
+
+ private void makevertex ( Site v )
+ {
+ v.sitenbr = nvertices;
+ nvertices++;
+ }
+
+ private bool PQinitialize ()
+ {
+ PQcount = 0;
+ PQmin = 0;
+ PQhashsize = 4 * sqrt_nsites;
+ PQhash = new Halfedge[ PQhashsize ];
+
+ for ( int i = 0; i < PQhashsize; i++ )
+ {
+ PQhash [i] = new Halfedge();
+ }
+ return true;
+ }
+
+ private int PQbucket ( Halfedge he )
+ {
+ int bucket;
+
+ bucket = (int) ((he.ystar - ymin) / deltay * PQhashsize);
+ if ( bucket < 0 )
+ bucket = 0;
+ if ( bucket >= PQhashsize )
+ bucket = PQhashsize - 1;
+ if ( bucket < PQmin )
+ PQmin = bucket;
+
+ return bucket;
+ }
+
+ // push the HalfEdge into the ordered linked list of vertices
+ private void PQinsert ( Halfedge he, Site v, double offset )
+ {
+ Halfedge last, next;
+
+ he.vertex = v;
+ he.ystar = (double)(v.coord.y + offset);
+ last = PQhash [ PQbucket (he) ];
+
+ while
+ (
+ (next = last.PQnext) != null
+ &&
+ (he.ystar > next.ystar || (he.ystar == next.ystar && v.coord.x > next.vertex.coord.x))
+ )
+ {
+ last = next;
+ }
+
+ he.PQnext = last.PQnext;
+ last.PQnext = he;
+ PQcount++;
+ }
+
+ // remove the HalfEdge from the list of vertices
+ private void PQdelete ( Halfedge he )
+ {
+ Halfedge last;
+
+ if (he.vertex != null)
+ {
+ last = PQhash [ PQbucket (he) ];
+ while ( last.PQnext != he )
+ {
+ last = last.PQnext;
+ }
+
+ last.PQnext = he.PQnext;
+ PQcount--;
+ he.vertex = null;
+ }
+ }
+
+ private bool PQempty ()
+ {
+ return ( PQcount == 0 );
+ }
+
+ private Point PQ_min ()
+ {
+ Point answer = new Point ();
+
+ while ( PQhash[PQmin].PQnext == null )
+ {
+ PQmin++;
+ }
+
+ answer.x = PQhash[PQmin].PQnext.vertex.coord.x;
+ answer.y = PQhash[PQmin].PQnext.ystar;
+ return answer;
+ }
+
+ private Halfedge PQextractmin ()
+ {
+ Halfedge curr;
+
+ curr = PQhash[PQmin].PQnext;
+ PQhash[PQmin].PQnext = curr.PQnext;
+ PQcount--;
+
+ return curr;
+ }
+
+ private Halfedge HEcreate(Edge e, int pm)
+ {
+ Halfedge answer = new Halfedge();
+ answer.ELedge = e;
+ answer.ELpm = pm;
+ answer.PQnext = null;
+ answer.vertex = null;
+
+ return answer;
+ }
+
+ private bool ELinitialize()
+ {
+ ELhashsize = 2 * sqrt_nsites;
+ ELhash = new Halfedge[ELhashsize];
+
+ for (int i = 0; i < ELhashsize; i++)
+ {
+ ELhash[i] = null;
+ }
+
+ ELleftend = HEcreate ( null, 0 );
+ ELrightend = HEcreate ( null, 0 );
+ ELleftend.ELleft = null;
+ ELleftend.ELright = ELrightend;
+ ELrightend.ELleft = ELleftend;
+ ELrightend.ELright = null;
+ ELhash[0] = ELleftend;
+ ELhash[ELhashsize - 1] = ELrightend;
+
+ return true;
+ }
+
+ private Halfedge ELright( Halfedge he )
+ {
+ return he.ELright;
+ }
+
+ private Halfedge ELleft( Halfedge he )
+ {
+ return he.ELleft;
+ }
+
+ private Site leftreg( Halfedge he )
+ {
+ if (he.ELedge == null)
+ {
+ return bottomsite;
+ }
+ return (he.ELpm == LE ? he.ELedge.reg[LE] : he.ELedge.reg[RE]);
+ }
+
+ private void ELinsert( Halfedge lb, Halfedge newHe )
+ {
+ newHe.ELleft = lb;
+ newHe.ELright = lb.ELright;
+ (lb.ELright).ELleft = newHe;
+ lb.ELright = newHe;
+ }
+
+ /*
+ * This delete routine can't reclaim node, since pointers from hash table
+ * may be present.
+ */
+ private void ELdelete( Halfedge he )
+ {
+ (he.ELleft).ELright = he.ELright;
+ (he.ELright).ELleft = he.ELleft;
+ he.deleted = true;
+ }
+
+ /* Get entry from hash table, pruning any deleted nodes */
+ private Halfedge ELgethash( int b )
+ {
+ Halfedge he;
+ if (b < 0 || b >= ELhashsize)
+ return null;
+
+ he = ELhash[b];
+ if (he == null || !he.deleted )
+ return he;
+
+ /* Hash table points to deleted half edge. Patch as necessary. */
+ ELhash[b] = null;
+ return null;
+ }
+
+ private Halfedge ELleftbnd( Point p )
+ {
+ int bucket;
+ Halfedge he;
+
+ /* Use hash table to get close to desired halfedge */
+ // use the hash function to find the place in the hash map that this
+ // HalfEdge should be
+ bucket = (int) ((p.x - xmin) / deltax * ELhashsize);
+
+ // make sure that the bucket position is within the range of the hash
+ // array
+ if ( bucket < 0 ) bucket = 0;
+ if ( bucket >= ELhashsize ) bucket = ELhashsize - 1;
+
+ he = ELgethash ( bucket );
+
+ // if the HE isn't found, search backwards and forwards in the hash map
+ // for the first non-null entry
+ if ( he == null )
+ {
+ for ( int i = 1; i < ELhashsize; i++ )
+ {
+ if ( (he = ELgethash ( bucket - i ) ) != null )
+ break;
+ if ( (he = ELgethash ( bucket + i ) ) != null )
+ break;
+ }
+ }
+
+ /* Now search linear list of halfedges for the correct one */
+ if ( he == ELleftend || ( he != ELrightend && right_of (he, p) ) )
+ {
+ // keep going right on the list until either the end is reached, or
+ // you find the 1st edge which the point isn't to the right of
+ do
+ {
+ he = he.ELright;
+ }
+ while ( he != ELrightend && right_of(he, p) );
+ he = he.ELleft;
+ }
+ else
+ // if the point is to the left of the HalfEdge, then search left for
+ // the HE just to the left of the point
+ {
+ do
+ {
+ he = he.ELleft;
+ }
+ while ( he != ELleftend && !right_of(he, p) );
+ }
+
+ /* Update hash table and reference counts */
+ if ( bucket > 0 && bucket < ELhashsize - 1)
+ {
+ ELhash[bucket] = he;
+ }
+
+ return he;
+ }
+
+ private void pushGraphEdge( Site leftSite, Site rightSite, Vector2 point1, Vector2 point2 )
+ {
+ GraphEdge newEdge = new GraphEdge ();
+ allEdges.Add ( newEdge );
+ newEdge.point1 = point1;
+ newEdge.point2 = point2;
+
+ newEdge.site1 = leftSite.sitenbr;
+ newEdge.site2 = rightSite.sitenbr;
+ }
+
+ private void clip_line( Edge e )
+ {
+ double pxmin, pxmax, pymin, pymax;
+ Site s1, s2;
+
+ double x1 = e.reg[0].coord.x;
+ double y1 = e.reg[0].coord.y;
+ double x2 = e.reg[1].coord.x;
+ double y2 = e.reg[1].coord.y;
+ double x = x2- x1;
+ double y = y2 - y1;
+
+ // if the distance between the two points this line was created from is
+ // less than the square root of 2 عن جد؟, then ignore it
+ if ( Math.Sqrt ( (x*x) + (y*y) ) < minDistanceBetweenSites )
+ {
+ return;
+ }
+ pxmin = borderMinX;
+ pymin = borderMinY;
+ pxmax = borderMaxX;
+ pymax = borderMaxY;
+
+ if ( e.a == 1.0 && e.b >= 0.0 )
+ {
+ s1 = e.ep[1];
+ s2 = e.ep[0];
+ }
+ else
+ {
+ s1 = e.ep[0];
+ s2 = e.ep[1];
+ }
+
+ if ( e.a == 1.0 )
+ {
+ y1 = pymin;
+
+ if ( s1 != null && s1.coord.y > pymin )
+ y1 = s1.coord.y;
+ if ( y1 > pymax )
+ y1 = pymax;
+ x1 = e.c - e.b * y1;
+ y2 = pymax;
+
+ if ( s2 != null && s2.coord.y < pymax )
+ y2 = s2.coord.y;
+ if ( y2 < pymin )
+ y2 = pymin;
+ x2 = e.c - e.b * y2;
+ if ( ( (x1 > pxmax) & (x2 > pxmax) ) | ( (x1 < pxmin) & (x2 < pxmin) ) )
+ return;
+
+ if ( x1 > pxmax )
+ {
+ x1 = pxmax;
+ y1 = ( e.c - x1 ) / e.b;
+ }
+ if ( x1 < pxmin )
+ {
+ x1 = pxmin;
+ y1 = ( e.c - x1 ) / e.b;
+ }
+ if ( x2 > pxmax )
+ {
+ x2 = pxmax;
+ y2 = ( e.c - x2 ) / e.b;
+ }
+ if ( x2 < pxmin )
+ {
+ x2 = pxmin;
+ y2 = ( e.c - x2 ) / e.b;
+ }
+
+ }
+ else
+ {
+ x1 = pxmin;
+ if ( s1 != null && s1.coord.x > pxmin )
+ x1 = s1.coord.x;
+ if ( x1 > pxmax )
+ x1 = pxmax;
+ y1 = e.c - e.a * x1;
+
+ x2 = pxmax;
+ if ( s2 != null && s2.coord.x < pxmax )
+ x2 = s2.coord.x;
+ if ( x2 < pxmin )
+ x2 = pxmin;
+ y2 = e.c - e.a * x2;
+
+ if (((y1 > pymax) & (y2 > pymax)) | ((y1 < pymin) & (y2 < pymin)))
+ return;
+
+ if ( y1 > pymax )
+ {
+ y1 = pymax;
+ x1 = ( e.c - y1 ) / e.a;
+ }
+ if ( y1 < pymin )
+ {
+ y1 = pymin;
+ x1 = ( e.c - y1 ) / e.a;
+ }
+ if ( y2 > pymax )
+ {
+ y2 = pymax;
+ x2 = ( e.c - y2 ) / e.a;
+ }
+ if ( y2 < pymin )
+ {
+ y2 = pymin;
+ x2 = ( e.c - y2 ) / e.a;
+ }
+ }
+
+ pushGraphEdge(e.reg[0], e.reg[1], new Vector2((float)x1, (float)y1), new Vector2((float)x2, (float)y2));
+ }
+
+ private void endpoint( Edge e, int lr, Site s )
+ {
+ e.ep[lr] = s;
+ if ( e.ep[RE - lr] == null )
+ return;
+ clip_line ( e );
+ }
+
+ /* returns true if p is to right of halfedge e */
+ private bool right_of(Halfedge el, Point p)
+ {
+ Edge e;
+ Site topsite;
+ bool right_of_site;
+ bool above, fast;
+ double dxp, dyp, dxs, t1, t2, t3, yl;
+
+ e = el.ELedge;
+ topsite = e.reg[1];
+
+ if ( p.x > topsite.coord.x )
+ right_of_site = true;
+ else
+ right_of_site = false;
+
+ if ( right_of_site && el.ELpm == LE )
+ return true;
+ if (!right_of_site && el.ELpm == RE )
+ return false;
+
+ if ( e.a == 1.0 )
+ {
+ dxp = p.x - topsite.coord.x;
+ dyp = p.y - topsite.coord.y;
+ fast = false;
+
+ if ( (!right_of_site & (e.b < 0.0)) | (right_of_site & (e.b >= 0.0)) )
+ {
+ above = dyp >= e.b * dxp;
+ fast = above;
+ }
+ else
+ {
+ above = p.x + p.y * e.b > e.c;
+ if ( e.b < 0.0 )
+ above = !above;
+ if ( !above )
+ fast = true;
+ }
+ if ( !fast )
+ {
+ dxs = topsite.coord.x - ( e.reg[0] ).coord.x;
+ above = e.b * (dxp * dxp - dyp * dyp)
+ < dxs * dyp * (1.0 + 2.0 * dxp / dxs + e.b * e.b);
+
+ if ( e.b < 0 )
+ above = !above;
+ }
+ }
+ else // e.b == 1.0
+ {
+ yl = e.c - e.a * p.x;
+ t1 = p.y - yl;
+ t2 = p.x - topsite.coord.x;
+ t3 = yl - topsite.coord.y;
+ above = t1 * t1 > t2 * t2 + t3 * t3;
+ }
+ return ( el.ELpm == LE ? above : !above );
+ }
+
+ private Site rightreg(Halfedge he)
+ {
+ if (he.ELedge == (Edge) null)
+ // if this halfedge has no edge, return the bottom site (whatever
+ // that is)
+ {
+ return (bottomsite);
+ }
+
+ // if the ELpm field is zero, return the site 0 that this edge bisects,
+ // otherwise return site number 1
+ return (he.ELpm == LE ? he.ELedge.reg[RE] : he.ELedge.reg[LE]);
+ }
+
+ private double dist( Site s, Site t )
+ {
+ double dx, dy;
+ dx = s.coord.x - t.coord.x;
+ dy = s.coord.y - t.coord.y;
+ return Math.Sqrt ( dx * dx + dy * dy );
+ }
+
+ // create a new site where the HalfEdges el1 and el2 intersect - note that
+ // the Point in the argument list is not used, don't know why it's there
+ private Site intersect( Halfedge el1, Halfedge el2 )
+ {
+ Edge e1, e2, e;
+ Halfedge el;
+ double d, xint, yint;
+ bool right_of_site;
+ Site v; // vertex
+
+ e1 = el1.ELedge;
+ e2 = el2.ELedge;
+
+ if ( e1 == null || e2 == null )
+ return null;
+
+ // if the two edges bisect the same parent, return null
+ if ( e1.reg[1] == e2.reg[1] )
+ return null;
+
+ d = e1.a * e2.b - e1.b * e2.a;
+ if ( -1.0e-10 < d && d < 1.0e-10 )
+ return null;
+
+ xint = ( e1.c * e2.b - e2.c * e1.b ) / d;
+ yint = ( e2.c * e1.a - e1.c * e2.a ) / d;
+
+ if ( (e1.reg[1].coord.y < e2.reg[1].coord.y)
+ || (e1.reg[1].coord.y == e2.reg[1].coord.y && e1.reg[1].coord.x < e2.reg[1].coord.x) )
+ {
+ el = el1;
+ e = e1;
+ }
+ else
+ {
+ el = el2;
+ e = e2;
+ }
+
+ right_of_site = xint >= e.reg[1].coord.x;
+ if ((right_of_site && el.ELpm == LE)
+ || (!right_of_site && el.ELpm == RE))
+ return null;
+
+ // create a new site at the point of intersection - this is a new vector
+ // event waiting to happen
+ v = new Site();
+ v.coord.x = xint;
+ v.coord.y = yint;
+ return v;
+ }
+
+ /*
+ * implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax, deltax,
+ * deltay (can all be estimates). Performance suffers if they are wrong;
+ * better to make nsites, deltax, and deltay too big than too small. (?)
+ */
+ private bool voronoi_bd()
+ {
+ Site newsite, bot, top, temp, p;
+ Site v;
+ Point newintstar = null;
+ int pm;
+ Halfedge lbnd, rbnd, llbnd, rrbnd, bisector;
+ Edge e;
+
+ PQinitialize();
+ ELinitialize();
+
+ bottomsite = nextone();
+ newsite = nextone();
+ while (true)
+ {
+ if (!PQempty())
+ {
+ newintstar = PQ_min();
+ }
+ // if the lowest site has a smaller y value than the lowest vector
+ // intersection,
+ // process the site otherwise process the vector intersection
+
+ if (newsite != null && (PQempty()
+ || newsite.coord.y < newintstar.y
+ || (newsite.coord.y == newintstar.y
+ && newsite.coord.x < newintstar.x)))
+ {
+ /* new site is smallest -this is a site event */
+ // get the first HalfEdge to the LEFT of the new site
+ lbnd = ELleftbnd((newsite.coord));
+ // get the first HalfEdge to the RIGHT of the new site
+ rbnd = ELright(lbnd);
+ // if this halfedge has no edge,bot =bottom site (whatever that
+ // is)
+ bot = rightreg(lbnd);
+ // create a new edge that bisects
+ e = bisect(bot, newsite);
+
+ // create a new HalfEdge, setting its ELpm field to 0
+ bisector = HEcreate(e, LE);
+ // insert this new bisector edge between the left and right
+ // vectors in a linked list
+ ELinsert(lbnd, bisector);
+
+ // if the new bisector intersects with the left edge,
+ // remove the left edge's vertex, and put in the new one
+ if ((p = intersect(lbnd, bisector)) != null)
+ {
+ PQdelete(lbnd);
+ PQinsert(lbnd, p, dist(p, newsite));
+ }
+ lbnd = bisector;
+ // create a new HalfEdge, setting its ELpm field to 1
+ bisector = HEcreate(e, RE);
+ // insert the new HE to the right of the original bisector
+ // earlier in the IF stmt
+ ELinsert(lbnd, bisector);
+
+ // if this new bisector intersects with the new HalfEdge
+ if ((p = intersect(bisector, rbnd)) != null)
+ {
+ // push the HE into the ordered linked list of vertices
+ PQinsert(bisector, p, dist(p, newsite));
+ }
+ newsite = nextone();
+ } else if (!PQempty())
+ /* intersection is smallest - this is a vector event */
+ {
+ // pop the HalfEdge with the lowest vector off the ordered list
+ // of vectors
+ lbnd = PQextractmin();
+ // get the HalfEdge to the left of the above HE
+ llbnd = ELleft(lbnd);
+ // get the HalfEdge to the right of the above HE
+ rbnd = ELright(lbnd);
+ // get the HalfEdge to the right of the HE to the right of the
+ // lowest HE
+ rrbnd = ELright(rbnd);
+ // get the Site to the left of the left HE which it bisects
+ bot = leftreg(lbnd);
+ // get the Site to the right of the right HE which it bisects
+ top = rightreg(rbnd);
+
+ v = lbnd.vertex; // get the vertex that caused this event
+ makevertex(v); // set the vertex number - couldn't do this
+ // earlier since we didn't know when it would be processed
+ endpoint(lbnd.ELedge, lbnd.ELpm, v);
+ // set the endpoint of
+ // the left HalfEdge to be this vector
+ endpoint(rbnd.ELedge, rbnd.ELpm, v);
+ // set the endpoint of the right HalfEdge to
+ // be this vector
+ ELdelete(lbnd); // mark the lowest HE for
+ // deletion - can't delete yet because there might be pointers
+ // to it in Hash Map
+ PQdelete(rbnd);
+ // remove all vertex events to do with the right HE
+ ELdelete(rbnd); // mark the right HE for
+ // deletion - can't delete yet because there might be pointers
+ // to it in Hash Map
+ pm = LE; // set the pm variable to zero
+
+ if (bot.coord.y > top.coord.y)
+ // if the site to the left of the event is higher than the
+ // Site
+ { // to the right of it, then swap them and set the 'pm'
+ // variable to 1
+ temp = bot;
+ bot = top;
+ top = temp;
+ pm = RE;
+ }
+ e = bisect(bot, top); // create an Edge (or line)
+ // that is between the two Sites. This creates the formula of
+ // the line, and assigns a line number to it
+ bisector = HEcreate(e, pm); // create a HE from the Edge 'e',
+ // and make it point to that edge
+ // with its ELedge field
+ ELinsert(llbnd, bisector); // insert the new bisector to the
+ // right of the left HE
+ endpoint(e, RE - pm, v); // set one endpoint to the new edge
+ // to be the vector point 'v'.
+ // If the site to the left of this bisector is higher than the
+ // right Site, then this endpoint
+ // is put in position 0; otherwise in pos 1
+
+ // if left HE and the new bisector intersect, then delete
+ // the left HE, and reinsert it
+ if ((p = intersect(llbnd, bisector)) != null)
+ {
+ PQdelete(llbnd);
+ PQinsert(llbnd, p, dist(p, bot));
+ }
+
+ // if right HE and the new bisector intersect, then
+ // reinsert it
+ if ((p = intersect(bisector, rrbnd)) != null)
+ {
+ PQinsert(bisector, p, dist(p, bot));
+ }
+ } else
+ {
+ break;
+ }
+ }
+
+ for (lbnd = ELright(ELleftend); lbnd != ELrightend; lbnd = ELright(lbnd))
+ {
+ e = lbnd.ELedge;
+ clip_line(e);
+ }
+
+ return true;
+ }
+
+ } // Voronoi Class End
+} // namespace Voronoi2 End
\ No newline at end of file
diff --git a/Subsurface/Map/VoronoiElements.cs b/Subsurface/Map/VoronoiElements.cs
new file mode 100644
index 000000000..d5e933de0
--- /dev/null
+++ b/Subsurface/Map/VoronoiElements.cs
@@ -0,0 +1,149 @@
+/*
+ * Created by SharpDevelop.
+ * User: Burhan
+ * Date: 17/06/2014
+ * Time: 09:29 م
+ *
+ * To change this template use Tools | Options | Coding | Edit Standard Headers.
+ */
+
+/*
+ Copyright 2011 James Humphreys. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are
+ permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY James Humphreys ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ The views and conclusions contained in the software and documentation are those of the
+ authors and should not be interpreted as representing official policies, either expressed
+ or implied, of James Humphreys.
+ */
+
+/*
+ * C# Version by Burhan Joukhadar
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+
+using Microsoft.Xna.Framework;
+using System;
+using System.Collections.Generic;
+
+namespace Voronoi2
+{
+ public class Point
+ {
+ public double x, y;
+
+ public Point ()
+ {
+ }
+
+ public void setPoint ( double x, double y )
+ {
+ this.x = x;
+ this.y = y;
+ }
+ }
+
+ // use for sites and vertecies
+ public class Site
+ {
+ public Point coord;
+ public int sitenbr;
+
+ public Site ()
+ {
+ coord = new Point();
+ }
+ }
+
+ public class Edge
+ {
+ public double a = 0, b = 0, c = 0;
+ public Site[] ep;
+ public Site[] reg;
+ public int edgenbr;
+
+ public Edge ()
+ {
+ ep = new Site[2];
+ reg = new Site[2];
+ }
+ }
+
+
+ public class Halfedge
+ {
+ public Halfedge ELleft, ELright;
+ public Edge ELedge;
+ public bool deleted;
+ public int ELpm;
+ public Site vertex;
+ public double ystar;
+ public Halfedge PQnext;
+
+ public Halfedge ()
+ {
+ PQnext = null;
+ }
+ }
+
+ public class VoronoiCell
+ {
+ public List edges;
+ public int site;
+
+ public VoronoiCell(int site)
+ {
+ edges = new List();
+ this.site = site;
+ }
+ }
+
+ public class GraphEdge
+ {
+ public Vector2 point1, point2;
+ public int site1, site2;
+ }
+
+ // للترتيب
+ public class SiteSorterYX : IComparer
+ {
+ public int Compare ( Site p1, Site p2 )
+ {
+ Point s1 = p1.coord;
+ Point s2 = p2.coord;
+ if ( s1.y < s2.y ) return -1;
+ if ( s1.y > s2.y ) return 1;
+ if ( s1.x < s2.x ) return -1;
+ if ( s1.x > s2.x ) return 1;
+ return 0;
+ }
+ }
+}
diff --git a/Subsurface/Screens/GameScreen.cs b/Subsurface/Screens/GameScreen.cs
index 989b60c86..6d7a8ee63 100644
--- a/Subsurface/Screens/GameScreen.cs
+++ b/Subsurface/Screens/GameScreen.cs
@@ -183,6 +183,8 @@ namespace Subsurface
BlendState.AlphaBlend,
null, null, null, null,
cam.Transform);
+
+ if (Game1.Level!=null) Game1.Level.Render(spriteBatch);
Map.DrawBack(spriteBatch);
diff --git a/Subsurface/Subsurface.csproj b/Subsurface/Subsurface.csproj
index 19d88f624..11d227d65 100644
--- a/Subsurface/Subsurface.csproj
+++ b/Subsurface/Subsurface.csproj
@@ -124,9 +124,12 @@
+
+
+
diff --git a/Subsurface/Subsurface.csproj.user b/Subsurface/Subsurface.csproj.user
index 505c3a0bf..693505ea4 100644
--- a/Subsurface/Subsurface.csproj.user
+++ b/Subsurface/Subsurface.csproj.user
@@ -9,6 +9,6 @@
en-US
false
- ProjectFiles
+ ShowAllFiles
\ No newline at end of file