diff --git a/Project/Panels/GenerateNavMeshPanel.Designer.cs b/Project/Panels/GenerateNavMeshPanel.Designer.cs index 270ce69..c6b9e99 100644 --- a/Project/Panels/GenerateNavMeshPanel.Designer.cs +++ b/Project/Panels/GenerateNavMeshPanel.Designer.cs @@ -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 // diff --git a/Project/Panels/GenerateNavMeshPanel.cs b/Project/Panels/GenerateNavMeshPanel.cs index be39eec..3a3b589 100644 --- a/Project/Panels/GenerateNavMeshPanel.cs +++ b/Project/Panels/GenerateNavMeshPanel.cs @@ -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(); + 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,27 +183,30 @@ 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)) { - hitCount++; - vert.Position = intres.Position; - vert.Normal = intres.Normal; - vert.Material = intres.Material.Type; - vert.PolyFlags = intres.Material.PolyFlags; - vert.PrevIDX = -1; - vert.PrevIDY = -1; - vert.NextIDX = -1; - vert.NextIDY = -1; - vert.CompPrevX = false; - vert.CompPrevY = false; - vert.CompNextX = false; - vert.CompNextY = false; - vert.PolyID = -1; - vgrid.AddVertex(ref vert); + if (intres.HitDist > 0) + { + hitCount++; + vert.Position = intres.Position; + vert.Normal = intres.Normal; + vert.Material = intres.Material.Type; + vert.PolyFlags = intres.Material.PolyFlags; + vert.PrevIDX = -1; + vert.PrevIDY = -1; + vert.NextIDX = -1; + vert.NextIDY = -1; + vert.CompPrevX = false; + vert.CompPrevY = false; + vert.CompNextX = false; + vert.CompNextY = false; + vert.PolyID = -1; + vgrid.AddVertex(ref vert); + if (vgrid.CurVertexCount > 15) //too many hits? + { break; } + } //continue down until no more hits..... step by 3m - if (vgrid.CurVertexCount > 15) //too many hits? - { break; } ray.Position.Z = intres.Position.Z - 3.0f; intres = space.RayIntersect(ray, float.MaxValue, layers); } @@ -218,32 +223,574 @@ namespace CodeWalker.Project.Panels vgrid.ConnectVertices(); - var polys = vgrid.GenPolys(); - newCount += polys.Count; + var genPolys = vgrid.GenPolys2(); + polys.AddRange(genPolys); - foreach (var poly in polys) - { - if (poly.Vertices == null) continue; + newCount += genPolys.Count; - var ypoly = builder.AddPoly(poly.Vertices); - - - ypoly.B02_IsFootpath = (poly.Material.Index == 1); - - ypoly.B18_IsRoad = (poly.Material.Index == 4);//4,5,6 - - - } } } + //try merge generated polys into bigger ones, while keeping convex! + UpdateStatus("Building edge dictionary..."); + var edgeDict = new Dictionary(); + var tryGetEdge = new Func((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((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(); + //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(); + foreach (var poly in polys) + { + if (poly == null) continue; + if (poly.Merged) continue; + mergedPolys.Add(poly); + } + polys = mergedPolys; + + + UpdateStatus("Merging edges..."); + edgeDict = new Dictionary(); + 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(); + var getAngle = new Func((poly, i1, i2) => + { + var edge0 = poly.Vertices[i2] - poly.Vertices[i1]; + return (float)Math.Atan2(edge0.Y, edge0.X); + }); + var getAngleDiff = new Func((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((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((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((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(); + 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(); + 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 + + + } + + 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(); + 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 GenPolys2() + { + List polys = new List(); + + //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 { diff --git a/Project/ProjectForm.Designer.cs b/Project/ProjectForm.Designer.cs index bf77d6c..f96e4f9 100644 --- a/Project/ProjectForm.Designer.cs +++ b/Project/ProjectForm.Designer.cs @@ -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);