#region ================== Namespaces using System; using System.Collections.Generic; using System.Drawing; using CodeImp.DoomBuilder.Geometry; #endregion namespace CodeImp.DoomBuilder.Map { //mxd. Shameless Slade 3 SectorBuilder::SectorBuilder ripoff... //TODO: There are lots of overlaps with already existing code. //TODO: Replace with existing implementations if results are the same & existing code performs faster internal sealed class SectorBuilder { #region ================== Variables private List sector_edges; private HashSet vertex_valid; // Current outline private List o_edges; #endregion #region ================== Properties public List SectorEdges { get { return sector_edges; } } #endregion #region ================== Constructor public SectorBuilder() { sector_edges = new List(); vertex_valid = new HashSet(); o_edges = new List(); } #endregion #region ================== Methods ///Traces all edges to build a closed sector starting from [line] internal bool TraceSector(Linedef line, bool front) { // [ZZ] There indeed already was an implementation of this. // To do: make sure this works correctly. I don't understand what the old SectorBuilder was doing exactly, but from the looks of it FindPotentialSectorAt should be ok here. sector_edges.Clear(); List edges = Tools.FindPotentialSectorAt(line, front); if (edges == null) return false; sector_edges.AddRange(edges); return sector_edges.Count > 0; } /// Checks if the traced sector is valid (ie. all edges are currently referencing the same (existing) sector) public bool IsValidSector() { if(sector_edges.Count == 0) return false; // Get first edge's sector Sector sector = (sector_edges[0].Front ? (sector_edges[0].Line.Front != null ? sector_edges[0].Line.Front.Sector : null) : (sector_edges[0].Line.Back != null ? sector_edges[0].Line.Back.Sector : null)); // Sector is invalid if any edge has no current sector if(sector == null) return false; // Go through subsequent edges for(int a = 1; a < sector_edges.Count; a++) { // Get edge sector Sector ssector = (sector_edges[a].Front ? (sector_edges[a].Line.Front != null ? sector_edges[a].Line.Front.Sector : null) : (sector_edges[a].Line.Back != null ? sector_edges[a].Line.Back.Sector : null)); // Check if different if(sector != ssector) return false; } // Return true if the entire sector was traced return (sector.Sidedefs.Count == sector_edges.Count); } /// Finds any existing sector that is already part of the traced new sector internal Sector FindExistingSector(HashSet sides_ignore) { // Go through new sector edges Sector sector = null; Sector sector_priority = null; foreach(LinedefSide edge in sector_edges) { // Check if the edge's corresponding MapSide has a front sector if(edge.Front && edge.Line.Front != null && edge.Line.Front.Sector != null) { if(sides_ignore.Contains(edge.Line.Front)) sector = edge.Line.Front.Sector; else sector_priority = edge.Line.Front.Sector; } // Check if the edge's corresponding MapSide has a back sector if(!edge.Front && edge.Line.Back != null && edge.Line.Back.Sector != null) { if(sides_ignore.Contains(edge.Line.Back)) sector = edge.Line.Back.Sector; else sector_priority = edge.Line.Back.Sector; } } return (sector_priority ?? sector); } /// Sets all traced edges to [sector], or creates a new sector using properties /// from [sector_copy] if none given internal void CreateSector(Sector sector, Sector sector_copy) { // Create the sector if needed if(sector == null) { sector = General.Map.Map.CreateSector(); if(sector == null) return; sector.Marked = true; //mxd // Find potential sector to copy if none specified if(sector_copy == null) sector_copy = FindCopySector(); if(sector_copy != null) sector_copy.CopyPropertiesTo(sector); } //DebugConsole.WriteLine(" "); //DebugConsole.WriteLine("Creating sector " + sector.Index + " from " + sector_edges.Count + " lines"); //DebugConsole.WriteLine("*************************************************************"); //DebugConsole.WriteLine(" "); // Set sides to new sector foreach(LinedefSide edge in sector_edges) { Sidedef target = (edge.Front ? edge.Line.Front : edge.Line.Back); if(target != null) { if(target.Sector != sector) { bool targetwas2s = (target.Other != null); target.SetSector(sector); //mxd. Reattach side //mxd. Mark for texture adjustments if sidedness was changed. //mxd. Also keep existing mark if the side was already marked. target.Marked |= ((targetwas2s && target.Other == null) || (!targetwas2s && target.Other != null)); } } else { target = General.Map.Map.CreateSidedef(edge.Line, edge.Front, sector); //mxd. Create new side target.Marked = true; //mxd. Mark it for texture adjustments if(target.Other != null) { //mxd. Better than nothing target.Other.CopyPropertiesTo(target); //mxd. Other was singlesided. We'll need to adjust it's textures as well target.Other.Marked = true; } } } } /// Finds an appropriate existing sector to copy properties from, for the new sector being built private Sector FindCopySector() { // Go through new sector edges Sector sector_copy = null; foreach(LinedefSide edge in sector_edges) { // Check if the edge's corresponding MapSide has a front sector if(edge.Line.Front != null && edge.Line.Front.Sector != null) { // Set sector to copy sector_copy = edge.Line.Front.Sector; // If the edge is a front edge, use this sector and ignore all else if(edge.Front) break; } // Check if the edge's corresponding MapSide has a back sector if(edge.Line.Back != null && edge.Line.Back.Sector != null) { // Set sector to copy sector_copy = edge.Line.Back.Sector; // If the edge is a back edge, use this sector and ignore all else if(!edge.Front) break; } } return sector_copy; } #endregion } }