private List <YnvPoly> SplitPolys(List <YnvPoly> polys, bool xaxis) { var newpolys = new List <YnvPoly>(); var verts1 = new List <Vector3>(); var verts2 = new List <Vector3>(); var edges1 = new List <YnvEdge>(); var edges2 = new List <YnvEdge>(); var polysplits = new Dictionary <YnvPoly, YnvPolySplit>(); foreach (var poly in polys) //split along borders { var verts = poly.Vertices; if (verts == null) { continue; } //ignore empty polys.. if (verts.Length < 3) { continue; } //not enough verts for a triangle! Vector2I gprev = NavGrid.GetCellPos(verts[0]); int split1 = 0; int split2 = 0; for (int i = 1; i < verts.Length; i++) { Vector2I g = NavGrid.GetCellPos(verts[i]); int g1 = xaxis ? g.X : g.Y; int g2 = xaxis ? gprev.X : gprev.Y; if (g1 != g2) //this poly is crossing a border { if (split1 == 0) { split1 = i; } else { split2 = i; break; } } gprev = g; } if (split1 > 0) { var split2beg = (split2 > 0) ? split2 - 1 : verts.Length - 1; var split2end = split2beg + 1; var sv11 = verts[split1 - 1]; var sv12 = verts[split1]; var sv21 = verts[split2beg]; var sv22 = verts[split2]; var sp1 = GetSplitPos(sv11, sv12, xaxis); var sp2 = GetSplitPos(sv21, sv22, xaxis); //if ((sp1 == sp2) || (sp1 == sv11) || (sp1 == sv12) || (sp2 == sv21) || (sp2 == sv22)) if (!IsValidSplit(sp1, sp2, sv11, sv12, sv21, sv22)) { //split did nothing, just leave this poly alone newpolys.Add(poly); } else { //split it! var poly1 = new YnvPoly(); var poly2 = new YnvPoly(); poly1.RawData = poly.RawData; poly2.RawData = poly.RawData; verts1.Clear(); verts2.Clear(); for (int i = 0; i < split1; i++) { verts1.Add(verts[i]); } verts1.Add(sp1); verts1.Add(sp2); for (int i = split2end; i < verts.Length; i++) { verts1.Add(verts[i]); } verts2.Add(sp1); for (int i = split1; i < split2end; i++) { verts2.Add(verts[i]); } verts2.Add(sp2); poly1.Vertices = verts1.ToArray(); poly2.Vertices = verts2.ToArray(); //save this information for the edge splitting pass var polysplit = new YnvPolySplit(); polysplit.Orig = poly; polysplit.New1 = poly1; polysplit.New2 = poly2; polysplit.Split1 = split1; polysplit.Split2 = split2end; polysplits[poly] = polysplit; newpolys.Add(poly1); newpolys.Add(poly2); } } else { //no need to split newpolys.Add(poly); } } foreach (var polysplit in polysplits.Values) //build new edges for split polys { //the two edges that were split each need to be turned into two new edges (1 for each poly). //also, the split itself needs to be added as a new edge to the original poly. var poly = polysplit.Orig; var poly1 = polysplit.New1; var poly2 = polysplit.New2; var edges = poly.Edges; var verts = poly.Vertices; var ec = edges?.Length ?? 0; if (ec <= 0) { continue; } //shouldn't happen - no edges? if (ec != poly.Vertices?.Length) { continue; } //shouldn't happen var split1beg = polysplit.Split1 - 1; var split1end = polysplit.Split1; var split2beg = polysplit.Split2 - 1; var split2end = polysplit.Split2; edges1.Clear(); edges2.Clear(); var se1 = edges[split1beg]; //the two original edges that got split var se2 = edges[split2beg]; var sp1 = TryGetSplit(polysplits, se1.Poly1); //could use Poly2, but they should be the same.. var sp2 = TryGetSplit(polysplits, se2.Poly1); var sv1a = verts[split1beg]; var sv2a = verts[split2beg]; var sp1a = sp1?.GetNearest(sv1a); var sp1b = sp1?.GetOther(sp1a); var sp2b = sp2?.GetNearest(sv2a); var sp2a = sp2?.GetOther(sp2b); var edge1a = new YnvEdge(se1, sp1a); var edge1b = new YnvEdge(se1, sp1b); var edge2a = new YnvEdge(se2, sp2a); var edge2b = new YnvEdge(se2, sp2b); var splita = new YnvEdge(se1, poly2); var splitb = new YnvEdge(se1, poly1); for (int i = 0; i < split1beg; i++) { edges1.Add(edges[i]); //untouched edges } edges1.Add(edge1a); edges1.Add(splita); edges1.Add(edge2a); for (int i = split2end; i < ec; i++) { edges1.Add(edges[i]); //untouched edges } edges2.Add(edge1b); for (int i = split1end; i < split2beg; i++) { edges2.Add(edges[i]); //untouched edges } edges2.Add(edge2b); edges2.Add(splitb); poly1.Edges = edges1.ToArray(); poly2.Edges = edges2.ToArray(); if (poly1.Edges.Length != poly1.Vertices.Length) { } //debug if (poly2.Edges.Length != poly2.Vertices.Length) { } //debug } foreach (var poly in newpolys) //fix any untouched edges that joined to split polys { if (poly.Edges?.Length != poly.Vertices?.Length) { continue; } //shouldn't happen (no edges?) for (int i = 0; i < poly.Edges.Length; i++) { var edge = poly.Edges[i]; var vert = poly.Vertices[i]; if (edge == null) { continue; } //shouldn't happen if (edge.Poly1 != edge.Poly2) { continue; } //shouldn't happen? if (edge.Poly1 == null) { continue; } //probably this edge joins to nothing YnvPolySplit polysplit; if (polysplits.TryGetValue(edge.Poly1, out polysplit)) { var newpoly = polysplit.GetNearest(vert); if (newpoly == null) { } //debug edge.Poly1 = newpoly; edge.Poly2 = newpoly; } } } return(newpolys); }
private void ProcessButton_Click(object sender, EventArgs e) { if (!Directory.Exists(InputFolderTextBox.Text)) { MessageBox.Show("Input folder doesn't exist: " + InputFolderTextBox.Text); return; } if (!Directory.Exists(OutputFolderTextBox.Text)) { MessageBox.Show("Output folder doesn't exist: " + OutputFolderTextBox.Text); return; } Cursor = Cursors.WaitCursor; string inputpath = InputFolderTextBox.Text; string outputpath = OutputFolderTextBox.Text; string[] onvfiles = Directory.GetFiles(inputpath, "*.onv", SearchOption.TopDirectoryOnly); float offsetx = float.Parse(OffsetXTextBox.Text, CultureInfo.InvariantCulture); float offsety = float.Parse(OffsetYTextBox.Text, CultureInfo.InvariantCulture); float offsetz = float.Parse(OffsetZTextBox.Text, CultureInfo.InvariantCulture); Vector3 offset = new Vector3(offsetx, offsety, offsetz); var vehc = VehicleCheckBox.Checked; if (!outputpath.EndsWith("\\")) { outputpath = outputpath + "\\"; } StringBuilder errorlog = new StringBuilder(); List <OnvFile> onvlist = new List <OnvFile>(); Dictionary <int, OnvFile> onvdict = new Dictionary <int, OnvFile>(); YnvBuilder builder = new YnvBuilder(); foreach (var onvfile in onvfiles) //load onv files... { try { OnvFile onv = new OnvFile(); onv.Load(onvfile); onv.InitPolys(); onvlist.Add(onv); onvdict[onv.SectorID] = onv; } catch (Exception ex) { string err = "Error loading " + onvfile + ":\n" + ex.ToString(); errorlog.AppendLine(err); } } foreach (var onv in onvlist) //join up all the edges { onv.InitEdges(onvdict); } foreach (var onv in onvlist) //offset all the vertices { for (int i = 0; i < onv.VerticesWS.Count; i++) { onv.VerticesWS[i] = onv.VerticesWS[i] + offset; } foreach (var poly in onv.Polys) { if (poly.Vertices != null) { for (int i = 0; i < poly.Vertices.Length; i++) { poly.Vertices[i] = poly.Vertices[i] + offset; } } } foreach (var portal in onv.Portals) { //TODO: offset portals } //TODO: points ("Bounds") } foreach (var onv in onvlist) //create the new polys { foreach (var poly in onv.Polys) { var ypoly = builder.AddPoly(poly.Vertices); poly.NewPoly = ypoly; var f1 = poly.Flags1; var f2 = poly.Flags2; var f3 = poly.Flags3; //## FLAGS TODO if ((f1 & 1) > 0) { ypoly.B00_AvoidUnk = true; } if ((f1 & 2) > 0) { ypoly.B01_AvoidUnk = true; } if ((f1 & 4) > 0) { ypoly.B02_IsFootpath = true; } if ((f1 & 8) > 0) { ypoly.B03_IsUnderground = true; } //if ((f1 & 16) > 0) ypoly.B04_Unused = true; //if ((f1 & 32) > 0) ypoly.B05_Unused = true; if ((f1 & 64) > 0) { ypoly.B06_SteepSlope = true; } if ((f1 & 128) > 0) { ypoly.B07_IsWater = true; } if (ypoly.B02_IsFootpath) { ypoly.B00_AvoidUnk = false; //ypoly.B01_AvoidUnk = false; ////ypoly.B01_AvoidUnk = true; //ypoly.B02_IsFootpath = true; ypoly.B17_IsFlatGround = true; ypoly.B22_FootpathUnk1 = true; //ypoly.B23_FootpathUnk2 = true; //ypoly.B24_FootpathMall = true; } if ((f1 & 16) > 0) { } //no hits if ((f1 & 32) > 0) { } //some hits if (f1 > 255) { } //no hits ypoly.UnkX = 127; ypoly.UnkY = 127; } } foreach (var onv in onvlist) //create the new edges { foreach (var poly in onv.Polys) { var ypoly = poly.NewPoly; int ec = poly.Edges?.Length ?? 0; if (ec == 0) { continue; } //no edges? shouldn't happen if (ec != ypoly.Vertices?.Length) { continue; } //shouldn't happen! error log this? var newedges = new YnvEdge[ec]; for (int i = 0; i < ec; i++) { var edge = poly.Edges[i]; var yedge = new YnvEdge(); bool haspoly = (edge.Poly1?.NewPoly != null); bool f1 = (edge.Flags1 & 1) > 0; //nonav? bool f2 = (edge.Flags1 & 2) > 0; //nonav? bool f3 = (edge.Flags1 & 4) > 0; //drop? bool f4 = (edge.Flags1 & 8) > 0; //suicide? bool f5 = (edge.Flags1 & 1) > 0; bool nonav = f1 || f2; uint edgeval = 62; //62 yedge.Poly1 = edge.Poly1?.NewPoly; yedge.Poly2 = edge.Poly2?.NewPoly; yedge.AreaID1 = 0x3FFF; yedge.AreaID2 = 0x3FFF; yedge.PolyID1 = 0x3FFF; yedge.PolyID2 = 0x3FFF; yedge._RawData._Poly1.Unk2 = haspoly ? nonav ? 2 : 0u : 1u; //2 if nonnavigable? yedge._RawData._Poly2.Unk2 = haspoly ? 0 : 1u; yedge._RawData._Poly1.Unk3 = haspoly ? nonav ? 1u : edgeval : 0u; //odd if nonnavigable? haspoly ? 42 : 0u; //TEST yedge._RawData._Poly2.Unk3 = haspoly ? nonav ? 2 : 0u : 0u; //2 if nonnavigable? 4 if cell edge! - needs to be set later in ynv's newedges[i] = yedge; } ypoly.Edges = newedges; } } List <YnvFile> ynvs = null; if (vehc) { ynvs = new List <YnvFile>(); foreach (var onv in onvlist) { builder.PolyList.Clear(); foreach (var poly in onv.Polys) { var ypoly = poly.NewPoly; builder.PolyList.Add(ypoly); } builder.VehicleName = onv.Name; var ynv = builder.Build(true); ynvs.AddRange(ynv); } } else { ynvs = builder.Build(false); } foreach (var ynv in ynvs) { byte[] data = ynv.Save(); string filename = outputpath + ynv.Name + ".ynv"; File.WriteAllBytes(filename, data); } Cursor = Cursors.Default; if (errorlog.Length > 0) { File.WriteAllText(outputpath + "errorlog.txt", errorlog.ToString()); MessageBox.Show("Process complete with errors, see errorlog.txt."); } else { MessageBox.Show("Process complete."); } }