diff --git a/Source/Core/Actions/Action.cs b/Source/Core/Actions/Action.cs index 353be60f..efd8fc1d 100644 --- a/Source/Core/Actions/Action.cs +++ b/Source/Core/Actions/Action.cs @@ -130,15 +130,14 @@ namespace CodeImp.DoomBuilder.Actions public static string GetShortcutKeyDesc(int key) { KeysConverter conv = new KeysConverter(); - int ctrl, button; string ctrlprefix = ""; // When key is 0, then return an empty string if(key == 0) return ""; // Split the key in Control and Button - ctrl = key & ((int)Keys.Control | (int)Keys.Shift | (int)Keys.Alt); - button = key & ~((int)Keys.Control | (int)Keys.Shift | (int)Keys.Alt); + int ctrl = key & ((int)Keys.Control | (int)Keys.Shift | (int)Keys.Alt); + int button = key & ~((int)Keys.Control | (int)Keys.Shift | (int)Keys.Alt); // When the button is a control key, then remove the control itsself if((button == (int)Keys.ControlKey) || diff --git a/Source/Core/General/General.cs b/Source/Core/General/General.cs index b15c6d83..c3b3f9cd 100644 --- a/Source/Core/General/General.cs +++ b/Source/Core/General/General.cs @@ -1540,9 +1540,10 @@ namespace CodeImp.DoomBuilder // This outputs log information public static void WriteLogLine(string line) { +#if DEBUG // Output to console Console.WriteLine(line); - +#endif // Write to log file try { File.AppendAllText(logfile, line + Environment.NewLine); } catch(Exception) { } @@ -1551,8 +1552,10 @@ namespace CodeImp.DoomBuilder // This outputs log information public static void WriteLog(string text) { +#if DEBUG // Output to console Console.Write(text); +#endif // Write to log file try { File.AppendAllText(logfile, text); } diff --git a/Source/Core/Geometry/Line2D.cs b/Source/Core/Geometry/Line2D.cs index b0bb6f55..a1ab9e8c 100644 --- a/Source/Core/Geometry/Line2D.cs +++ b/Source/Core/Geometry/Line2D.cs @@ -125,7 +125,8 @@ namespace CodeImp.DoomBuilder.Geometry u_ray = ((v2.x - v1.x) * (v1.y - y3) - (v2.y - v1.y) * (v1.x - x3)) / div; // Return if intersecting - return (u_ray >= 0.0f) && (u_ray <= 1.0f) && (u_line >= 0.0f) && (u_line <= 1.0f); + if (u_ray <= 0.0f || u_ray >= 1.0f || u_line <= 0.0f || u_line >= 1.0f) return false; //mxd + return true; } else { diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs index 043e766e..15f92d11 100644 --- a/Source/Core/Geometry/Tools.cs +++ b/Source/Core/Geometry/Tools.cs @@ -910,16 +910,24 @@ namespace CodeImp.DoomBuilder.Geometry // Check if any other lines intersect this line List intersections = new List(); Line2D measureline = ld.Line; - foreach(Linedef ld2 in map.Linedefs) - { - // Intersecting? - // We only keep the unit length from the start of the line and - // do the real splitting later, when all intersections are known - float u; - if(ld2.Line.GetIntersection(measureline, out u)) - { - if(!float.IsNaN(u) && (u > 0.0f) && (u < 1.0f) && (ld2 != ld)) - intersections.Add(u); + Dictionary processed = new Dictionary(); //mxd + + //mxd + foreach (Sector s in map.Sectors) { + //line intersects with sector's bounding box? + if((MapSet.GetCSFieldBits(measureline.v1, s.BBox) & MapSet.GetCSFieldBits(measureline.v2, s.BBox)) == 0) { + foreach (Sidedef side in s.Sidedefs) { + if(processed.ContainsKey(side.Line)) continue; + if(side.Line == ld) continue; + + float u; + if(side.Line.Line.GetIntersection(measureline, out u)) { + if(float.IsNaN(u) || (u < 0.0f) || (u > 1.0f)) continue; + intersections.Add(u); + } + + processed.Add(side.Line, false); + } } } @@ -960,7 +968,7 @@ namespace CodeImp.DoomBuilder.Geometry // Join merge vertices so that overlapping vertices in the draw become one. map.BeginAddRemove(); - MapSet.JoinVertices(mergeverts, mergeverts, false, MapSet.STITCH_DISTANCE); + MapSet.JoinVertices(mergeverts, MapSet.STITCH_DISTANCE); //mxd map.EndAddRemove(); /***************************************************\ @@ -1187,7 +1195,7 @@ namespace CodeImp.DoomBuilder.Geometry drawingclosed = true; // Join merge vertices so that overlapping vertices in the draw become one. - MapSet.JoinVertices(mergeverts, mergeverts, false, MapSet.STITCH_DISTANCE); + MapSet.JoinVertices(mergeverts, MapSet.STITCH_DISTANCE); //mxd } } } @@ -1417,7 +1425,8 @@ namespace CodeImp.DoomBuilder.Geometry for(int i = newlines.Count - 1; i >= 0; i--) { // Remove the line if it has no sides - if((newlines[i].Front == null) && (newlines[i].Back == null)) newlines[i].Dispose(); + if((newlines[i].Front != null) || (newlines[i].Back != null)) continue; + newlines[i].Dispose(); } } diff --git a/Source/Core/Map/BlockMap.cs b/Source/Core/Map/BlockMap.cs index b2c7bdd8..010cb075 100644 --- a/Source/Core/Map/BlockMap.cs +++ b/Source/Core/Map/BlockMap.cs @@ -52,6 +52,7 @@ namespace CodeImp.DoomBuilder.Map public Size Size { get { return size; } } public RectangleF Range { get { return range; } } public int BlockSize { get { return blocksize; } } + internal BE[,] Map { get { return blockmap; } } #endregion diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs index dab9f247..9712cd9d 100644 --- a/Source/Core/Map/MapSet.cs +++ b/Source/Core/Map/MapSet.cs @@ -17,7 +17,6 @@ #region ================== Namespaces using System; -using System.Collections; using System.Collections.Generic; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Windows; @@ -1907,7 +1906,7 @@ namespace CodeImp.DoomBuilder.Map foreach(Linedef l in lines) { // Check the cs field bits - if ((GetCSFieldBits(l.Start, ref area) & GetCSFieldBits(l.End, ref area)) == 0) + if ((GetCSFieldBits(l.Start.Position, area) & GetCSFieldBits(l.End.Position, area)) == 0) { // The line could be in the area newlines.Add(l); @@ -1918,14 +1917,14 @@ namespace CodeImp.DoomBuilder.Map return newlines; } - // This returns the cohen-sutherland field bits for a vertex in a rectangle area - private static int GetCSFieldBits(Vertex v, ref RectangleF area) + /// This returns the cohen-sutherland field bits for a vector in a rectangle area + public static int GetCSFieldBits(Vector2D v, RectangleF area) { int bits = 0; - if(v.Position.y < area.Top) bits |= 0x01; - if(v.Position.y > area.Bottom) bits |= 0x02; - if(v.Position.x < area.Left) bits |= 0x04; - if(v.Position.x > area.Right) bits |= 0x08; + if(v.y < area.Top) bits |= 0x01; + if(v.y > area.Bottom) bits |= 0x02; + if(v.x < area.Left) bits |= 0x04; + if(v.x > area.Right) bits |= 0x08; return bits; } @@ -2270,6 +2269,48 @@ namespace CodeImp.DoomBuilder.Map return joinsdone; } + /// This joins nearby vertices in the same collection + public static int JoinVertices(List set, float joindist) { + float joindist2 = joindist * joindist; + int joinsdone = 0; + bool joined; + Vertex v1, v2; + + do { + // No joins yet + joined = false; + + // Go for all vertices in the first set + for(int i = 0; i < set.Count - 1; i++) { + for(int c = i + 1; c < set.Count; c++) { + v1 = set[i]; + v2 = set[c]; + + // Check if vertices are close enough + if (v1.DistanceToSq(v2.Position) <= joindist2) { + // Check if not the same vertex + if (v1.Index != v2.Index) { + // Move the second vertex to match the first + v2.Move(v1.Position); + + // Join the second into the first + v2.Join(v1); + set.Remove(v2); + + // Count the join + joinsdone++; + joined = true; + break; + } + } + } + } + } while(joined); + + // Return result + return joinsdone; + } + /// This corrects lines that have a back sidedef but no front sidedef by flipping them. Returns the number of flips made. public static int FlipBackwardLinedefs(ICollection lines) { @@ -2299,58 +2340,69 @@ namespace CodeImp.DoomBuilder.Map float splitdist2 = splitdist * splitdist; bool splitted; + //mxd. Create blockmap + RectangleF area = CreateArea(verts); + BlockMap blockmap = new BlockMap(area); + blockmap.AddVerticesSet(verts); + blockmap.AddLinedefsSet(lines); + int bmWidth = blockmap.Size.Width; + int bmHeight = blockmap.Size.Height; + BlockEntry[,] bmap = blockmap.Map; + BlockEntry block; + int w, h; + do { // No split yet splitted = false; - - // Go for all the lines - foreach(Linedef l in lines) - { - // Go for all the vertices - foreach(Vertex v in verts) - { - // Check if v is close enough to l for splitting - if(l.DistanceToSq(v.Position, true) <= splitdist2) - { - // Line is not already referencing v? - Vector2D deltastart = l.Start.Position - v.Position; - Vector2D deltaend = l.End.Position - v.Position; - if(((Math.Abs(deltastart.x) > 0.001f) || - (Math.Abs(deltastart.y) > 0.001f)) && - ((Math.Abs(deltaend.x) > 0.001f) || - (Math.Abs(deltaend.y) > 0.001f))) - { - // Split line l with vertex v - Linedef nl = l.Split(v); - if(nl == null) return false; - // Add the new line to the list - lines.Add(nl); + for(w = 0; w < bmWidth; w++) { + for(h = 0; h < bmHeight; h++) { + block = bmap[w, h]; + if(block.Vertices.Count == 0 || block.Lines.Count == 0) continue; - // Both lines must be updated because their new length - // is relevant for next iterations! - l.UpdateCache(); - nl.UpdateCache(); + // Go for all the lines + foreach(Linedef l in block.Lines) { + // Go for all the vertices + foreach(Vertex v in block.Vertices) { + // Check if v is close enough to l for splitting + if(l.DistanceToSq(v.Position, true) <= splitdist2) { + // Line is not already referencing v? + Vector2D deltastart = l.Start.Position - v.Position; + Vector2D deltaend = l.End.Position - v.Position; + if(((Math.Abs(deltastart.x) > 0.001f) || (Math.Abs(deltastart.y) > 0.001f)) && + ((Math.Abs(deltaend.x) > 0.001f) || (Math.Abs(deltaend.y) > 0.001f))) { + // Split line l with vertex v + Linedef nl = l.Split(v); + if(nl == null) return false; - // Add both lines to changedlines - if(changedlines != null) - { - changedlines.Add(l); - changedlines.Add(nl); + // Add the new line to the list + lines.Add(nl); + + // Both lines must be updated because their new length + // is relevant for next iterations! + l.UpdateCache(); + nl.UpdateCache(); + + // Add both lines to changedlines + if(changedlines != null) { + changedlines.Add(l); + changedlines.Add(nl); + } + + // Count the split + splitted = true; + break; + } } - - // Count the split - splitted = true; - break; } + + // Will have to restart when splitted + // TODO: If we make (linked) lists from the collections first, + // we don't have to restart when splitted? + if(splitted) break; } } - - // Will have to restart when splitted - // TODO: If we make (linked) lists from the collections first, - // we don't have to restart when splitted? - if(splitted) break; } } while(splitted); diff --git a/Source/Core/Map/Sidedef.cs b/Source/Core/Map/Sidedef.cs index 170d9562..f2dce798 100644 --- a/Source/Core/Map/Sidedef.cs +++ b/Source/Core/Map/Sidedef.cs @@ -269,31 +269,30 @@ namespace CodeImp.DoomBuilder.Map #region ================== Methods // This checks and returns a flag without creating it - public bool IsFlagSet(string flagname) { - if(flags.ContainsKey(flagname)) - return flags[flagname]; - else - return false; + public bool IsFlagSet(string flagname) + { + return (flags.ContainsKey(flagname) && flags[flagname]); } // This sets a flag - public void SetFlag(string flagname, bool value) { + public void SetFlag(string flagname, bool value) + { if(!flags.ContainsKey(flagname) || (IsFlagSet(flagname) != value)) { BeforePropsChange(); - flags[flagname] = value; } } // This returns a copy of the flags dictionary - public Dictionary GetFlags() { + public Dictionary GetFlags() + { return new Dictionary(flags); } // This clears all flags - public void ClearFlags() { + public void ClearFlags() + { BeforePropsChange(); - flags.Clear(); } @@ -306,11 +305,13 @@ namespace CodeImp.DoomBuilder.Map // This removes textures that are not required public void RemoveUnneededTextures(bool removemiddle, bool force) { - BeforePropsChange(); + bool changed = false; //mxd // The middle texture can be removed regardless of any sector tag or linedef action if(!MiddleRequired() && removemiddle) { + BeforePropsChange(); //mxd + changed = true; //mxd this.texnamemid = "-"; this.longtexnamemid = MapSet.EmptyLongName; General.Map.IsChanged = true; @@ -324,6 +325,10 @@ namespace CodeImp.DoomBuilder.Map { if(!HighRequired()) { + if(!changed) { //mxd + BeforePropsChange(); + changed = true; + } this.texnamehigh = "-"; this.longtexnamehigh = MapSet.EmptyLongName; General.Map.IsChanged = true; @@ -331,6 +336,7 @@ namespace CodeImp.DoomBuilder.Map if(!LowRequired()) { + if(!changed) BeforePropsChange(); //mxd this.texnamelow = "-"; this.longtexnamelow = MapSet.EmptyLongName; General.Map.IsChanged = true; @@ -349,10 +355,8 @@ namespace CodeImp.DoomBuilder.Map // Texture is required when ceiling of other side is lower return (Other.sector.CeilHeight < this.sector.CeilHeight); } - else - { - return false; - } + + return false; } /// @@ -375,10 +379,8 @@ namespace CodeImp.DoomBuilder.Map // Texture is required when floor of other side is higher return (Other.sector.FloorHeight > this.sector.FloorHeight); } - else - { - return false; - } + + return false; } /// @@ -394,10 +396,8 @@ namespace CodeImp.DoomBuilder.Map int height = top - bottom; return (height > 0) ? height : 0; } - else - { - return 0; - } + + return 0; } /// @@ -435,10 +435,8 @@ namespace CodeImp.DoomBuilder.Map int height = top - bottom; return (height > 0) ? height : 0; } - else - { - return 0; - } + + return 0; } // This creates a checksum from the sidedef properties diff --git a/Source/Plugins/BuilderModes/ClassicModes/SnapVerticesMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SnapVerticesMode.cs index 2b6883b1..559c28b3 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/SnapVerticesMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/SnapVerticesMode.cs @@ -81,12 +81,12 @@ namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes if (block == null) continue; foreach (Vertex blockVert in block.Vertices) { - if(!blockVert.IsDisposed && blockVert.Index != v.Index && blockVert.Position == v.Position) { - foreach(Linedef l in blockVert.Linedefs) - if(!movedLines.Contains(l)) movedLines.Add(l); - v.Join(blockVert); - break; - } + if(blockVert.IsDisposed || blockVert.Index == v.Index || blockVert.Position != v.Position) continue; + + foreach(Linedef l in blockVert.Linedefs) + if(!movedLines.Contains(l)) movedLines.Add(l); + v.Join(blockVert); + break; } }