NavMesh generator progress

This commit is contained in:
dexy 2019-02-19 20:04:08 +11:00
parent dd97b65933
commit 7fe0bef6bd
3 changed files with 872 additions and 59 deletions

View File

@ -62,7 +62,7 @@
this.MaxTextBox.Name = "MaxTextBox"; this.MaxTextBox.Name = "MaxTextBox";
this.MaxTextBox.Size = new System.Drawing.Size(177, 20); this.MaxTextBox.Size = new System.Drawing.Size(177, 20);
this.MaxTextBox.TabIndex = 48; this.MaxTextBox.TabIndex = 48;
this.MaxTextBox.Text = "100, 100"; this.MaxTextBox.Text = "50, 50";
// //
// label1 // label1
// //

View File

@ -74,7 +74,6 @@ namespace CodeWalker.Project.Panels
// return; // return;
//} //}
var path = ProjectForm.CurrentProjectFile.GetFullFilePath("navmeshes") + "\\";
GenerateButton.Enabled = false; GenerateButton.Enabled = false;
@ -112,6 +111,8 @@ namespace CodeWalker.Project.Panels
var vert = new GenVertex(); var vert = new GenVertex();
var builder = new YnvBuilder(); 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 x = imin.X; x <= imax.X; x++) //generate verts for each world cell
{ {
for (int y = imin.Y; y <= imax.Y; y++) for (int y = imin.Y; y <= imax.Y; y++)
@ -122,8 +123,8 @@ namespace CodeWalker.Project.Panels
var cellmin = space.Grid.GetWorldPos(gi); var cellmin = space.Grid.GetWorldPos(gi);
var cellmax = cellmin + SpaceGrid.CellSize; var cellmax = cellmin + SpaceGrid.CellSize;
var vertexCountXY = (cellmax - cellmin) / density; var vertexCountXY = (cellmax - cellmin) / density;
int vertexCountX = (int)vertexCountXY.X; int vertexCountX = (int)vertexCountXY.X+1;
int vertexCountY = (int)vertexCountXY.Y; int vertexCountY = (int)vertexCountXY.Y+1;
//int vertexCountTot = vertexCountX * vertexCountY; //int vertexCountTot = vertexCountX * vertexCountY;
vgrid.BeginGrid(vertexCountX, vertexCountY); vgrid.BeginGrid(vertexCountX, vertexCountY);
cellmin.Z = 0.0f;//min probably not needed here cellmin.Z = 0.0f;//min probably not needed here
@ -154,6 +155,7 @@ namespace CodeWalker.Project.Panels
break; break;
} }
Thread.Sleep(20);//~50fps should be fine Thread.Sleep(20);//~50fps should be fine
ybn = gameFileCache.GetYbn(boundsitem.Name); //try queue it again..
} }
} }
if (ybn.Loaded && (ybn.Bounds != null)) 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 ray.Position.Z = cellmax.Z + 1.0f;//start the ray at the top of the cell
var intres = space.RayIntersect(ray, float.MaxValue, layers); var intres = space.RayIntersect(ray, float.MaxValue, layers);
hitTestCount++; hitTestCount++;
while (intres.Hit && (intres.HitDist > 0)) while (intres.Hit)// && (intres.HitDist > 0))
{
if (intres.HitDist > 0)
{ {
hitCount++; hitCount++;
vert.Position = intres.Position; vert.Position = intres.Position;
@ -199,9 +203,10 @@ namespace CodeWalker.Project.Panels
vert.PolyID = -1; vert.PolyID = -1;
vgrid.AddVertex(ref vert); vgrid.AddVertex(ref vert);
//continue down until no more hits..... step by 3m
if (vgrid.CurVertexCount > 15) //too many hits? if (vgrid.CurVertexCount > 15) //too many hits?
{ break; } { break; }
}
//continue down until no more hits..... step by 3m
ray.Position.Z = intres.Position.Z - 3.0f; ray.Position.Z = intres.Position.Z - 3.0f;
intres = space.RayIntersect(ray, float.MaxValue, layers); intres = space.RayIntersect(ray, float.MaxValue, layers);
} }
@ -218,16 +223,555 @@ namespace CodeWalker.Project.Panels
vgrid.ConnectVertices(); vgrid.ConnectVertices();
var polys = vgrid.GenPolys(); var genPolys = vgrid.GenPolys2();
newCount += polys.Count; 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) foreach (var poly in polys)
{ {
if (poly.Vertices == null) continue; if (poly.Vertices == null) continue;
var ypoly = builder.AddPoly(poly.Vertices); var ypoly = builder.AddPoly(poly.Vertices);
if (ypoly == null)
{ continue; }
//TODO: add poly edges!
ypoly.B02_IsFootpath = (poly.Material.Index == 1); ypoly.B02_IsFootpath = (poly.Material.Index == 1);
ypoly.B18_IsRoad = (poly.Material.Index == 4);//4,5,6 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! var ynvs = builder.Build(false);//todo:vehicles!
UpdateStatus("Creating YNV files...");
var path = ProjectForm.CurrentProjectFile?.GetFullFilePath("navmeshes") + "\\";
foreach (var ynv in ynvs) foreach (var ynv in ynvs)
{ {
var bytes = ynv.Save(); var bytes = ynv.Save();
@ -258,7 +805,7 @@ namespace CodeWalker.Project.Panels
nynv.Load(bytes); nynv.Load(bytes);
ProjectForm.Invoke((MethodInvoker) delegate ProjectForm.Invoke((MethodInvoker)delegate
{ {
ProjectForm.AddYnvToProject(nynv); 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 private class GenEdge
{ {
//public GenPoly From; public GenPoly Poly1;
//public GenPoly To; 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 private class GenPoly
@ -311,6 +900,76 @@ namespace CodeWalker.Project.Panels
public int[] CornerIndices; public int[] CornerIndices;
public Vector3[] Vertices; public Vector3[] Vertices;
//public GenEdge[] Edges; //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 private class VertexGrid
@ -397,12 +1056,12 @@ namespace CodeWalker.Project.Panels
public void ConnectVertices() public void ConnectVertices()
{ {
var connectThresh = 0.2f; var connectThresh = 0.4f;
var density = 0.5f;//to match vertex density (x/y distance) 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; int px = vx - 1;
for (int vy = 1; vy < VertexCountY; vy++) for (int vy = 0; vy < VertexCountY; vy++)
{ {
int py = vy - 1; int py = vy - 1;
int imin = VertexOffsets[vx, vy]; int imin = VertexOffsets[vx, vy];
@ -413,8 +1072,8 @@ namespace CodeWalker.Project.Panels
var vn = Vertices[i].Normal; var vn = Vertices[i].Normal;
var vxz = vz + (vn.X / Math.Max(vn.Z, 1e-5f)) * density; 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 vyz = vz + (vn.Y / Math.Max(vn.Z, 1e-5f)) * density;
var prevIDX = FindVertex(px, vy, vxz, connectThresh); var prevIDX = (px < 0) ? -1 : FindVertex(px, vy, vxz, connectThresh);
var prevIDY = FindVertex(vx, py, vyz, connectThresh); var prevIDY = (py < 0) ? -1 : FindVertex(vx, py, vyz, connectThresh);
var compPrevX = (prevIDX < 0) ? false : CompareVertexTypes(i, prevIDX); var compPrevX = (prevIDX < 0) ? false : CompareVertexTypes(i, prevIDX);
var compPrevY = (prevIDY < 0) ? false : CompareVertexTypes(i, prevIDY); var compPrevY = (prevIDY < 0) ? false : CompareVertexTypes(i, prevIDY);
Vertices[i].PrevIDX = prevIDX; Vertices[i].PrevIDX = prevIDX;
@ -588,7 +1247,6 @@ namespace CodeWalker.Project.Panels
return polys; return polys;
} }
private void AssignVertices(ref Plane vpl, float plt, int i, int dnx, int dny, int dpy, int dir, GenPoly poly) private void AssignVertices(ref Plane vpl, float plt, int i, int dnx, int dny, int dpy, int dir, GenPoly poly)
{ {
int pid = poly.Index; int pid = poly.Index;
@ -701,8 +1359,6 @@ namespace CodeWalker.Project.Panels
if (corners.Length < 3) if (corners.Length < 3)
{ }//debug { }//debug
} }
private void AssignVertices2(ref Plane vpl, float plt, int i, int dnx, int dny, int dpy, int dir, GenPoly poly) private void AssignVertices2(ref Plane vpl, float plt, int i, int dnx, int dny, int dpy, int dir, GenPoly poly)
{ {
int pid = poly.Index; 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) private void AssignVertices3(ref Plane vpl, float plt, int i, int dir, GenPoly poly)
{ {
int pid = poly.Index; 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) 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 //find the next vertex along the slope in the given direction
@ -1318,7 +2132,7 @@ namespace CodeWalker.Project.Panels
{ {
if (InvokeRequired) if (InvokeRequired)
{ {
Invoke(new Action(() => { UpdateStatus(text); })); BeginInvoke(new Action(() => { UpdateStatus(text); }));
} }
else else
{ {

View File

@ -140,6 +140,7 @@
this.AudioRemoveFromProjectMenu = new System.Windows.Forms.ToolStripMenuItem(); this.AudioRemoveFromProjectMenu = new System.Windows.Forms.ToolStripMenuItem();
this.ToolsMenu = new System.Windows.Forms.ToolStripMenuItem(); this.ToolsMenu = new System.Windows.Forms.ToolStripMenuItem();
this.ToolsManifestGeneratorMenu = 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.ToolsNavMeshGeneratorMenu = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.ToolsImportMenyooXmlMenu = new System.Windows.Forms.ToolStripMenuItem(); this.ToolsImportMenyooXmlMenu = new System.Windows.Forms.ToolStripMenuItem();
@ -172,7 +173,6 @@
this.ToolbarSaveButton = new System.Windows.Forms.ToolStripButton(); this.ToolbarSaveButton = new System.Windows.Forms.ToolStripButton();
this.ToolbarSaveAllButton = new System.Windows.Forms.ToolStripButton(); this.ToolbarSaveAllButton = new System.Windows.Forms.ToolStripButton();
this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
this.ToolsLODLightsGeneratorMenu = new System.Windows.Forms.ToolStripMenuItem();
this.MainMenu.SuspendLayout(); this.MainMenu.SuspendLayout();
this.MainToolbar.SuspendLayout(); this.MainToolbar.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
@ -1079,12 +1079,18 @@
this.ToolsManifestGeneratorMenu.Text = "Manifest Generator..."; this.ToolsManifestGeneratorMenu.Text = "Manifest Generator...";
this.ToolsManifestGeneratorMenu.Click += new System.EventHandler(this.ToolsManifestGeneratorMenu_Click); 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 // ToolsNavMeshGeneratorMenu
// //
this.ToolsNavMeshGeneratorMenu.Name = "ToolsNavMeshGeneratorMenu"; this.ToolsNavMeshGeneratorMenu.Name = "ToolsNavMeshGeneratorMenu";
this.ToolsNavMeshGeneratorMenu.Size = new System.Drawing.Size(196, 22); this.ToolsNavMeshGeneratorMenu.Size = new System.Drawing.Size(196, 22);
this.ToolsNavMeshGeneratorMenu.Text = "Nav Mesh Generator..."; this.ToolsNavMeshGeneratorMenu.Text = "Nav Mesh Generator...";
this.ToolsNavMeshGeneratorMenu.Visible = false;
this.ToolsNavMeshGeneratorMenu.Click += new System.EventHandler(this.ToolsNavMeshGeneratorMenu_Click); this.ToolsNavMeshGeneratorMenu.Click += new System.EventHandler(this.ToolsNavMeshGeneratorMenu_Click);
// //
// toolStripSeparator2 // toolStripSeparator2
@ -1336,13 +1342,6 @@
this.toolStripSeparator5.Name = "toolStripSeparator5"; this.toolStripSeparator5.Name = "toolStripSeparator5";
this.toolStripSeparator5.Size = new System.Drawing.Size(6, 25); 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 // ProjectForm
// //
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);