mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-22 15:02:54 +08:00
NavMesh generator progress
This commit is contained in:
parent
dd97b65933
commit
7fe0bef6bd
2
Project/Panels/GenerateNavMeshPanel.Designer.cs
generated
2
Project/Panels/GenerateNavMeshPanel.Designer.cs
generated
@ -62,7 +62,7 @@
|
||||
this.MaxTextBox.Name = "MaxTextBox";
|
||||
this.MaxTextBox.Size = new System.Drawing.Size(177, 20);
|
||||
this.MaxTextBox.TabIndex = 48;
|
||||
this.MaxTextBox.Text = "100, 100";
|
||||
this.MaxTextBox.Text = "50, 50";
|
||||
//
|
||||
// label1
|
||||
//
|
||||
|
@ -74,7 +74,6 @@ namespace CodeWalker.Project.Panels
|
||||
// return;
|
||||
//}
|
||||
|
||||
var path = ProjectForm.CurrentProjectFile.GetFullFilePath("navmeshes") + "\\";
|
||||
|
||||
GenerateButton.Enabled = false;
|
||||
|
||||
@ -112,6 +111,8 @@ namespace CodeWalker.Project.Panels
|
||||
var vert = new GenVertex();
|
||||
var builder = new YnvBuilder();
|
||||
|
||||
var polys = new List<GenPoly>();
|
||||
|
||||
for (int x = imin.X; x <= imax.X; x++) //generate verts for each world cell
|
||||
{
|
||||
for (int y = imin.Y; y <= imax.Y; y++)
|
||||
@ -122,8 +123,8 @@ namespace CodeWalker.Project.Panels
|
||||
var cellmin = space.Grid.GetWorldPos(gi);
|
||||
var cellmax = cellmin + SpaceGrid.CellSize;
|
||||
var vertexCountXY = (cellmax - cellmin) / density;
|
||||
int vertexCountX = (int)vertexCountXY.X;
|
||||
int vertexCountY = (int)vertexCountXY.Y;
|
||||
int vertexCountX = (int)vertexCountXY.X+1;
|
||||
int vertexCountY = (int)vertexCountXY.Y+1;
|
||||
//int vertexCountTot = vertexCountX * vertexCountY;
|
||||
vgrid.BeginGrid(vertexCountX, vertexCountY);
|
||||
cellmin.Z = 0.0f;//min probably not needed here
|
||||
@ -154,6 +155,7 @@ namespace CodeWalker.Project.Panels
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(20);//~50fps should be fine
|
||||
ybn = gameFileCache.GetYbn(boundsitem.Name); //try queue it again..
|
||||
}
|
||||
}
|
||||
if (ybn.Loaded && (ybn.Bounds != null))
|
||||
@ -181,7 +183,9 @@ namespace CodeWalker.Project.Panels
|
||||
ray.Position.Z = cellmax.Z + 1.0f;//start the ray at the top of the cell
|
||||
var intres = space.RayIntersect(ray, float.MaxValue, layers);
|
||||
hitTestCount++;
|
||||
while (intres.Hit && (intres.HitDist > 0))
|
||||
while (intres.Hit)// && (intres.HitDist > 0))
|
||||
{
|
||||
if (intres.HitDist > 0)
|
||||
{
|
||||
hitCount++;
|
||||
vert.Position = intres.Position;
|
||||
@ -199,9 +203,10 @@ namespace CodeWalker.Project.Panels
|
||||
vert.PolyID = -1;
|
||||
vgrid.AddVertex(ref vert);
|
||||
|
||||
//continue down until no more hits..... step by 3m
|
||||
if (vgrid.CurVertexCount > 15) //too many hits?
|
||||
{ break; }
|
||||
}
|
||||
//continue down until no more hits..... step by 3m
|
||||
ray.Position.Z = intres.Position.Z - 3.0f;
|
||||
intres = space.RayIntersect(ray, float.MaxValue, layers);
|
||||
}
|
||||
@ -218,16 +223,555 @@ namespace CodeWalker.Project.Panels
|
||||
vgrid.ConnectVertices();
|
||||
|
||||
|
||||
var polys = vgrid.GenPolys();
|
||||
newCount += polys.Count;
|
||||
var genPolys = vgrid.GenPolys2();
|
||||
polys.AddRange(genPolys);
|
||||
|
||||
newCount += genPolys.Count;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//try merge generated polys into bigger ones, while keeping convex!
|
||||
UpdateStatus("Building edge dictionary...");
|
||||
var edgeDict = new Dictionary<GenEdgeKey, GenEdge>();
|
||||
var tryGetEdge = new Func<Vector3, Vector3, GenEdge>((v1, v2) =>
|
||||
{
|
||||
var key1 = new GenEdgeKey(v1, v2);
|
||||
var key2 = new GenEdgeKey(v2, v1);
|
||||
GenEdge edge = null;
|
||||
if (edgeDict.TryGetValue(key1, out edge) || edgeDict.TryGetValue(key2, out edge))
|
||||
{
|
||||
return edge;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
var tryRemoveEdge = new Action<Vector3, Vector3>((v1, v2) =>
|
||||
{
|
||||
var key1 = new GenEdgeKey(v1, v2);
|
||||
var key2 = new GenEdgeKey(v2, v1);
|
||||
edgeDict.Remove(key1);
|
||||
edgeDict.Remove(key2);
|
||||
});
|
||||
var buildEdgeDict = new Action(() =>
|
||||
{
|
||||
for (int p = 0; p < polys.Count; p++) //build edge dict
|
||||
{
|
||||
var poly = polys[p];
|
||||
poly.Index = p;
|
||||
for (int i = 0; i < poly.Vertices.Length; i++)
|
||||
{
|
||||
var ip = (i + 1) % poly.Vertices.Length;
|
||||
var edge = tryGetEdge(poly.Vertices[i], poly.Vertices[ip]);
|
||||
if (edge != null)
|
||||
{
|
||||
if (edge.Poly2 != null)
|
||||
{ } //edge already assigned a second poly! shouldn't happen...
|
||||
edge.Poly2 = poly;
|
||||
edge.EdgeIndex2 = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
var key = new GenEdgeKey(poly.Vertices[i], poly.Vertices[ip]);
|
||||
edge = new GenEdge(poly, i);
|
||||
edgeDict[key] = edge;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
buildEdgeDict();
|
||||
|
||||
UpdateStatus("Merging polygons...");
|
||||
float plthresh = 0.3f;//threshold for plane dist test
|
||||
float dpthresh = 0.75f;//threshold for plane normals test
|
||||
float dthresh = 6.0f;//absolute distance thresh
|
||||
for (int p = 0; p < polys.Count; p++)
|
||||
{
|
||||
//UpdateStatus("Merging polygons... (" + p.ToString() + "/" + polys.Count.ToString() + ")");
|
||||
var poly = polys[p];
|
||||
if (poly == null) continue;
|
||||
if (poly.Merged) continue;
|
||||
var p1cnt = poly.Vertices.Length;
|
||||
if (p1cnt < 3) continue;
|
||||
var vplane = new Plane(poly.Vertices[0], poly.Normal);
|
||||
|
||||
var polycenter = poly.GetCenter();
|
||||
|
||||
for (int i = 0; i < poly.Vertices.Length; i++)
|
||||
{
|
||||
var ip = (i + 1) % poly.Vertices.Length;
|
||||
var eind1 = i;
|
||||
var edge = tryGetEdge(poly.Vertices[i], poly.Vertices[ip]);
|
||||
if (edge == null) continue;
|
||||
var poly2 = edge.Poly1;
|
||||
var eind2 = edge.EdgeIndex1;
|
||||
if (poly2 == poly) { poly2 = edge.Poly2; eind2 = edge.EdgeIndex2; }
|
||||
if (poly2 == poly) continue;//can't merge with itself! redundant edges/verts...
|
||||
if (poly2 == null) continue;
|
||||
if (poly2.Merged) continue;//new merged poly will get checked later..
|
||||
if (poly.Material.Index != poly2.Material.Index) continue;
|
||||
if (poly.PolyFlags != poly2.PolyFlags) continue;
|
||||
|
||||
var poly2center = poly2.GetCenter();
|
||||
|
||||
var npdist = Math.Abs(Plane.DotCoordinate(vplane, poly2center));
|
||||
if (npdist > plthresh) continue;
|
||||
var dpval = Vector3.Dot(poly.Normal, poly2.Normal);
|
||||
if (dpval < dpthresh) continue;
|
||||
var dist = (polycenter - poly2center).Length();
|
||||
if (dist > dthresh) continue;
|
||||
|
||||
|
||||
//if we got here, can merge these 2 polys....
|
||||
|
||||
|
||||
var newverts = new List<Vector3>();
|
||||
//add verts from poly1 from 0 to poly1 edge index (ip)
|
||||
//add verts from poly2 from poly2 edge index+2 to poly2 edge index (wrap/mod!)
|
||||
//add verts from poly1 from poly1 edge index+2 to last
|
||||
var p2cnt = poly2.Vertices.Length;
|
||||
var l2beg = (eind2 + 2) % p2cnt;
|
||||
var l2end = eind2;
|
||||
if (l2end < l2beg) l2end += p2cnt;
|
||||
var l1beg = (eind1 + 2);
|
||||
if (l1beg > p1cnt) l2end--;//don't add the first vertex again in this case!
|
||||
for (int j = 0; j <= eind1; j++) newverts.Add(poly.Vertices[j]);
|
||||
for (int j = l2beg; j <= l2end; j++) newverts.Add(poly2.Vertices[j % p2cnt]);
|
||||
for (int j = l1beg; j < p1cnt; j++) newverts.Add(poly.Vertices[j]);
|
||||
|
||||
|
||||
|
||||
|
||||
var varr = newverts.ToArray();
|
||||
var remredun = true;
|
||||
while (remredun)
|
||||
{
|
||||
remredun = false;
|
||||
newverts.Clear(); // remove redundant edges!
|
||||
for (int j = 0; j < varr.Length; j++)
|
||||
{
|
||||
var j0 = j - 1; if (j0 < 0) j0 += varr.Length;
|
||||
var j2 = j + 1; j2 = j2 % varr.Length;
|
||||
var v0 = varr[j0];
|
||||
var v1 = varr[j];
|
||||
var v2 = varr[j2];
|
||||
if (v0 == v2)
|
||||
{
|
||||
if (j2 > j)
|
||||
{
|
||||
j = j2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j == varr.Length - 1)
|
||||
{
|
||||
newverts = newverts.GetRange(0, newverts.Count - 1);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
j = varr.Length;
|
||||
}
|
||||
remredun = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
newverts.Add(v1);
|
||||
}
|
||||
}
|
||||
varr = newverts.ToArray();
|
||||
if (remredun)
|
||||
{ }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var newpoly = new GenPoly(newverts.ToArray(), poly);
|
||||
newpoly.Index = polys.Count;
|
||||
polys.Add(newpoly);//try merge this poly again later...
|
||||
|
||||
|
||||
//for all the edges in this new poly, need to update all the values!!! polys and indices!
|
||||
for (int j = 0; j < newpoly.Vertices.Length; j++)
|
||||
{
|
||||
var jp = (j + 1) % newpoly.Vertices.Length;
|
||||
var v = newpoly.Vertices[j];
|
||||
var vp = newpoly.Vertices[jp];
|
||||
var tedge = tryGetEdge(v, vp);
|
||||
if (tedge == null)
|
||||
{ continue; }//shouldn't happen..
|
||||
if (tedge.Poly1 == poly) { tedge.Poly1 = newpoly; tedge.EdgeIndex1 = j; }
|
||||
if (tedge.Poly2 == poly) { tedge.Poly2 = newpoly; tedge.EdgeIndex2 = j; }
|
||||
if (tedge.Poly1 == poly2) { tedge.Poly1 = newpoly; tedge.EdgeIndex1 = j; }
|
||||
if (tedge.Poly2 == poly2) { tedge.Poly2 = newpoly; tedge.EdgeIndex2 = j; }
|
||||
if (tedge.Poly1 == tedge.Poly2)
|
||||
{ } //why does this happen..? probably when an edge can't be removed due to an enclosed poly
|
||||
}
|
||||
|
||||
//tryRemoveEdge(poly.Vertices[i], poly.Vertices[ip]);
|
||||
polys[p] = null;//free up some memory..?
|
||||
polys[poly2.Index] = null;
|
||||
poly.Merged = true;
|
||||
poly2.Merged = true;
|
||||
break;//go to the next poly: don't do more than 1 merge at a time..
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var mergedPolys = new List<GenPoly>();
|
||||
foreach (var poly in polys)
|
||||
{
|
||||
if (poly == null) continue;
|
||||
if (poly.Merged) continue;
|
||||
mergedPolys.Add(poly);
|
||||
}
|
||||
polys = mergedPolys;
|
||||
|
||||
|
||||
UpdateStatus("Merging edges...");
|
||||
edgeDict = new Dictionary<GenEdgeKey, GenEdge>();
|
||||
buildEdgeDict();
|
||||
float dpthresh1 = 0.5f;
|
||||
float dpthresh2 = 0.7f; //try preserve shape more when not attached
|
||||
foreach (var poly in polys)
|
||||
{
|
||||
if (poly?.Vertices == null) continue;
|
||||
if (poly.Vertices.Length < 5) continue;
|
||||
for (int i = 1; i < poly.Vertices.Length; i++)
|
||||
{
|
||||
var ni = i - 1;
|
||||
var edge0 = tryGetEdge(poly.Vertices[ni], poly.Vertices[i]);
|
||||
if (edge0 == null)
|
||||
{ continue; }//really shouldn't happen
|
||||
var poly0 = (edge0.Poly1 != poly) ? edge0.Poly1 : edge0.Poly2;
|
||||
var vert0 = poly.Vertices[ni];
|
||||
|
||||
var ip = (i + 1) % poly.Vertices.Length;
|
||||
var ip2 = (i + 2) % poly.Vertices.Length;
|
||||
var edge1 = tryGetEdge(poly.Vertices[i], poly.Vertices[ip]);
|
||||
if (edge1 == null)
|
||||
{ continue; }//really shouldn't happen
|
||||
var poly1 = (edge1.Poly1 != poly) ? edge1.Poly1 : edge1.Poly2;
|
||||
var vert1 = poly.Vertices[ip];
|
||||
var verti = poly.Vertices[i];
|
||||
var vert2 = poly.Vertices[ip2];
|
||||
var dp = Vector3.Dot(Vector3.Normalize(verti - vert0), Vector3.Normalize(vert2 - verti));
|
||||
var dp2 = Vector3.Dot(Vector3.Normalize(verti - vert0), Vector3.Normalize(vert1 - verti));
|
||||
|
||||
var usedpthresh = ((poly0 == null) || (poly0 == poly)) ? dpthresh2 : dpthresh1;
|
||||
|
||||
if ((poly0 != poly1) || (dp < usedpthresh) || (dp2 < -0.05))//can't merge, move on to next edge
|
||||
{ continue; }
|
||||
|
||||
|
||||
if ((poly0 != null) && (poly0.Vertices.Length < 5))
|
||||
{ continue; }
|
||||
|
||||
//remove the relevant vertex from both polys, and start again for this poly (reset i to 1)
|
||||
poly.RemoveVertex(verti);
|
||||
poly0?.RemoveVertex(verti);//if poly0==poly, remove same vertex twice?
|
||||
|
||||
|
||||
//remove merged edges from edge dict, and add new edge to it
|
||||
tryRemoveEdge(vert0, verti);
|
||||
tryRemoveEdge(verti, vert1);
|
||||
|
||||
var key = new GenEdgeKey(vert0, vert1);
|
||||
var edge = new GenEdge(poly, i-1);
|
||||
edge.Poly2 = poly0;
|
||||
edge.EdgeIndex2 = poly0?.FindVertex(vert0) ?? -1; //(edge0.Poly2 != poly0) ? edge0.EdgeIndex1 : edge0.EdgeIndex2;
|
||||
edgeDict[key] = edge;
|
||||
|
||||
i = 0;//will be incremented to 1 before next loop
|
||||
if (poly.Vertices.Length < 5) break;//don't make polys disappear! shouldn't happen anyway
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
UpdateStatus("Convexifying polygons...");
|
||||
mergedPolys = new List<GenPoly>();
|
||||
var getAngle = new Func<GenPoly, int, int, float>((poly, i1, i2) =>
|
||||
{
|
||||
var edge0 = poly.Vertices[i2] - poly.Vertices[i1];
|
||||
return (float)Math.Atan2(edge0.Y, edge0.X);
|
||||
});
|
||||
var getAngleDiff = new Func<float, float, float>((a1, a2) =>
|
||||
{
|
||||
var angldiff = a2 - a1;
|
||||
if (angldiff > Math.PI) angldiff -= (float)(Math.PI * 2);
|
||||
if (angldiff < -Math.PI) angldiff += (float)(Math.PI * 2);
|
||||
return angldiff;
|
||||
});
|
||||
var findInflection = new Func<GenPoly, int, int>((poly, starti) =>
|
||||
{
|
||||
var vcnt = poly.Vertices.Length;
|
||||
var i0 = starti % vcnt;
|
||||
var i1 = (i0 + 1) % vcnt;
|
||||
var angl0 = getAngle(poly, i0, i1);
|
||||
var curangl = angl0;
|
||||
for (int i = starti+1; i <= vcnt; i++)
|
||||
{
|
||||
i0 = i % vcnt;
|
||||
i1 = (i0 + 1) % vcnt;
|
||||
angl0 = getAngle(poly, i0, i1);
|
||||
var angldiff = getAngleDiff(curangl, angl0);
|
||||
if (angldiff < 0)
|
||||
{
|
||||
return i0;
|
||||
}
|
||||
curangl = angl0;
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
var findIntersection = new Func<GenPoly, int, int, int>((poly, i0, i1) =>
|
||||
{
|
||||
var vcnt = poly.Vertices.Length;
|
||||
var v0 = poly.Vertices[i0];
|
||||
var v1 = poly.Vertices[i1];
|
||||
var minx0 = Math.Min(v0.X, v1.X);
|
||||
var miny0 = Math.Min(v0.Y, v1.Y);
|
||||
var maxx0 = Math.Max(v0.X, v1.X);
|
||||
var maxy0 = Math.Max(v0.Y, v1.Y);
|
||||
for (int i = 1; i < vcnt; i++)
|
||||
{
|
||||
var i2 = (i + i0) % vcnt;
|
||||
var i3 = (i2 + 1) % vcnt;
|
||||
if (i3 == i1) break;
|
||||
var v2 = poly.Vertices[i2];
|
||||
var v3 = poly.Vertices[i3];
|
||||
|
||||
if ((v0 == v2) || (v0 == v3) || (v1 == v2) || (v1 == v3)) continue; //don't test if sharing a vertex.
|
||||
|
||||
//https://rosettacode.org/wiki/Find_the_intersection_of_two_lines
|
||||
float a1 = v1.Y - v0.Y;
|
||||
float b1 = v0.X - v1.X;
|
||||
float c1 = a1 * v0.X + b1 * v0.Y;
|
||||
float a2 = v3.Y - v2.Y;
|
||||
float b2 = v2.X - v3.X;
|
||||
float c2 = a2 * v2.X + b2 * v2.Y;
|
||||
float delta = a1 * b2 - a2 * b1;
|
||||
if (delta != 0)
|
||||
{
|
||||
var deltai = 1.0f / delta;
|
||||
var vix = (b2 * c1 - b1 * c2) * deltai;
|
||||
var viy = (a1 * c2 - a2 * c1) * deltai;
|
||||
|
||||
var minx1 = Math.Min(v2.X, v3.X);
|
||||
var miny1 = Math.Min(v2.Y, v3.Y);
|
||||
var maxx1 = Math.Max(v2.X, v3.X);
|
||||
var maxy1 = Math.Max(v2.Y, v3.Y);
|
||||
|
||||
if ((vix >= minx0) && (vix >= minx1) && (vix <= maxx0) && (vix <= maxx1) &&
|
||||
(viy >= miny0) && (viy >= miny1) && (viy <= maxy0) && (viy <= maxy1))
|
||||
{
|
||||
return i2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
var findConvexSplit = new Func<GenPoly, int, int>((poly, starti) =>
|
||||
{
|
||||
var vcnt = poly.Vertices.Length;
|
||||
|
||||
|
||||
//step backwards to find a valid split
|
||||
var i0 = starti - 1; if (i0 < 0) i0 += vcnt;
|
||||
var curangl = getAngle(poly, i0, starti);
|
||||
var prevangl = curangl;
|
||||
var iok = starti - 2; if (iok < 0) iok += vcnt;
|
||||
var anyok = false;
|
||||
for (int i = -2; i >= -vcnt; i--)
|
||||
{
|
||||
var i1 = i + starti; if (i1 < 0) i1 += vcnt; //i1 = i1 % vcnt;
|
||||
var angl0 = getAngle(poly, starti, i1);
|
||||
var angldiff0 = getAngleDiff(curangl, angl0);
|
||||
if (angldiff0 < 0)
|
||||
{
|
||||
break;//split line would not be convex at starti
|
||||
}
|
||||
var i2 = (i1 + 1) % vcnt;
|
||||
var angl1 = getAngle(poly, i1, i2);
|
||||
var angldiff1 = getAngleDiff(angl0, angl1);
|
||||
if (angldiff1 < 0)
|
||||
{
|
||||
break;//split line would not be convex at i1
|
||||
}
|
||||
var angl2 = getAngle(poly, i1, i2);
|
||||
var angldiff2 = getAngleDiff(angl2, prevangl);
|
||||
if (angldiff2 < 0)
|
||||
{
|
||||
break;//this step back is not convex
|
||||
}
|
||||
var inti = findIntersection(poly, starti, i1);
|
||||
if (inti >= 0)
|
||||
{
|
||||
break;//split line intersects a poly edge!
|
||||
}
|
||||
prevangl = angl2;
|
||||
anyok = true;
|
||||
iok = i1;
|
||||
}
|
||||
if (anyok)
|
||||
{
|
||||
return iok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//couldn't split by stepping backwards... so try split by stepping forwards!
|
||||
i0 = (starti + 1) % vcnt;
|
||||
curangl = getAngle(poly, starti, i0);
|
||||
prevangl = curangl;
|
||||
iok = (starti + 2) % vcnt;
|
||||
for (int i = 2; i <= vcnt; i++)
|
||||
{
|
||||
var i1 = (i + starti) % vcnt;
|
||||
var angl0 = getAngle(poly, i1, starti);
|
||||
var angldiff0 = getAngleDiff(angl0, curangl);
|
||||
if (angldiff0 < 0)
|
||||
{
|
||||
break;//split line would not be convex at starti
|
||||
}
|
||||
var i2 = (i1 - 1); if (i2 < 0) i2 += vcnt;
|
||||
var angl1 = getAngle(poly, i2, i1);
|
||||
var angldiff1 = getAngleDiff(angl1, angl0);
|
||||
if (angldiff1 < 0)
|
||||
{
|
||||
break;//split line would not be convex at i1
|
||||
}
|
||||
var angl2 = getAngle(poly, i2, i1);
|
||||
var angldiff2 = getAngleDiff(prevangl, angl2);
|
||||
if (angldiff2 < 0)
|
||||
{
|
||||
break;//this step forward is not convex..
|
||||
}
|
||||
var inti = findIntersection(poly, i1, starti);
|
||||
if (inti >= 0)
|
||||
{
|
||||
break;//split line intersects poly edge!
|
||||
}
|
||||
prevangl = angl2;
|
||||
anyok = true;
|
||||
iok = i1;
|
||||
}
|
||||
if (anyok)
|
||||
{
|
||||
return iok | 0x40000000;//set this flag to indicate polys got switched
|
||||
}
|
||||
|
||||
|
||||
|
||||
//can't go either way... what now?
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
|
||||
return -1;
|
||||
});
|
||||
foreach (var poly in polys)
|
||||
{
|
||||
if (poly?.Vertices == null) continue;
|
||||
|
||||
var infi = findInflection(poly, 0);
|
||||
var infi1 = infi;
|
||||
//bool split = false;
|
||||
|
||||
while (infi >= 0)
|
||||
{
|
||||
//split = true;
|
||||
var convi = findConvexSplit(poly, infi);
|
||||
if (convi >= 0)
|
||||
{
|
||||
var flag = 0x40000000;
|
||||
var reversed = (convi & flag) == flag;
|
||||
convi = convi & 0x3FFFFFFF;//mask out that flag (don't care about sign bit)
|
||||
|
||||
//make a new poly, starting at convi and ending at spliti
|
||||
var newverts = new List<Vector3>();
|
||||
var vcnt = poly.Vertices.Length;
|
||||
var endi = infi;
|
||||
if (endi < convi) endi += vcnt;
|
||||
for (int i = convi; i <= endi; i++)
|
||||
{
|
||||
var i0 = i % vcnt;
|
||||
newverts.Add(poly.Vertices[i0]);
|
||||
}
|
||||
var varr1 = newverts.ToArray();
|
||||
|
||||
//remove the clipped vertices from the current poly
|
||||
newverts.Clear();
|
||||
if (convi < endi) convi += vcnt;
|
||||
for (int i = endi; i <= convi; i++)
|
||||
{
|
||||
var i0 = i % vcnt;
|
||||
newverts.Add(poly.Vertices[i0]);
|
||||
}
|
||||
var varr2 = newverts.ToArray();
|
||||
|
||||
|
||||
var newpoly = new GenPoly((reversed ? varr2 : varr1), poly);
|
||||
newpoly.Index = mergedPolys.Count;
|
||||
mergedPolys.Add(newpoly);
|
||||
|
||||
poly.Vertices = (reversed ? varr1 : varr2);
|
||||
|
||||
infi = findInflection(poly, 0);
|
||||
infi1 = infi;
|
||||
}
|
||||
else
|
||||
{
|
||||
//couldn't split at this inflection point, move on to the next...
|
||||
var infi2 = findInflection(poly, infi);
|
||||
if (infi2 != infi1)
|
||||
{
|
||||
infi = infi2;
|
||||
}
|
||||
else
|
||||
{
|
||||
infi = -1;//don't get stuck in the loop!
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (split) continue;
|
||||
//else
|
||||
//{ } //poly is already convex..
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
poly.Index = mergedPolys.Count;
|
||||
mergedPolys.Add(poly);
|
||||
}
|
||||
|
||||
polys = mergedPolys;
|
||||
edgeDict = new Dictionary<GenEdgeKey, GenEdge>();
|
||||
buildEdgeDict();
|
||||
|
||||
newCount = polys.Count;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
UpdateStatus("Building YNVs...");
|
||||
foreach (var poly in polys)
|
||||
{
|
||||
if (poly.Vertices == null) continue;
|
||||
|
||||
var ypoly = builder.AddPoly(poly.Vertices);
|
||||
if (ypoly == null)
|
||||
{ continue; }
|
||||
|
||||
|
||||
//TODO: add poly edges!
|
||||
|
||||
ypoly.B02_IsFootpath = (poly.Material.Index == 1);
|
||||
|
||||
ypoly.B18_IsRoad = (poly.Material.Index == 4);//4,5,6
|
||||
@ -235,15 +779,18 @@ namespace CodeWalker.Project.Panels
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var ynvs = builder.Build(false);//todo:vehicles!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
UpdateStatus("Creating YNV files...");
|
||||
|
||||
var path = ProjectForm.CurrentProjectFile?.GetFullFilePath("navmeshes") + "\\";
|
||||
foreach (var ynv in ynvs)
|
||||
{
|
||||
var bytes = ynv.Save();
|
||||
@ -258,7 +805,7 @@ namespace CodeWalker.Project.Panels
|
||||
nynv.Load(bytes);
|
||||
|
||||
|
||||
ProjectForm.Invoke((MethodInvoker) delegate
|
||||
ProjectForm.Invoke((MethodInvoker)delegate
|
||||
{
|
||||
ProjectForm.AddYnvToProject(nynv);
|
||||
});
|
||||
@ -295,10 +842,52 @@ namespace CodeWalker.Project.Panels
|
||||
|
||||
}
|
||||
|
||||
private struct GenEdgeKey
|
||||
{
|
||||
public Vector3 V1;
|
||||
public Vector3 V2;
|
||||
public GenEdgeKey(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
V1 = v1;
|
||||
V2 = v2;
|
||||
}
|
||||
|
||||
//public int V1X;
|
||||
//public int V1Y;
|
||||
//public int V1Z;
|
||||
//public int V2X;
|
||||
//public int V2Y;
|
||||
//public int V2Z;
|
||||
//public GenEdgeKey(Vector3 v1, Vector3 v2)
|
||||
//{
|
||||
// V1X = (int)(v1.X * 100);
|
||||
// V1Y = (int)(v1.Y * 100);
|
||||
// V1Z = (int)(v1.Z * 100);
|
||||
// V2X = (int)(v2.X * 100);
|
||||
// V2Y = (int)(v2.Y * 100);
|
||||
// V2Z = (int)(v2.Z * 100);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
private class GenEdge
|
||||
{
|
||||
//public GenPoly From;
|
||||
//public GenPoly To;
|
||||
public GenPoly Poly1;
|
||||
public GenPoly Poly2;
|
||||
public int EdgeIndex1;
|
||||
public int EdgeIndex2;
|
||||
public GenEdge(GenPoly p1, int e1)
|
||||
{
|
||||
Poly1 = p1;
|
||||
EdgeIndex1 = e1;
|
||||
}
|
||||
public GenEdge(GenPoly p1, GenPoly p2, int e1, int e2)
|
||||
{
|
||||
Poly1 = p1;
|
||||
Poly2 = p2;
|
||||
EdgeIndex1 = e1;
|
||||
EdgeIndex2 = e2;
|
||||
}
|
||||
}
|
||||
|
||||
private class GenPoly
|
||||
@ -311,6 +900,76 @@ namespace CodeWalker.Project.Panels
|
||||
public int[] CornerIndices;
|
||||
public Vector3[] Vertices;
|
||||
//public GenEdge[] Edges;
|
||||
|
||||
public bool Merged = false;
|
||||
|
||||
|
||||
public GenPoly() { }
|
||||
public GenPoly(Vector3[] verts, ref GenVertex vert)
|
||||
{
|
||||
Vertices = verts;
|
||||
Normal = vert.Normal;
|
||||
Material = vert.Material;
|
||||
PolyFlags = vert.PolyFlags;
|
||||
}
|
||||
public GenPoly(Vector3[] verts, GenPoly orig)
|
||||
{
|
||||
Vertices = verts;
|
||||
Normal = orig.Normal;
|
||||
Material = orig.Material;
|
||||
PolyFlags = orig.PolyFlags;
|
||||
}
|
||||
|
||||
public Vector3 GetCenter()
|
||||
{
|
||||
var c = Vector3.Zero;
|
||||
if (Vertices?.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < Vertices.Length; i++)
|
||||
{
|
||||
c += Vertices[i];
|
||||
}
|
||||
c /= Vertices.Length;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public int FindVertex(Vector3 v)
|
||||
{
|
||||
if (Vertices != null)
|
||||
{
|
||||
for (int i = 0; i < Vertices.Length; i++)
|
||||
{
|
||||
if (Vertices[i] == v) return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
public void RemoveVertex(Vector3 v)
|
||||
{
|
||||
var newverts = new List<Vector3>();
|
||||
bool removed = false;
|
||||
if (Vertices != null)
|
||||
{
|
||||
for (int i = 0; i < Vertices.Length; i++)
|
||||
{
|
||||
if (Vertices[i] == v)
|
||||
{
|
||||
removed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
newverts.Add(Vertices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (removed)
|
||||
{
|
||||
Vertices = newverts.ToArray();
|
||||
}
|
||||
else
|
||||
{ }//probably shouldn't happen
|
||||
}
|
||||
}
|
||||
|
||||
private class VertexGrid
|
||||
@ -397,12 +1056,12 @@ namespace CodeWalker.Project.Panels
|
||||
|
||||
public void ConnectVertices()
|
||||
{
|
||||
var connectThresh = 0.2f;
|
||||
var connectThresh = 0.4f;
|
||||
var density = 0.5f;//to match vertex density (x/y distance)
|
||||
for (int vx = 1; vx < VertexCountX; vx++)
|
||||
for (int vx = 0; vx < VertexCountX; vx++)
|
||||
{
|
||||
int px = vx - 1;
|
||||
for (int vy = 1; vy < VertexCountY; vy++)
|
||||
for (int vy = 0; vy < VertexCountY; vy++)
|
||||
{
|
||||
int py = vy - 1;
|
||||
int imin = VertexOffsets[vx, vy];
|
||||
@ -413,8 +1072,8 @@ namespace CodeWalker.Project.Panels
|
||||
var vn = Vertices[i].Normal;
|
||||
var vxz = vz + (vn.X / Math.Max(vn.Z, 1e-5f)) * density;
|
||||
var vyz = vz + (vn.Y / Math.Max(vn.Z, 1e-5f)) * density;
|
||||
var prevIDX = FindVertex(px, vy, vxz, connectThresh);
|
||||
var prevIDY = FindVertex(vx, py, vyz, connectThresh);
|
||||
var prevIDX = (px < 0) ? -1 : FindVertex(px, vy, vxz, connectThresh);
|
||||
var prevIDY = (py < 0) ? -1 : FindVertex(vx, py, vyz, connectThresh);
|
||||
var compPrevX = (prevIDX < 0) ? false : CompareVertexTypes(i, prevIDX);
|
||||
var compPrevY = (prevIDY < 0) ? false : CompareVertexTypes(i, prevIDY);
|
||||
Vertices[i].PrevIDX = prevIDX;
|
||||
@ -588,7 +1247,6 @@ namespace CodeWalker.Project.Panels
|
||||
return polys;
|
||||
}
|
||||
|
||||
|
||||
private void AssignVertices(ref Plane vpl, float plt, int i, int dnx, int dny, int dpy, int dir, GenPoly poly)
|
||||
{
|
||||
int pid = poly.Index;
|
||||
@ -701,8 +1359,6 @@ namespace CodeWalker.Project.Panels
|
||||
if (corners.Length < 3)
|
||||
{ }//debug
|
||||
}
|
||||
|
||||
|
||||
private void AssignVertices2(ref Plane vpl, float plt, int i, int dnx, int dny, int dpy, int dir, GenPoly poly)
|
||||
{
|
||||
int pid = poly.Index;
|
||||
@ -882,8 +1538,6 @@ namespace CodeWalker.Project.Panels
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void AssignVertices3(ref Plane vpl, float plt, int i, int dir, GenPoly poly)
|
||||
{
|
||||
int pid = poly.Index;
|
||||
@ -954,6 +1608,166 @@ namespace CodeWalker.Project.Panels
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public List<GenPoly> GenPolys2()
|
||||
{
|
||||
List<GenPoly> polys = new List<GenPoly>();
|
||||
|
||||
//do marching squares on the grid, assuming each vertex starts a cell
|
||||
|
||||
for (int vx = 0; vx < VertexCountX; vx++)
|
||||
{
|
||||
for (int vy = 0; vy < VertexCountY; vy++)
|
||||
{
|
||||
int imin = VertexOffsets[vx, vy];
|
||||
int imax = VertexCounts[vx, vy] + imin;
|
||||
for (int i = imin; i < imax; i++)
|
||||
{
|
||||
var nidx = Vertices[i].NextIDX;
|
||||
var nidy = Vertices[i].NextIDY;
|
||||
var nidxy = -1;
|
||||
var nidyx = -1;
|
||||
|
||||
|
||||
if ((nidx < 0) || (nidy < 0)) continue; //(can't form a square... try with less verts?)
|
||||
|
||||
//try to find the index of the opposite corner...
|
||||
//there's 2 possibilities, can only form the square if they are both the same...
|
||||
//what to do if they're different..? just choose one?
|
||||
|
||||
nidxy = Vertices[nidx].NextIDY;
|
||||
nidyx = Vertices[nidy].NextIDX;
|
||||
|
||||
if (nidxy != nidyx)
|
||||
{ }
|
||||
|
||||
|
||||
if (nidxy == -1)
|
||||
{
|
||||
if (nidyx == -1)
|
||||
{ continue; } //can't form a square! could use the 3?
|
||||
nidxy = nidyx;
|
||||
}
|
||||
|
||||
|
||||
bool f0 = CompareVertexTypes(i, nidx);
|
||||
bool f1 = CompareVertexTypes(nidx, nidxy);
|
||||
bool f2 = CompareVertexTypes(nidy, nidxy);
|
||||
bool f3 = CompareVertexTypes(i, nidy);
|
||||
//bool f4 = CompareVertexTypes(i, nidxy); //diagonal
|
||||
//bool f5 = CompareVertexTypes(nidx, nidy); //diagonal
|
||||
|
||||
|
||||
var v0 = Vertices[i];
|
||||
var v1 = Vertices[nidx];
|
||||
var v2 = Vertices[nidxy];
|
||||
var v3 = Vertices[nidy];
|
||||
var p0 = v0.Position;
|
||||
var p1 = v1.Position;
|
||||
var p2 = v2.Position;
|
||||
var p3 = v3.Position;
|
||||
|
||||
var s0 = (p0 + p1) * 0.5f; //edge splits
|
||||
var s1 = (p1 + p2) * 0.5f;
|
||||
var s2 = (p2 + p3) * 0.5f;
|
||||
var s3 = (p3 + p0) * 0.5f;
|
||||
var sc = (s0 + s2) * 0.5f;//square center
|
||||
|
||||
|
||||
|
||||
var id = (f0 ? 8 : 0) + (f1 ? 4 : 0) + (f2 ? 2 : 0) + (f3 ? 1 : 0);
|
||||
switch (id)
|
||||
{
|
||||
case 15: //all corners same
|
||||
polys.Add(new GenPoly(new[] { p0, p1, p2, p3 }, ref v0));
|
||||
break;
|
||||
case 3://single split cases
|
||||
polys.Add(new GenPoly(new[] { s0, p1, s1 }, ref v1));
|
||||
polys.Add(new GenPoly(new[] { s1, p2, p3, p0, s0 }, ref v2));
|
||||
break;
|
||||
case 5:
|
||||
polys.Add(new GenPoly(new[] { s0, p1, p2, s2 }, ref v1));
|
||||
polys.Add(new GenPoly(new[] { s2, p3, p0, s0 }, ref v3));
|
||||
break;
|
||||
case 6:
|
||||
polys.Add(new GenPoly(new[] { s0, p1, p2, p3, s3 }, ref v1));
|
||||
polys.Add(new GenPoly(new[] { s3, p0, s0 }, ref v0));
|
||||
break;
|
||||
case 9:
|
||||
polys.Add(new GenPoly(new[] { s1, p2, s2 }, ref v2));
|
||||
polys.Add(new GenPoly(new[] { s2, p3, p0, p1, s1 }, ref v3));
|
||||
break;
|
||||
case 10:
|
||||
polys.Add(new GenPoly(new[] { s1, p2, p3, s3 }, ref v2));
|
||||
polys.Add(new GenPoly(new[] { s3, p0, p1, s1 }, ref v0));
|
||||
break;
|
||||
case 12:
|
||||
polys.Add(new GenPoly(new[] { s2, p3, s3 }, ref v3));
|
||||
polys.Add(new GenPoly(new[] { s3, p0, p1, p2, s2 }, ref v0));
|
||||
break;
|
||||
case 1://double split cases
|
||||
polys.Add(new GenPoly(new[] { p0, s0, sc, s2, p3 }, ref v0));
|
||||
polys.Add(new GenPoly(new[] { p1, s1, sc, s0 }, ref v1));
|
||||
polys.Add(new GenPoly(new[] { p2, s2, sc, s1 }, ref v2));
|
||||
break;
|
||||
case 2:
|
||||
polys.Add(new GenPoly(new[] { p0, s0, sc, s3 }, ref v0));
|
||||
polys.Add(new GenPoly(new[] { p1, s1, sc, s0 }, ref v1));
|
||||
polys.Add(new GenPoly(new[] { p2, p3, s3, sc, s1 }, ref v2));
|
||||
break;
|
||||
case 4:
|
||||
polys.Add(new GenPoly(new[] { p0, s0, sc, s3 }, ref v0));
|
||||
polys.Add(new GenPoly(new[] { p1, p2, s2, sc, s0 }, ref v1));
|
||||
polys.Add(new GenPoly(new[] { p3, s3, sc, s2 }, ref v3));
|
||||
break;
|
||||
case 8:
|
||||
polys.Add(new GenPoly(new[] { p0, p1, s1, sc, s3 }, ref v0));
|
||||
polys.Add(new GenPoly(new[] { p2, s2, sc, s1 }, ref v2));
|
||||
polys.Add(new GenPoly(new[] { p3, s3, sc, s2 }, ref v3));
|
||||
break;
|
||||
case 0: //all corners different? maybe check diagonals?
|
||||
polys.Add(new GenPoly(new[] { p0, s0, sc, s3 }, ref v0));
|
||||
polys.Add(new GenPoly(new[] { p1, s1, sc, s0 }, ref v1));
|
||||
polys.Add(new GenPoly(new[] { p2, s2, sc, s1 }, ref v2));
|
||||
polys.Add(new GenPoly(new[] { p3, s3, sc, s2 }, ref v3));
|
||||
break;
|
||||
default://shouldn't happen?
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return polys;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private int FindNextID(ref Plane vpl, float plt, int i, int dirnx, int dirny, int dirpy, float slope, out int dx, out int dy)
|
||||
{
|
||||
//find the next vertex along the slope in the given direction
|
||||
@ -1318,7 +2132,7 @@ namespace CodeWalker.Project.Panels
|
||||
{
|
||||
if (InvokeRequired)
|
||||
{
|
||||
Invoke(new Action(() => { UpdateStatus(text); }));
|
||||
BeginInvoke(new Action(() => { UpdateStatus(text); }));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
17
Project/ProjectForm.Designer.cs
generated
17
Project/ProjectForm.Designer.cs
generated
@ -140,6 +140,7 @@
|
||||
this.AudioRemoveFromProjectMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ToolsMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ToolsManifestGeneratorMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ToolsLODLightsGeneratorMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.ToolsNavMeshGeneratorMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.ToolsImportMenyooXmlMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@ -172,7 +173,6 @@
|
||||
this.ToolbarSaveButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.ToolbarSaveAllButton = new System.Windows.Forms.ToolStripButton();
|
||||
this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.ToolsLODLightsGeneratorMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.MainMenu.SuspendLayout();
|
||||
this.MainToolbar.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
@ -1079,12 +1079,18 @@
|
||||
this.ToolsManifestGeneratorMenu.Text = "Manifest Generator...";
|
||||
this.ToolsManifestGeneratorMenu.Click += new System.EventHandler(this.ToolsManifestGeneratorMenu_Click);
|
||||
//
|
||||
// ToolsLODLightsGeneratorMenu
|
||||
//
|
||||
this.ToolsLODLightsGeneratorMenu.Name = "ToolsLODLightsGeneratorMenu";
|
||||
this.ToolsLODLightsGeneratorMenu.Size = new System.Drawing.Size(196, 22);
|
||||
this.ToolsLODLightsGeneratorMenu.Text = "LOD Lights Generator...";
|
||||
this.ToolsLODLightsGeneratorMenu.Click += new System.EventHandler(this.ToolsLODLightsGeneratorMenu_Click);
|
||||
//
|
||||
// ToolsNavMeshGeneratorMenu
|
||||
//
|
||||
this.ToolsNavMeshGeneratorMenu.Name = "ToolsNavMeshGeneratorMenu";
|
||||
this.ToolsNavMeshGeneratorMenu.Size = new System.Drawing.Size(196, 22);
|
||||
this.ToolsNavMeshGeneratorMenu.Text = "Nav Mesh Generator...";
|
||||
this.ToolsNavMeshGeneratorMenu.Visible = false;
|
||||
this.ToolsNavMeshGeneratorMenu.Click += new System.EventHandler(this.ToolsNavMeshGeneratorMenu_Click);
|
||||
//
|
||||
// toolStripSeparator2
|
||||
@ -1336,13 +1342,6 @@
|
||||
this.toolStripSeparator5.Name = "toolStripSeparator5";
|
||||
this.toolStripSeparator5.Size = new System.Drawing.Size(6, 25);
|
||||
//
|
||||
// ToolsLODLightsGeneratorMenu
|
||||
//
|
||||
this.ToolsLODLightsGeneratorMenu.Name = "ToolsLODLightsGeneratorMenu";
|
||||
this.ToolsLODLightsGeneratorMenu.Size = new System.Drawing.Size(196, 22);
|
||||
this.ToolsLODLightsGeneratorMenu.Text = "LOD Lights Generator...";
|
||||
this.ToolsLODLightsGeneratorMenu.Click += new System.EventHandler(this.ToolsLODLightsGeneratorMenu_Click);
|
||||
//
|
||||
// ProjectForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
|
Loading…
Reference in New Issue
Block a user