From 3bef7dbf7230458b4bc5b37526b587569b97560d Mon Sep 17 00:00:00 2001 From: MaxED Date: Thu, 2 Jun 2016 09:55:01 +0000 Subject: [PATCH] Added 3 map geometry dragging modes (used when applying Drag Vertices/Linedefs/Sectors modes and Edit Selection mode): - "Merge Dragged Vertices Only". Only vertex-line intersections will be processed (DB2 mode). - "Merge Dragged Geometry". Geometry merging will be performed. - "Replace with Dragged Geometry". Dragged geometry will replace underlaying geometry. You can switch between these using 3 new actions, top toolbar buttons and Edit menu buttons. Changed: activating the same 2D mode repeatedly now toggles View modes. Renamed "Merge Geometry" action/menu item to "Snap to Geometry". More fixes to vertex/linedef/sector dragging logic. Updated ZDoom_DECORATE.cfg. --- Build/Scripting/ZDoom_DECORATE.cfg | 32 ++- Source/Core/Builder.csproj | 4 + Source/Core/Config/ProgramConfiguration.cs | 6 +- Source/Core/Controls/DebugConsole.cs | 14 +- Source/Core/Editing/ClassicMode.cs | 2 +- Source/Core/Editing/EditModeInfo.cs | 12 + Source/Core/Geometry/Tools.cs | 6 +- Source/Core/Map/MapSet.cs | 260 ++++++++++++------ Source/Core/Map/MergeGeometryMode.cs | 9 + Source/Core/Map/SectorBuilder.cs | 85 +++++- Source/Core/Map/Vertex.cs | 2 +- Source/Core/Properties/Resources.Designer.cs | 21 ++ Source/Core/Properties/Resources.resx | 9 + Source/Core/Resources/Actions.cfg | 34 ++- Source/Core/Resources/MergeGeo.png | Bin 0 -> 1272 bytes Source/Core/Resources/MergeGeoClassic.png | Bin 0 -> 1112 bytes Source/Core/Resources/MergeGeoRemoveLines.png | Bin 0 -> 1159 bytes Source/Core/Windows/MainForm.Designer.cs | 102 ++++++- Source/Core/Windows/MainForm.cs | 72 ++++- .../ClassicModes/DragGeometryMode.cs | 2 +- .../ClassicModes/EditSelectionMode.cs | 5 +- 21 files changed, 546 insertions(+), 131 deletions(-) create mode 100644 Source/Core/Map/MergeGeometryMode.cs create mode 100644 Source/Core/Resources/MergeGeo.png create mode 100644 Source/Core/Resources/MergeGeoClassic.png create mode 100644 Source/Core/Resources/MergeGeoRemoveLines.png diff --git a/Build/Scripting/ZDoom_DECORATE.cfg b/Build/Scripting/ZDoom_DECORATE.cfg index b07ca2f4..606881db 100644 --- a/Build/Scripting/ZDoom_DECORATE.cfg +++ b/Build/Scripting/ZDoom_DECORATE.cfg @@ -82,21 +82,21 @@ keywords A_ClearLastHeard = "A_ClearLastHeard"; A_ClearSoundTarget = "A_ClearSoundTarget"; A_ClearTarget = "A_ClearTarget"; - A_DamageChildren = "A_DamageChildren(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; - A_DamageMaster = "A_DamageMaster(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; - A_DamageSelf = "A_DamageSelf(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; - A_DamageSiblings = "A_DamageSiblings(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; - A_DamageTarget = "A_DamageTarget(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; - A_DamageTracer = "A_DamageTracer(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_DamageChildren = "A_DamageChildren(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_DamageMaster = "A_DamageMaster(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_DamageSelf = "A_DamageSelf(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_DamageSiblings = "A_DamageSiblings(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_DamageTarget = "A_DamageTarget(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_DamageTracer = "A_DamageTracer(int amount[, str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]]])\namount: amount of damage to inflict. Use a negative value to heal.\ndamagetype: the type of damage to inflict.\nflags: DMSS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; A_Die = "A_Die[(str damagetype = \"none\")]"; A_FaceTarget = "A_FaceTarget[(float angle = 0.0[, float pitch = 270.0])]\nA_FaceTarget([float max_turn = 0.0[, float max_pitch = 270.0[, float ang_offset = 0.0[, float pitch_offset = 0.0[, int flags = 0[, float z_add = 0.0]]]]]])"; A_FaceMaster = "A_FaceMaster[(float angle = 0.0[, float pitch = 270.0])]\nA_FaceMaster([float max_turn = 0.0[, float max_pitch = 270.0[, float ang_offset = 0.0[, float pitch_offset = 0.0[, int flags = 0[, float z_add = 0.0]]]]]])"; A_FastChase = "A_FastChase"; - A_KillChildren = "A_KillChildren[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\[, str species = \"None\]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; - A_KillMaster = "A_KillMaster[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; - A_KillSiblings = "A_KillSiblings[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; - A_KillTarget = "A_KillTarget[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; - A_KillTracer = "A_KillTracer[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_KillChildren = "A_KillChildren[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_KillMaster = "A_KillMaster[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_KillSiblings = "A_KillSiblings[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_KillTarget = "A_KillTarget[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; + A_KillTracer = "A_KillTracer[(str damagetype = \"None\"[, int flags = 0[, str filter = \"None\"[, str species = \"None\"[, int src = AAPTR_DEFAULT[, int inflictor = AAPTR_DEFAULT]]]]])]\ndamagetype: if the actor dies, the actor will enter a death state based on damagetype if present (or pain state if using NODAMAGE).\nflags: KILS flags.\nfilter: the actor class to damage.\nspecies: the actor species to damage."; A_Look = "A_Look"; A_Look2 = "A_Look2"; A_LookEx = "A_LookEx(int flags, float minseedist, float maxseedist, float maxheardist, float fov, state seestate)"; @@ -433,6 +433,7 @@ keywords GetSpawnHealth = "int GetSpawnHealth()"; GetZAt = "float GetZAt([float x = 0.0[, float y = 0.0[, float angle = 0.0[, int flags = 0[, int pick_pointer = AAPTR_TARGET]]]]])"; GetGibHealth = "int GetGibHealth()"; + GetCrouchFactor = "float GetCrouchFactor(int ptr = AAPTR_PLAYER1)"; } properties @@ -744,7 +745,14 @@ constants AAPTR_TARGET; AAPTR_MASTER; AAPTR_TRACER; - AAPTR_PLAYER; + AAPTR_PLAYER1; + AAPTR_PLAYER2; + AAPTR_PLAYER3; + AAPTR_PLAYER4; + AAPTR_PLAYER5; + AAPTR_PLAYER6; + AAPTR_PLAYER7; + AAPTR_PLAYER8; AAPTR_PLAYER_GETTARGET; AAPTR_PLAYER_GETCONVERSATION; //A_SpawnItemEx flags diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index df20cf20..ad05fe97 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -888,6 +888,7 @@ + @@ -1168,6 +1169,9 @@ + + + diff --git a/Source/Core/Config/ProgramConfiguration.cs b/Source/Core/Config/ProgramConfiguration.cs index e86cff85..e8dcaa33 100644 --- a/Source/Core/Config/ProgramConfiguration.cs +++ b/Source/Core/Config/ProgramConfiguration.cs @@ -91,6 +91,7 @@ namespace CodeImp.DoomBuilder.Config private bool locatetexturegroup; //mxd private bool keeptexturefilterfocused; //mxd private SplitLineBehavior splitlinebehavior; //mxd + private MergeGeometryMode mergegeomode; //mxd private bool usehighlight; //mxd //mxd. Script editor settings @@ -204,6 +205,7 @@ namespace CodeImp.DoomBuilder.Config public bool LocateTextureGroup { get { return locatetexturegroup; } internal set { locatetexturegroup = value; } } //mxd public bool KeepTextureFilterFocused { get { return keeptexturefilterfocused; } internal set { keeptexturefilterfocused = value; } } //mxd public SplitLineBehavior SplitLineBehavior { get { return splitlinebehavior; } set { splitlinebehavior = value; } } //mxd + public MergeGeometryMode MergeGeometryMode { get { return mergegeomode; } internal set { mergegeomode = value; } } //mxd //mxd. Highlight mode public bool UseHighlight @@ -349,7 +351,8 @@ namespace CodeImp.DoomBuilder.Config showtexturesizes = cfg.ReadSetting("showtexturesizes", true); locatetexturegroup = cfg.ReadSetting("locatetexturegroup", true); //mxd keeptexturefilterfocused = cfg.ReadSetting("keeptexturefilterfocused", true); //mxd - splitlinebehavior = (SplitLineBehavior)General.Clamp(cfg.ReadSetting("splitlinebehavior", 0), 0, 3); //mxd + splitlinebehavior = (SplitLineBehavior)General.Clamp(cfg.ReadSetting("splitlinebehavior", 0), 0, Enum.GetValues(typeof(SplitLineBehavior)).Length - 1); //mxd + mergegeomode = (MergeGeometryMode)General.Clamp(cfg.ReadSetting("mergegeometrymode", (int)MergeGeometryMode.REPLACE), 0, Enum.GetValues(typeof(MergeGeometryMode)).Length - 1); //mxd usehighlight = cfg.ReadSetting("usehighlight", true); //mxd //mxd. Script editor @@ -466,6 +469,7 @@ namespace CodeImp.DoomBuilder.Config cfg.WriteSetting("locatetexturegroup", locatetexturegroup); //mxd cfg.WriteSetting("keeptexturefilterfocused", keeptexturefilterfocused); //mxd cfg.WriteSetting("splitlinebehavior", (int)splitlinebehavior); //mxd + cfg.WriteSetting("mergegeometrymode", (int)mergegeomode); //mxd cfg.WriteSetting("usehighlight", usehighlight); //mxd //mxd. Script editor diff --git a/Source/Core/Controls/DebugConsole.cs b/Source/Core/Controls/DebugConsole.cs index b1eedf0b..e1a6385a 100644 --- a/Source/Core/Controls/DebugConsole.cs +++ b/Source/Core/Controls/DebugConsole.cs @@ -173,14 +173,18 @@ namespace CodeImp.DoomBuilder counter += incrementby; } + public static void ResetCounter() { ResetCounter(string.Empty); } public static void ResetCounter(string message) { - if(message.Contains("%")) - message = message.Replace("%", counter.ToString()); - else - message = message.TrimEnd() + ": " + counter; + if(!string.IsNullOrEmpty(message)) + { + if(message.Contains("%")) + message = message.Replace("%", counter.ToString()); + else + message = message.TrimEnd() + ": " + counter; - WriteLine(DebugMessageType.SPECIAL, message); + WriteLine(DebugMessageType.SPECIAL, message); + } counter = 0; } diff --git a/Source/Core/Editing/ClassicMode.cs b/Source/Core/Editing/ClassicMode.cs index b378b19e..05de3563 100644 --- a/Source/Core/Editing/ClassicMode.cs +++ b/Source/Core/Editing/ClassicMode.cs @@ -633,7 +633,7 @@ namespace CodeImp.DoomBuilder.Editing } // This sets the view mode - private static void SetViewMode(ViewMode mode) + internal static void SetViewMode(ViewMode mode) { General.Map.CRenderer2D.SetViewMode(mode); General.MainWindow.UpdateInterface(); diff --git a/Source/Core/Editing/EditModeInfo.cs b/Source/Core/Editing/EditModeInfo.cs index 42654775..1abb009a 100644 --- a/Source/Core/Editing/EditModeInfo.cs +++ b/Source/Core/Editing/EditModeInfo.cs @@ -17,10 +17,13 @@ #region ================== Namespaces using System; +using System.Collections.Generic; using System.Drawing; using System.IO; +using System.Linq; using CodeImp.DoomBuilder.Actions; using CodeImp.DoomBuilder.Plugins; +using CodeImp.DoomBuilder.Rendering; using CodeImp.DoomBuilder.VisualModes; #endregion @@ -160,6 +163,15 @@ namespace CodeImp.DoomBuilder.Editing // Switch back to last classic mode General.Editing.ChangeMode(General.Editing.PreviousClassicMode.Name); } + //mxd. The same mode? Switch view modes instead + else if(General.Editing.Mode is ClassicMode && General.Editing.Mode.GetType().FullName == type.FullName) + { + List vmodes = new List(Enum.GetValues(typeof(ViewMode)).Cast()); + int curmode = vmodes.IndexOf(General.Map.Renderer2D.ViewMode); + curmode = (curmode == vmodes.Count - 1 ? 0 : ++curmode); + + ClassicMode.SetViewMode(vmodes[curmode]); + } else { // Create instance diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs index 0056cee7..03412d18 100644 --- a/Source/Core/Geometry/Tools.cs +++ b/Source/Core/Geometry/Tools.cs @@ -1260,8 +1260,8 @@ namespace CodeImp.DoomBuilder.Geometry // self intersections for which splits were made above. map.Update(true, false); map.BeginAddRemove(); - MapSet.SplitLinesByVertices(newlines, intersectverts, MapSet.STITCH_DISTANCE, null, false); - MapSet.SplitLinesByVertices(newlines, mergeverts, MapSet.STITCH_DISTANCE, null, false); + MapSet.SplitLinesByVertices(newlines, intersectverts, MapSet.STITCH_DISTANCE, null); + MapSet.SplitLinesByVertices(newlines, mergeverts, MapSet.STITCH_DISTANCE, null); map.EndAddRemove(); /***************************************************\ @@ -1328,7 +1328,7 @@ namespace CodeImp.DoomBuilder.Geometry // Before this point, the new geometry is not linked with the existing geometry. // Now perform standard geometry stitching to merge the new geometry with the rest // of the map. The marked vertices indicate the new geometry. - map.StitchGeometry(false); + map.StitchGeometry(); map.Update(true, false); // Find our new lines again, because they have been merged with the other geometry diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs index 84712161..c2f1bc2d 100644 --- a/Source/Core/Map/MapSet.cs +++ b/Source/Core/Map/MapSet.cs @@ -1988,9 +1988,9 @@ namespace CodeImp.DoomBuilder.Map } /// This filters lines by a rectangular area. - public static List FilterByArea(ICollection lines, ref RectangleF area) + public static HashSet FilterByArea(ICollection lines, ref RectangleF area) { - List newlines = new List(lines.Count); + HashSet newlines = new HashSet(); // Go for all lines foreach(Linedef l in lines) @@ -2045,18 +2045,18 @@ namespace CodeImp.DoomBuilder.Map /// /// Stitches marked geometry with non-marked geometry. Returns false when the operation failed. /// - public bool StitchGeometry() { return StitchGeometry(false); } //mxd. Compatibility - public bool StitchGeometry(bool correctsectorrefs) + public bool StitchGeometry() { return StitchGeometry(MergeGeometryMode.CLASSIC); } //mxd. Compatibility + public bool StitchGeometry(MergeGeometryMode mergemode) { // Find vertices - ICollection movingverts = General.Map.Map.GetMarkedVertices(true); - ICollection fixedverts = General.Map.Map.GetMarkedVertices(false); + HashSet movingverts = new HashSet(General.Map.Map.GetMarkedVertices(true)); + HashSet fixedverts = new HashSet(General.Map.Map.GetMarkedVertices(false)); // Find lines that moved during the drag - List movinglines = LinedefsFromMarkedVertices(false, true, true); + HashSet movinglines = new HashSet(LinedefsFromMarkedVertices(false, true, true)); // Find all non-moving lines - List fixedlines = LinedefsFromMarkedVertices(true, false, false); + HashSet fixedlines = new HashSet(LinedefsFromMarkedVertices(true, false, false)); // Determine area in which we are editing RectangleF editarea = CreateArea(movinglines); @@ -2075,16 +2075,16 @@ namespace CodeImp.DoomBuilder.Map // Split moving lines with unselected vertices ICollection nearbyfixedverts = FilterByArea(fixedverts, ref editarea); - if(!SplitLinesByVertices(movinglines, nearbyfixedverts, STITCH_DISTANCE, movinglines, correctsectorrefs)) + if(!SplitLinesByVertices(movinglines, nearbyfixedverts, STITCH_DISTANCE, movinglines, mergemode)) return false; // Split non-moving lines with selected vertices fixedlines = FilterByArea(fixedlines, ref editarea); - if(!SplitLinesByVertices(fixedlines, movingverts, STITCH_DISTANCE, movinglines, correctsectorrefs)) + if(!SplitLinesByVertices(fixedlines, movingverts, STITCH_DISTANCE, movinglines, mergemode)) return false; //mxd. Split moving lines with fixed lines - if(!SplitLinesByLines(fixedlines, movinglines, correctsectorrefs)) return false; + if(!SplitLinesByLines(fixedlines, movinglines, mergemode)) return false; // Remove looped linedefs RemoveLoopedLinedefs(movinglines); @@ -2092,10 +2092,49 @@ namespace CodeImp.DoomBuilder.Map // Join overlapping lines if(!JoinOverlappingLines(movinglines)) return false; + //mxd. Remove remaining new verts from dragged shape if possible + if(mergemode == MergeGeometryMode.REPLACE) + { + // Get lines, which belong to dragged sectors + HashSet draggedsectors = GetSectorsFromLinedefs(movinglines); + HashSet sectorlines = new HashSet(); + foreach(Sector s in draggedsectors) + { + foreach(Sidedef side in s.Sidedefs) + sectorlines.Add(side.Line); + } + + HashSet tocheck = new HashSet(); + + foreach(Linedef l in sectorlines) + { + if(l.IsDisposed) continue; + if(!movingverts.Contains(l.Start)) tocheck.Add(l.Start); + if(!movingverts.Contains(l.End)) tocheck.Add(l.End); + } + + // Remove verts, which are not part of initially dragged verts + foreach(Vertex v in tocheck) + { + if(!v.IsDisposed && v.Linedefs.Count == 2) + { + Linedef ld1 = General.GetByIndex(v.Linedefs, 0); + Linedef ld2 = General.GetByIndex(v.Linedefs, 1); + + Vertex v2 = (ld2.Start == v) ? ld2.End : ld2.Start; + if(ld1.Start == v) ld1.SetStartVertex(v2); else ld1.SetEndVertex(v2); + ld2.Dispose(); + + // Trash vertex + v.Dispose(); + } + } + } + EndAddRemove(); //mxd. Correct sector references - if(correctsectorrefs) + if(mergemode != MergeGeometryMode.CLASSIC) { // Linedefs cache needs to be up to date... Update(true, false); @@ -2104,6 +2143,11 @@ namespace CodeImp.DoomBuilder.Map List changedlines = LinedefsFromMarkedVertices(false, true, true); CorrectSectorReferences(changedlines, true); CorrectOuterSides(new HashSet(changedlines)); + + // Mark only fully selected sectors + ClearMarkedSectors(false); + HashSet changedsectors = GetSectorsFromLinedefs(changedlines); + foreach(Sector s in changedsectors) s.Marked = true; } return true; @@ -2112,6 +2156,9 @@ namespace CodeImp.DoomBuilder.Map //mxd. Shameless SLADEMap::correctSectors ripoff... Corrects/builds sectors for all lines in [lines] private static void CorrectSectorReferences(List lines, bool existing_only) { + //DebugConsole.Clear(); + //DebugConsole.WriteLine("CorrectSectorReferences for " + lines.Count + " lines"); + // Create a list of sidedefs to perform sector creation with List edges = new List(); if(existing_only) @@ -2151,15 +2198,9 @@ namespace CodeImp.DoomBuilder.Map HashSet affectedsectors = new HashSet(General.Map.Map.GetSelectedSectors(true)); affectedsectors.UnionWith(General.Map.Map.GetUnselectedSectorsFromLinedefs(lines)); - //mxd. Collect their lines - HashSet sectorlines = new HashSet(); - foreach(Sector s in affectedsectors) - { - foreach(Sidedef side in s.Sidedefs) - { - if(side.Line != null) sectorlines.Add(side.Line); - } - } + //mxd. Collect their sidedefs + HashSet sectorsides = new HashSet(); + foreach(Sector s in affectedsectors) sectorsides.UnionWith(s.Sidedefs); // Build sectors SectorBuilder builder = new SectorBuilder(); @@ -2168,6 +2209,7 @@ namespace CodeImp.DoomBuilder.Map foreach(LinedefSide ls in edges) { // Skip if edge is ignored + //DebugConsole.WriteLine((ls.Ignore ? "Ignoring line " : "Processing line ") + ls.Line.Index); if(ls.Ignore) continue; // Run sector builder on current edge @@ -2176,13 +2218,15 @@ namespace CodeImp.DoomBuilder.Map // Find any subsequent edges that were part of the sector created bool has_existing_lines = false; bool has_existing_sides = false; - bool has_zero_sided_lines = false; - bool has_sides_belonging_to_dragged_sectors = false; //mxd + //bool has_zero_sided_lines = false; + bool has_dragged_sides = false; //mxd List edges_in_sector = new List(); foreach(LinedefSide edge in builder.SectorEdges) { bool line_is_ours = false; - if(sectorlines.Contains(edge.Line)) has_sides_belonging_to_dragged_sectors = true; //mxd + bool side_exists = (edge.Front ? edge.Line.Front != null : edge.Line.Back != null); //mxd + if(side_exists && sectorsides.Contains(edge.Front ? edge.Line.Front : edge.Line.Back)) + has_dragged_sides = true; //mxd foreach(LinedefSide ls2 in edges) { @@ -2199,14 +2243,13 @@ namespace CodeImp.DoomBuilder.Map if(line_is_ours) { - if(edge.Line.Front == null && edge.Line.Back == null) - has_zero_sided_lines = true; + //if(edge.Line.Front == null && edge.Line.Back == null) + //has_zero_sided_lines = true; } else { has_existing_lines = true; - if(edge.Front ? edge.Line.Front != null : edge.Line.Back != null) - has_existing_sides = true; + has_existing_sides |= side_exists; //mxd } } @@ -2217,7 +2260,8 @@ namespace CodeImp.DoomBuilder.Map // in an enclosed void, and should not be drawn. // However, if existing_only is false, the caller expects us to create // new sides anyway; skip this check. - if(existing_only && has_existing_lines && !has_existing_sides && !has_sides_belonging_to_dragged_sectors) continue; + if(existing_only && has_existing_lines && !has_existing_sides && !has_dragged_sides) + continue; // Ignore traced edges when trying to create any further sectors foreach(LinedefSide ls3 in edges_in_sector) ls3.Ignore = true; @@ -2331,7 +2375,7 @@ namespace CodeImp.DoomBuilder.Map foreach(Sidedef side in newsides) { // Clear any unneeded textures - side.RemoveUnneededTextures(side.Other != null); + side.RemoveUnneededTextures(side.Other != null, false, true); // Set middle texture if needed if(side.MiddleRequired() && side.MiddleTexture == "-") @@ -2627,8 +2671,8 @@ namespace CodeImp.DoomBuilder.Map // Go for all the lines foreach(Linedef l in lines) { - // Check if referencing the same vertex twice - if(l.Start == l.End) + // Check if referencing the same vertex twice (mxd. Or if both verts are null) + if(l.Start == l.End || l.Start.Position == l.End.Position) { // Remove this line while(lines.Remove(l)); @@ -2784,8 +2828,8 @@ namespace CodeImp.DoomBuilder.Map /// This splits the given lines with the given vertices. All affected lines /// will be added to changedlines. Returns false when the operation failed. - public static bool SplitLinesByVertices(ICollection lines, ICollection verts, float splitdist, ICollection changedlines) { return SplitLinesByVertices(lines, verts, splitdist, changedlines, false); } - public static bool SplitLinesByVertices(ICollection lines, ICollection verts, float splitdist, ICollection changedlines, bool removeinnerlines) + public static bool SplitLinesByVertices(ICollection lines, ICollection verts, float splitdist, ICollection changedlines) { return SplitLinesByVertices(lines, verts, splitdist, changedlines, MergeGeometryMode.CLASSIC); } + public static bool SplitLinesByVertices(ICollection lines, ICollection verts, float splitdist, ICollection changedlines, MergeGeometryMode mergemode) { if(verts.Count == 0 || lines.Count == 0) return true; //mxd @@ -2802,9 +2846,14 @@ namespace CodeImp.DoomBuilder.Map BlockEntry[,] bmap = blockmap.Map; //mxd - //HashSet splitverts = new HashSet(); - //HashSet changedsectors = (removeinnerlines ? General.Map.Map.GetSectorsFromLinedefs(changedlines) : new HashSet()); - //HashSet initialchanedlines = new HashSet(changedlines); + HashSet splitverts = new HashSet(); + HashSet changedsectors = (mergemode == MergeGeometryMode.REPLACE ? General.Map.Map.GetSectorsFromLinedefs(changedlines) : new HashSet()); + HashSet lineverts = new HashSet(); + foreach(Linedef l in lines) + { + lineverts.Add(l.Start); + lineverts.Add(l.End); + } for(int w = 0; w < bmWidth; w++) { @@ -2836,7 +2885,7 @@ namespace CodeImp.DoomBuilder.Map Linedef nl = l.Split(v); if(nl == null) return false; v.Marked = true; //mxd - //splitverts.Add(v); //mxd + splitverts.Add(v); //mxd // Add the new line to the list lines.Add(nl); @@ -2860,7 +2909,7 @@ namespace CodeImp.DoomBuilder.Map } //mxd. Remove lines, which are inside affected sectors - /*if(removeinnerlines) + if(mergemode == MergeGeometryMode.REPLACE && changedsectors.Count > 0) { HashSet alllines = new HashSet(lines); if(changedlines != null) alllines.UnionWith(changedlines); @@ -2870,7 +2919,7 @@ namespace CodeImp.DoomBuilder.Map foreach(Linedef l in alllines) { // Remove line when both it's start and end are inside a changed sector and neither side references it - if(l.Start != null && l.End != null && !initialchanedlines.Contains(l) && + if(l.Start != null && l.End != null && (l.Front == null || !changedsectors.Contains(l.Front.Sector)) && (l.Back == null || !changedsectors.Contains(l.Back.Sector))) { @@ -2878,30 +2927,29 @@ namespace CodeImp.DoomBuilder.Map { if(s.Intersect(l.Start.Position) && s.Intersect(l.End.Position)) { - Vertex[] tocheck = new[] { l.Start, l.End }; - - // Remove from collections and dispose - lines.Remove(l); - if(changedlines != null) changedlines.Remove(l); + Vertex[] tocheck = { l.Start, l.End }; + while(lines.Remove(l)); + if(changedlines != null) while(changedlines.Remove(l)); l.Dispose(); foreach(Vertex v in tocheck) { - // If the vertex only has 2 linedefs attached, then merge the linedefs - if(v.Linedefs.Count == 2) + // If the newly created vertex only has 2 linedefs attached, then merge the linedefs + if(!v.IsDisposed && v.Linedefs.Count == 2 && splitverts.Contains(v)) { Linedef ld1 = General.GetByIndex(v.Linedefs, 0); Linedef ld2 = General.GetByIndex(v.Linedefs, 1); - Vertex v2 = (ld2.Start == v) ? ld2.End : ld2.Start; - if(ld1.Start == v) ld1.SetStartVertex(v2); else ld1.SetEndVertex(v2); - - // Remove from collections and dispose - lines.Remove(ld2); - if(changedlines != null) changedlines.Remove(ld2); - ld2.Dispose(); + if(!ld1.Marked && !ld2.Marked) + { + Vertex v2 = (ld2.Start == v) ? ld2.End : ld2.Start; + if(ld1.Start == v) ld1.SetStartVertex(v2); else ld1.SetEndVertex(v2); + while(lines.Remove(ld2)); + if(changedlines != null) while(changedlines.Remove(ld2)); + ld2.Dispose(); - // Trash vertex - v.Dispose(); + // Trash vertex + v.Dispose(); + } } } @@ -2910,29 +2958,41 @@ namespace CodeImp.DoomBuilder.Map } } } - }*/ + } return true; } /// Splits lines by lines. Adds new lines to the second collection. Returns false when the operation failed. - public static bool SplitLinesByLines(IList lines, IList changedlines, bool removeinnerlines) //mxd + public static bool SplitLinesByLines(HashSet lines, HashSet changedlines, MergeGeometryMode mergemode) //mxd { - if(lines.Count == 0 || changedlines.Count == 0) return true; + if(lines.Count == 0 || changedlines.Count == 0 || mergemode == MergeGeometryMode.CLASSIC) return true; // Create blockmap + HashSet verts = new HashSet(); //mxd + foreach(Linedef l in lines) + { + verts.Add(l.Start); + verts.Add(l.End); + } + foreach(Linedef l in changedlines) + { + verts.Add(l.Start); + verts.Add(l.End); + } + RectangleF area = RectangleF.Union(CreateArea(lines), CreateArea(changedlines)); BlockMap blockmap = new BlockMap(area); blockmap.AddLinedefsSet(lines); blockmap.AddLinedefsSet(changedlines); + blockmap.AddVerticesSet(verts); //mxd int bmWidth = blockmap.Size.Width; int bmHeight = blockmap.Size.Height; BlockEntry[,] bmap = blockmap.Map; //mxd HashSet splitverts = new HashSet(); - HashSet changedsectors = (removeinnerlines ? General.Map.Map.GetSectorsFromLinedefs(changedlines) : new HashSet()); - HashSet initialchanedlines = new HashSet(changedlines); + HashSet changedsectors = (mergemode == MergeGeometryMode.REPLACE ? General.Map.Map.GetSectorsFromLinedefs(changedlines) : new HashSet()); // Check for intersections for(int w = 0; w < bmWidth; w++) @@ -2960,8 +3020,25 @@ namespace CodeImp.DoomBuilder.Map Vector2D intersection = Line2D.GetIntersectionPoint(new Line2D(l1), new Line2D(l2), true); if(!float.IsNaN(intersection.x)) { - // Create split vertex - Vertex splitvertex = General.Map.Map.CreateVertex(intersection); + //mxd. Round to map format precision + intersection.x = (float)Math.Round(intersection.x, General.Map.FormatInterface.VertexDecimals); + intersection.y = (float)Math.Round(intersection.y, General.Map.FormatInterface.VertexDecimals); + + //mxd. Do we already have a vertex here? + bool existingvert = false; + Vertex splitvertex = null; + foreach(Vertex v in block.Vertices) + { + if(v.Position == intersection) + { + splitvertex = v; + existingvert = true; + break; + } + } + + //mxd. Create split vertex? + if(splitvertex == null) splitvertex = General.Map.Map.CreateVertex(intersection); if(splitvertex == null) return false; // Split both lines @@ -2971,9 +3048,12 @@ namespace CodeImp.DoomBuilder.Map Linedef nl2 = l2.Split(splitvertex); if(nl2 == null) return false; - // Mark split vertex - splitvertex.Marked = true; - splitverts.Add(splitvertex); //mxd + // Mark split vertex? + if(!existingvert) + { + splitvertex.Marked = true; + splitverts.Add(splitvertex); //mxd + } // Add to the second collection changedlines.Add(nl1); @@ -2989,7 +3069,7 @@ namespace CodeImp.DoomBuilder.Map } //mxd. Remove lines, which are inside affected sectors - if(removeinnerlines) + if(mergemode == MergeGeometryMode.REPLACE) { HashSet alllines = new HashSet(lines); alllines.UnionWith(changedlines); @@ -2999,34 +3079,40 @@ namespace CodeImp.DoomBuilder.Map foreach(Linedef l in alllines) { // Remove line when both it's start and end are inside a changed sector and neither side references it - if(l.Start != null && l.End != null && !initialchanedlines.Contains(l) && - (l.Front == null || !changedsectors.Contains(l.Front.Sector)) && - (l.Back == null || !changedsectors.Contains(l.Back.Sector))) + if(l.Start != null && l.End != null) { - foreach(Sector s in changedsectors) + if(l.Front == null && l.Back == null) { - if(s.Intersect(l.Start.Position) && s.Intersect(l.End.Position)) + l.Dispose(); + } + else if((l.Front == null || !changedsectors.Contains(l.Front.Sector)) && + (l.Back == null || !changedsectors.Contains(l.Back.Sector))) + { + foreach(Sector s in changedsectors) { - Vertex[] tocheck = new[] { l.Start, l.End }; - l.Dispose(); - - foreach(Vertex v in tocheck) + if(s.Intersect(l.Start.Position) && s.Intersect(l.End.Position)) { - // If the vertex only has 2 linedefs attached, then merge the linedefs - if(!v.IsDisposed && v.Linedefs.Count == 2) + Vertex[] tocheck = { l.Start, l.End }; + l.Dispose(); + + foreach(Vertex v in tocheck) { - Linedef ld1 = General.GetByIndex(v.Linedefs, 0); - Linedef ld2 = General.GetByIndex(v.Linedefs, 1); - Vertex v2 = (ld2.Start == v) ? ld2.End : ld2.Start; - if(ld1.Start == v) ld1.SetStartVertex(v2); else ld1.SetEndVertex(v2); - ld2.Dispose(); + // If the newly created vertex only has 2 linedefs attached, then merge the linedefs + if(!v.IsDisposed && v.Linedefs.Count == 2 && splitverts.Contains(v)) + { + Linedef ld1 = General.GetByIndex(v.Linedefs, 0); + Linedef ld2 = General.GetByIndex(v.Linedefs, 1); + Vertex v2 = (ld2.Start == v) ? ld2.End : ld2.Start; + if(ld1.Start == v) ld1.SetStartVertex(v2); else ld1.SetEndVertex(v2); + ld2.Dispose(); - // Trash vertex - v.Dispose(); + // Trash vertex + v.Dispose(); + } } - } - break; + break; + } } } } diff --git a/Source/Core/Map/MergeGeometryMode.cs b/Source/Core/Map/MergeGeometryMode.cs new file mode 100644 index 00000000..9d5d7ab5 --- /dev/null +++ b/Source/Core/Map/MergeGeometryMode.cs @@ -0,0 +1,9 @@ +namespace CodeImp.DoomBuilder.Map +{ + public enum MergeGeometryMode //mxd + { + CLASSIC, + MERGE, + REPLACE, + } +} diff --git a/Source/Core/Map/SectorBuilder.cs b/Source/Core/Map/SectorBuilder.cs index 94adc130..30f3bb98 100644 --- a/Source/Core/Map/SectorBuilder.cs +++ b/Source/Core/Map/SectorBuilder.cs @@ -64,19 +64,32 @@ namespace CodeImp.DoomBuilder.Map for(int a = 0; a < 10000; a++) { // Trace outline - if(!TraceOutline(line, front)) break; + if(!TraceOutline(line, front)) + { + //DebugConsole.WriteLine("TraceSector: find outmost outline failed"); + break; + } // Discard any vertices outside the traced outline vertex_valid.RemoveWhere(PointOutsideOutline); + //DebugConsole.WriteLine("vertex_valid: " + vertex_valid.Count + " verts after RemoveWhere"); // If it is clockwise, we've found the outmost outline - if(o_clockwise) break; + if(o_clockwise) + { + //DebugConsole.WriteLine("TraceSector: found outmost outline"); + break; + } // Otherwise, find the next edge outside the outline LinedefSide next = FindOuterEdge(); // If none was found, we're outside the map - if(next == null) return false; + if(next == null) + { + //DebugConsole.WriteLine("TraceSector aborted: no outer edge"); + return false; + } // Repeat with this edge line = next.Line; @@ -93,17 +106,25 @@ namespace CodeImp.DoomBuilder.Map LinedefSide edge = FindInnerEdge(); // Check if we're done - if(edge == null) break; + if(edge == null) + { + //DebugConsole.WriteLine("No inner edge found (no edge)"); + break; + } // Trace outline from edge - if(!TraceOutline(edge.Line, edge.Front)) break; + if(!TraceOutline(edge.Line, edge.Front)) + { + //DebugConsole.WriteLine("No inner edge found (TraceOutline failed)"); + break; + } // Discard any vertices outside the traced outline vertex_valid.RemoveWhere(PointOutsideOutline); + //DebugConsole.WriteLine("vertex_valid: " + vertex_valid.Count + " verts after RemoveWhere"); } //DebugConsole.WriteLine("FindInnerEdge: " + o_edges.Count + " lines"); - return true; } @@ -119,6 +140,7 @@ namespace CodeImp.DoomBuilder.Map // Init outline o_edges.Clear(); + o_bbox = RectangleF.Empty; LinedefSide start = new LinedefSide(line, front); o_edges.Add(start); int edge_sum = 0; @@ -144,12 +166,14 @@ namespace CodeImp.DoomBuilder.Map // Get next edge. If no valid next edge was found, go back along the current line LinedefSide edge_next = (NextEdge(edge, visited_lines) ?? new LinedefSide(edge.Line, !edge.Front)); - //DebugConsole.WriteLine("Next line " + edge_next.Line.Index + (edge_next.Front ? " (front)" : " (back)")); + //DebugConsole.WriteLine("Next line for " + edge.Line.Index + (edge.Front ? " (front)" : " (back)") + ": " + edge_next.Line.Index + (edge_next.Front ? " (front)" : " (back)")); // Discard edge vertices vertex_valid.Remove(edge_next.Line.Start); vertex_valid.Remove(edge_next.Line.End); + //DebugConsole.WriteLine("vertex_valid: " + vertex_valid.Count + " verts after Remove (in TraceOutline)"); + // Check if we're back to the start if(edge_next.Line == start.Line && edge_next.Front == start.Front) break; @@ -166,12 +190,15 @@ namespace CodeImp.DoomBuilder.Map Math.Max(edge.Line.Start.Position.x, edge.Line.End.Position.x), // right Math.Max(edge.Line.Start.Position.y, edge.Line.End.Position.y)); // bottom - o_bbox = (o_bbox.IsEmpty ? l_bbox : RectangleF.Union(o_bbox, l_bbox)); + //mxd. As it turned out, o_bbox.IsEmpty was not what we needed... + o_bbox = (o_bbox == RectangleF.Empty ? l_bbox : RectangleF.Union(o_bbox, l_bbox)); } // Check if outline is clockwise o_clockwise = (edge_sum < 0); + //DebugConsole.WriteLine("TraceOutline for line " + line.Index + " (" + (front ? "front":"back") + ") found " + o_edges.Count + " edges; o_clockwise=" + o_clockwise); + // Add outline edges to sector edge list sector_edges.AddRange(o_edges); @@ -230,6 +257,8 @@ namespace CodeImp.DoomBuilder.Map /// Find the closest edge within the current outline (that isn't part of the current outline) private LinedefSide FindInnerEdge() { + //DebugConsole.WriteLine("FindInnerEdge: processing " + vertex_valid.Count + " verts"); + // Find rightmost non-discarded vertex vertex_right = null; foreach(Vertex v in vertex_valid) @@ -247,7 +276,11 @@ namespace CodeImp.DoomBuilder.Map } // If no vertex was found, we're done - if(vertex_right == null) return null; + if(vertex_right == null) + { + //DebugConsole.WriteLine("FindInnerEdge: no vertex_right"); + return null; + } // Go through vertex's connected lines, to find // the line with the smallest angle parallel with @@ -280,6 +313,8 @@ namespace CodeImp.DoomBuilder.Map { // Discard vertex and try again vertex_valid.Remove(vertex_right); + //DebugConsole.WriteLine("vertex_valid: " + vertex_valid.Count + " verts after Remove (in FindInnerEdge)"); + return FindInnerEdge(); } @@ -384,11 +419,20 @@ namespace CodeImp.DoomBuilder.Map //mxd. The meaning of 0.0 is also inverted!!! // Return false if it is on the correct side - if(side > 0 && o_edges[nearest].Front) return false; - if(side <= 0 && !o_edges[nearest].Front) return false; + if(side > 0 && o_edges[nearest].Front) + { + //DebugConsole.WriteLine("Point " + point + " is within outline (infront of line) " + nearest); + return false; + } + if(side <= 0 && !o_edges[nearest].Front) + { + //DebugConsole.WriteLine("Point " + point + " is within outline (at the back of line) " + nearest); + return false; + } } // Not within the outline + //DebugConsole.WriteLine("Point " + point + " is outside outline"); return true; } @@ -491,7 +535,10 @@ namespace CodeImp.DoomBuilder.Map 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) @@ -501,14 +548,26 @@ namespace CodeImp.DoomBuilder.Map { if(target.Sector != sector) { + bool targetwas2s = (target.Other != null); target.SetSector(sector); //mxd. Reattach side - target.Marked = true; //mxd. Mark it + + //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 + 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; + } } } } diff --git a/Source/Core/Map/Vertex.cs b/Source/Core/Map/Vertex.cs index d0c80fab..d5ea0626 100644 --- a/Source/Core/Map/Vertex.cs +++ b/Source/Core/Map/Vertex.cs @@ -330,7 +330,7 @@ namespace CodeImp.DoomBuilder.Map public override string ToString() { #if DEBUG - return "Vertex (" + pos + (marked ? "; marked" : "") + ")"; + return "Vertex " + Index + " (" + pos + (marked ? "; marked" : "") + ")"; #else return "Vertex (" + pos + ")"; #endif diff --git a/Source/Core/Properties/Resources.Designer.cs b/Source/Core/Properties/Resources.Designer.cs index 5fa81635..086ad5f2 100644 --- a/Source/Core/Properties/Resources.Designer.cs +++ b/Source/Core/Properties/Resources.Designer.cs @@ -557,6 +557,20 @@ namespace CodeImp.DoomBuilder.Properties { } } + internal static System.Drawing.Bitmap MergeGeo { + get { + object obj = ResourceManager.GetObject("MergeGeo", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap MergeGeoClassic { + get { + object obj = ResourceManager.GetObject("MergeGeoClassic", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + internal static System.Drawing.Bitmap mergegeometry { get { object obj = ResourceManager.GetObject("mergegeometry", resourceCulture); @@ -571,6 +585,13 @@ namespace CodeImp.DoomBuilder.Properties { } } + internal static System.Drawing.Bitmap MergeGeoRemoveLines { + get { + object obj = ResourceManager.GetObject("MergeGeoRemoveLines", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + internal static System.Drawing.Bitmap MissingTexture { get { object obj = ResourceManager.GetObject("MissingTexture", resourceCulture); diff --git a/Source/Core/Properties/Resources.resx b/Source/Core/Properties/Resources.resx index 19b2e3e3..a114545d 100644 --- a/Source/Core/Properties/Resources.resx +++ b/Source/Core/Properties/Resources.resx @@ -586,4 +586,13 @@ ..\Resources\Angle7.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\MergeGeo.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MergeGeoClassic.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\MergeGeoRemoveLines.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Source/Core/Resources/Actions.cfg b/Source/Core/Resources/Actions.cfg index c847d08d..ec570210 100644 --- a/Source/Core/Resources/Actions.cfg +++ b/Source/Core/Resources/Actions.cfg @@ -457,6 +457,36 @@ redo allowscroll = true; } +geomergeclassic //mxd +{ + title = "Merge Dragged Vertices Only"; + category = "edit"; + description = "Only vertex-line intersections will be processed when applying geometry drag or paste actions."; + allowkeys = true; + allowmouse = true; + allowscroll = false; +} + +geomerge //mxd +{ + title = "Merge Dragged Geometry"; + category = "edit"; + description = "Geometry merging will be performed when applying geometry drag or paste actions."; + allowkeys = true; + allowmouse = true; + allowscroll = false; +} + +georeplace //mxd +{ + title = "Replace with Dragged Geometry"; + category = "edit"; + description = "Dragged geometry will replace underlaying geometry when applying geometry drag or paste actions."; + allowkeys = true; + allowmouse = true; + allowscroll = false; +} + togglesnap { title = "Snap to Grid"; @@ -469,9 +499,9 @@ togglesnap toggleautomerge { - title = "Merge Geometry"; + title = "Snap to Geometry"; category = "edit"; - description = "Toggles automatic merging of geometry for vertices and structures that are being dragged."; + description = "Toggles snapping to the nearest vertex or linedef for map elements that are being dragged."; allowkeys = true; allowmouse = true; allowscroll = true; diff --git a/Source/Core/Resources/MergeGeo.png b/Source/Core/Resources/MergeGeo.png new file mode 100644 index 0000000000000000000000000000000000000000..2bbe9944bacef910934c01e140c552da46135c54 GIT binary patch literal 1272 zcmbVMYj4|B7_p_&ku>~oI& zKF|BSH@}!3Jk+)Q?(G$i159D^1pz)@KZ;lC_=hyz&) z;YWQbI;BTpNlr`~aADvB`9YvP0gRV&GdaP){B*R1O{%6Ps3L6n zmXYrbZ0v?uE^0u*(u}O8jkmfWUD7PgENME3Mw?X!4;+)E~X4 z-+24i?gh}DcnhoF|NSYf7u)ll??@+ETU>g5@1sXt&wn$&{7U%aUU;H$@uyd-zt4cx z9{#!0XFFbQo7)RgD@$iqz0vTOAAP%0@7ZCE(8KzBPu_8+a_>W_t5@6H#~1FKpB=93 zY6n+7xXxUT&z(rT?>Rx?8T6UVD1&**iUdHCBJTHG9igXLa~m;p^l1 zIajUmgZuMZW!udIT}yiwm*`{p+4-5s(B<1cd1tY+F&^LHzF2X&(%s>aYj39Okx3UW tM@F#st2@shJDayFk;UqTUJcvUiG6k9g|@Cgqr07dQ8G5jzZ=QV{tdM5tbPCh literal 0 HcmV?d00001 diff --git a/Source/Core/Resources/MergeGeoClassic.png b/Source/Core/Resources/MergeGeoClassic.png new file mode 100644 index 0000000000000000000000000000000000000000..adcb1cc77dbe6252e43732fa9a5b9753fc4972e3 GIT binary patch literal 1112 zcmaJ=TSyd97@jCALPMg53d_R;rPS`s?mD~8v|H-Trc15ay5yozjWb6bb>>Vn$9C42 zGUu+FTm_0TqO=3Mx`@4uYy9ILOZ zDO$E>8AVY=v05oX=3;j&T}=L^-+#$uT8*PA+<;nfTDBlnrJ@!HV!GT06Hrz&2cN(& zMJ?Q*B~v&R-z6wW_sTBD>*yw7Q&f1nW6DY=#GnPXX-0(pdhY=ZG&Mpua&b0pim+X) z?Xh4(PhC>!=~Q@?-o6cl9f1hw5X->Py9`@!B6L<)AZz!Sp+OdcJ0tXLQmJ@75RnA| z=M8!kHW&gS-s|H+p^DIE;Aedt!v>fD>+uJK3RbA_gSn3;(JZx9NJu;8Vv${hZpYXZ z7$%)gd(#0gvf3CQ&+`oHXZ(H-L3r$pfn~>I*z0o&60{XdGqHvY;3~>3s2fLUlId&- zx;Zav*mG?n4PzYHWPD!MEhz_#$Nvx2^?9_76Yx*I{}i^9851%IXrpdRAs5%W-VJ36 zq6KA)tRzBRxh~eXBaG~JWCBslb`6v@YKDr^c6pW)j|(xw#L0F{m+RU=H%Vj(TG}C~?y!&! zvSkZe{#^LHdUISge=b#dxeQ5$aWD6;%g!AU2f536>ypj9`Jq7^ZxL&+z0_Prp2g#s zRF!mIUrh`bJ!A{Je*TEATz9trRKbD1siBg>y(3MVhwg+gTz_9XS$sD*(RcYv`7L|! zrE%`?$gOuC>Dt)Qy0`l9@`2GsA6{J=AD!O%%-(ax*K_#h%AHG^ABu+tK3-nPb!4WB zSA5+)8J#HGGI{sW>4M(Wk(uG+4k&@oto{}Ei^IL=2d1}FZk$^6?d?R#$iVqepfXcA z4*CmTEjW2&)9n-b?x(eFL;D8bzZo>HU{KS+KmUxOQo48g#mv>Nk>=h76t}TWAzl7@m+OZp?~Sf;L9*Fab?9JGb4 z6jb$@li$G}imKmlq%%093`-g^8P&ru1=A*Mit6br*s3-GG04Jk!-~>RmcOBap-1Us zVTDudILsMCvkp8uJCfFBCp1x~`+7l7K_UVs#40G5la?zLqI5-9B6Dw>r9lOPC!+Mb zq%z7Vh$9DrFw+&#xUL9@hzuW&L_(2HAaHz`<$`RG3kX3e#7Q9mY&&Z zMOINdhp{cOY(Af7@<9eU<18(I(O`wxHT9&v0HzRiL8$Kh!ig(JoHG_xb*(u$!K-A)A6OnsPL9 zaAWOWC|im+e6*zPLZXn&wxS z;`QDaZO8xC=593q+FT0VdnD!+J+bTTv&50R)V_ay50tmxuIukDCd#dgpO3Z}bGfFQ zU;V=M&4=pDZ0zdk_GRj$#yebn|I-IsuHL`)*=hgI($m-5i-Rk3&Hl5#{T;6lgchQ8 zzYY7(EHt$*eeh#Ld66k8#U1)?u(R>!2CmKb)0Y|lxh)+b{~rtY+Rjk*lomce-P9TU Q*84Ri6C?7CffMs@0S-=mwEzGB literal 0 HcmV?d00001 diff --git a/Source/Core/Windows/MainForm.Designer.cs b/Source/Core/Windows/MainForm.Designer.cs index 366ec483..0a174e38 100644 --- a/Source/Core/Windows/MainForm.Designer.cs +++ b/Source/Core/Windows/MainForm.Designer.cs @@ -97,6 +97,10 @@ namespace CodeImp.DoomBuilder.Windows this.itemviewfloors = new System.Windows.Forms.ToolStripMenuItem(); this.itemviewceilings = new System.Windows.Forms.ToolStripMenuItem(); this.seperatorviewviews = new System.Windows.Forms.ToolStripSeparator(); + this.itemmergegeoclassic = new System.Windows.Forms.ToolStripMenuItem(); + this.itemmergegeo = new System.Windows.Forms.ToolStripMenuItem(); + this.itemreplacegeo = new System.Windows.Forms.ToolStripMenuItem(); + this.separatorgeomerge = new System.Windows.Forms.ToolStripSeparator(); this.itemfullbrightness = new System.Windows.Forms.ToolStripMenuItem(); this.itemtogglegrid = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); @@ -180,6 +184,10 @@ namespace CodeImp.DoomBuilder.Windows this.buttonviewbrightness = new System.Windows.Forms.ToolStripButton(); this.buttonviewfloors = new System.Windows.Forms.ToolStripButton(); this.buttonviewceilings = new System.Windows.Forms.ToolStripButton(); + this.separatorgeomergemodes = new System.Windows.Forms.ToolStripSeparator(); + this.buttonmergegeoclassic = new System.Windows.Forms.ToolStripButton(); + this.buttonmergegeo = new System.Windows.Forms.ToolStripButton(); + this.buttonplacegeo = new System.Windows.Forms.ToolStripButton(); this.seperatorviews = new System.Windows.Forms.ToolStripSeparator(); this.buttontogglecomments = new System.Windows.Forms.ToolStripButton(); this.buttontogglefixedthingsscale = new System.Windows.Forms.ToolStripButton(); @@ -518,6 +526,10 @@ namespace CodeImp.DoomBuilder.Windows this.itempaste, this.itempastespecial, this.seperatoreditcopypaste, + this.itemmergegeoclassic, + this.itemmergegeo, + this.itemreplacegeo, + this.separatorgeomerge, this.itemsnaptogrid, this.itemdynamicgridsize, this.itemautomerge, @@ -619,7 +631,7 @@ namespace CodeImp.DoomBuilder.Windows this.itemautomerge.Name = "itemautomerge"; this.itemautomerge.Size = new System.Drawing.Size(219, 22); this.itemautomerge.Tag = "builder_toggleautomerge"; - this.itemautomerge.Text = "&Merge Geometry"; + this.itemautomerge.Text = "Snap to &Geometry"; this.itemautomerge.Click += new System.EventHandler(this.InvokeTaggedAction); // // itemautoclearsidetextures @@ -819,6 +831,38 @@ namespace CodeImp.DoomBuilder.Windows this.seperatorviewviews.Name = "seperatorviewviews"; this.seperatorviewviews.Size = new System.Drawing.Size(212, 6); // + // itemmergegeoclassic + // + this.itemmergegeoclassic.Image = global::CodeImp.DoomBuilder.Properties.Resources.MergeGeoClassic; + this.itemmergegeoclassic.Name = "itemmergegeoclassic"; + this.itemmergegeoclassic.Size = new System.Drawing.Size(215, 22); + this.itemmergegeoclassic.Tag = "builder_geomergeclassic"; + this.itemmergegeoclassic.Text = "Merge Dragged Vertices Only"; + this.itemmergegeoclassic.Click += new System.EventHandler(this.InvokeTaggedAction); + // + // itemmergegeo + // + this.itemmergegeo.Image = global::CodeImp.DoomBuilder.Properties.Resources.MergeGeo; + this.itemmergegeo.Name = "itemmergegeo"; + this.itemmergegeo.Size = new System.Drawing.Size(215, 22); + this.itemmergegeo.Tag = "builder_geomerge"; + this.itemmergegeo.Text = "Merge Dragged Geometry"; + this.itemmergegeo.Click += new System.EventHandler(this.InvokeTaggedAction); + // + // itemreplacegeo + // + this.itemreplacegeo.Image = global::CodeImp.DoomBuilder.Properties.Resources.MergeGeoRemoveLines; + this.itemreplacegeo.Name = "itemreplacegeo"; + this.itemreplacegeo.Size = new System.Drawing.Size(215, 22); + this.itemreplacegeo.Tag = "builder_georeplace"; + this.itemreplacegeo.Text = "Replace with Dragged Geometry"; + this.itemreplacegeo.Click += new System.EventHandler(this.InvokeTaggedAction); + // + // separatorgeomerge + // + this.separatorgeomerge.Name = "separatorgeomerge"; + this.separatorgeomerge.Size = new System.Drawing.Size(212, 6); + // // itemfullbrightness // this.itemfullbrightness.Checked = true; @@ -1254,6 +1298,10 @@ namespace CodeImp.DoomBuilder.Windows this.buttonviewbrightness, this.buttonviewfloors, this.buttonviewceilings, + this.separatorgeomergemodes, + this.buttonmergegeoclassic, + this.buttonmergegeo, + this.buttonplacegeo, this.seperatorviews, this.buttonsnaptogrid, this.buttontoggledynamicgrid, @@ -1645,6 +1693,48 @@ namespace CodeImp.DoomBuilder.Windows this.buttonviewceilings.Text = "View Ceiling Textures"; this.buttonviewceilings.Click += new System.EventHandler(this.InvokeTaggedAction); // + // separatorgeomergemodes + // + this.separatorgeomergemodes.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); + this.separatorgeomergemodes.Name = "separatorgeomergemodes"; + this.separatorgeomergemodes.Size = new System.Drawing.Size(6, 25); + // + // buttonmergegeoclassic + // + this.buttonmergegeoclassic.CheckOnClick = true; + this.buttonmergegeoclassic.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.buttonmergegeoclassic.Image = global::CodeImp.DoomBuilder.Properties.Resources.MergeGeoClassic; + this.buttonmergegeoclassic.ImageTransparentColor = System.Drawing.Color.Magenta; + this.buttonmergegeoclassic.Name = "buttonmergegeoclassic"; + this.buttonmergegeoclassic.Size = new System.Drawing.Size(23, 22); + this.buttonmergegeoclassic.Tag = "builder_geomergeclassic"; + this.buttonmergegeoclassic.Text = "Merge Dragged Vertices Only"; + this.buttonmergegeoclassic.Click += new System.EventHandler(this.InvokeTaggedAction); + // + // buttonmergegeoclassic + // + this.buttonmergegeo.CheckOnClick = true; + this.buttonmergegeo.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.buttonmergegeo.Image = global::CodeImp.DoomBuilder.Properties.Resources.MergeGeo; + this.buttonmergegeo.ImageTransparentColor = System.Drawing.Color.Magenta; + this.buttonmergegeo.Name = "buttonmergegeo"; + this.buttonmergegeo.Size = new System.Drawing.Size(23, 22); + this.buttonmergegeo.Tag = "builder_geomerge"; + this.buttonmergegeo.Text = "Merge Dragged Geometry"; + this.buttonmergegeo.Click += new System.EventHandler(this.InvokeTaggedAction); + // + // buttonmergegeoclassic + // + this.buttonplacegeo.CheckOnClick = true; + this.buttonplacegeo.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.buttonplacegeo.Image = global::CodeImp.DoomBuilder.Properties.Resources.MergeGeoRemoveLines; + this.buttonplacegeo.ImageTransparentColor = System.Drawing.Color.Magenta; + this.buttonplacegeo.Name = "buttonmergegeoclassic"; + this.buttonplacegeo.Size = new System.Drawing.Size(23, 22); + this.buttonplacegeo.Tag = "builder_georeplace"; + this.buttonplacegeo.Text = "Replace with Dragged Geometry"; + this.buttonplacegeo.Click += new System.EventHandler(this.InvokeTaggedAction); + // // seperatorviews // this.seperatorviews.Margin = new System.Windows.Forms.Padding(6, 0, 6, 0); @@ -1700,7 +1790,7 @@ namespace CodeImp.DoomBuilder.Windows this.buttonautomerge.Name = "buttonautomerge"; this.buttonautomerge.Size = new System.Drawing.Size(23, 22); this.buttonautomerge.Tag = "builder_toggleautomerge"; - this.buttonautomerge.Text = "Merge Geometry"; + this.buttonautomerge.Text = "Snap to Geometry"; this.buttonautomerge.Click += new System.EventHandler(this.InvokeTaggedAction); // // buttonautoclearsidetextures @@ -2607,6 +2697,10 @@ namespace CodeImp.DoomBuilder.Windows private System.Windows.Forms.ToolStripButton buttonviewbrightness; private System.Windows.Forms.ToolStripButton buttonviewfloors; private System.Windows.Forms.ToolStripButton buttonviewceilings; + private System.Windows.Forms.ToolStripSeparator separatorgeomergemodes; + private System.Windows.Forms.ToolStripButton buttonmergegeoclassic; + private System.Windows.Forms.ToolStripButton buttonmergegeo; + private System.Windows.Forms.ToolStripButton buttonplacegeo; private System.Windows.Forms.ToolStripSeparator seperatortoolsresources; private System.Windows.Forms.ToolStripButton buttonscripteditor; private System.Windows.Forms.ToolStripMenuItem menuview; @@ -2617,6 +2711,10 @@ namespace CodeImp.DoomBuilder.Windows private System.Windows.Forms.ToolStripMenuItem itemviewfloors; private System.Windows.Forms.ToolStripMenuItem itemviewceilings; private System.Windows.Forms.ToolStripSeparator seperatorviewzoom; + private System.Windows.Forms.ToolStripMenuItem itemmergegeoclassic; + private System.Windows.Forms.ToolStripMenuItem itemmergegeo; + private System.Windows.Forms.ToolStripMenuItem itemreplacegeo; + private System.Windows.Forms.ToolStripSeparator separatorgeomerge; private System.Windows.Forms.ToolStripMenuItem itemscripteditor; private System.Windows.Forms.ToolStripSeparator seperatortoolsconfig; private System.Windows.Forms.ToolStripMenuItem itemtestmap; diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs index a1949e3b..07e3a311 100644 --- a/Source/Core/Windows/MainForm.cs +++ b/Source/Core/Windows/MainForm.cs @@ -137,6 +137,10 @@ namespace CodeImp.DoomBuilder.Windows // View modes private ToolStripButton[] viewmodesbuttons; private ToolStripMenuItem[] viewmodesitems; + + //mxd. Geometry merge modes + private ToolStripButton[] geomergemodesbuttons; + private ToolStripMenuItem[] geomergemodesitems; // Edit modes private List editmodeitems; @@ -247,6 +251,17 @@ namespace CodeImp.DoomBuilder.Windows viewmodesitems[(int)ViewMode.Brightness] = itemviewbrightness; viewmodesitems[(int)ViewMode.FloorTextures] = itemviewfloors; viewmodesitems[(int)ViewMode.CeilingTextures] = itemviewceilings; + + //mxd. Make arrays for geometry merge modes + int numgeomodes = Enum.GetValues(typeof(MergeGeometryMode)).Length; + geomergemodesbuttons = new ToolStripButton[numgeomodes]; + geomergemodesbuttons[(int)MergeGeometryMode.CLASSIC] = buttonmergegeoclassic; + geomergemodesbuttons[(int)MergeGeometryMode.MERGE] = buttonmergegeo; + geomergemodesbuttons[(int)MergeGeometryMode.REPLACE] = buttonplacegeo; + geomergemodesitems = new ToolStripMenuItem[numgeomodes]; + geomergemodesitems[(int)MergeGeometryMode.CLASSIC] = itemmergegeoclassic; + geomergemodesitems[(int)MergeGeometryMode.MERGE] = itemmergegeo; + geomergemodesitems[(int)MergeGeometryMode.REPLACE] = itemreplacegeo; // Visual Studio IDE doesn't let me set these in the designer :( buttonzoom.Font = menufile.Font; @@ -312,10 +327,18 @@ namespace CodeImp.DoomBuilder.Windows } // View mode only matters in classic editing modes + bool isclassicmode = (General.Editing.Mode is ClassicMode); for(int i = 0; i < Renderer2D.NUM_VIEW_MODES; i++) { - viewmodesitems[i].Enabled = (General.Editing.Mode is ClassicMode); - viewmodesbuttons[i].Enabled = (General.Editing.Mode is ClassicMode); + viewmodesitems[i].Enabled = isclassicmode; + viewmodesbuttons[i].Enabled = isclassicmode; + } + + //mxd. Merge geometry mode only matters in classic editing modes + for(int i = 0; i < geomergemodesbuttons.Length; i++) + { + geomergemodesbuttons[i].Enabled = isclassicmode; + geomergemodesitems[i].Enabled = isclassicmode; } UpdateEditMenu(); @@ -2079,6 +2102,10 @@ namespace CodeImp.DoomBuilder.Windows buttonviewceilings.Visible = General.Settings.ToolbarViewModes && maploaded; buttonviewfloors.Visible = General.Settings.ToolbarViewModes && maploaded; buttonviewnormal.Visible = General.Settings.ToolbarViewModes && maploaded; + separatorgeomergemodes.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd + buttonmergegeoclassic.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd + buttonmergegeo.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd + buttonplacegeo.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd buttonsnaptogrid.Visible = General.Settings.ToolbarGeometry && maploaded; buttontoggledynamicgrid.Visible = General.Settings.ToolbarGeometry && maploaded; //mxd buttontoggledynamicgrid.Checked = General.Settings.DynamicGridSize; //mxd @@ -2756,6 +2783,17 @@ namespace CodeImp.DoomBuilder.Windows buttoncut.Enabled = itemcut.Enabled; buttoncopy.Enabled = itemcopy.Enabled; buttonpaste.Enabled = itempaste.Enabled; + + //mxd. Geometry merge mode items + if(General.Map != null) + { + for(int i = 0; i < geomergemodesbuttons.Length; i++) + { + // Check the correct item + geomergemodesbuttons[i].Checked = (i == (int)General.Settings.MergeGeometryMode); + geomergemodesitems[i].Checked = (i == (int)General.Settings.MergeGeometryMode); + } + } } //mxd @@ -2918,6 +2956,36 @@ namespace CodeImp.DoomBuilder.Windows ThingStatisticsForm f = new ThingStatisticsForm(); f.ShowDialog(this); } + + //mxd + [BeginAction("geomergeclassic")] + private void GeoMergeClassic() + { + General.Settings.MergeGeometryMode = MergeGeometryMode.CLASSIC; + UpdateToolbar(); + UpdateEditMenu(); + DisplayStatus(StatusType.Action, "\"Merge Dragged Vertices Only\" mode selected"); + } + + //mxd + [BeginAction("geomerge")] + private void GeoMerge() + { + General.Settings.MergeGeometryMode = MergeGeometryMode.MERGE; + UpdateToolbar(); + UpdateEditMenu(); + DisplayStatus(StatusType.Action, "\"Merge Dragged Geometry\" mode selected"); + } + + //mxd + [BeginAction("georeplace")] + private void GeoReplace() + { + General.Settings.MergeGeometryMode = MergeGeometryMode.REPLACE; + UpdateToolbar(); + UpdateEditMenu(); + DisplayStatus(StatusType.Action, "\"Replace with Dragged Geometry\" mode selected"); + } #endregion diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs index 5f256d5b..b8c6c3e6 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs @@ -420,7 +420,7 @@ namespace CodeImp.DoomBuilder.BuilderModes MoveGeometryRelative(mousemappos - dragstartmappos, snaptogrid, snaptogridincrement, snaptonearest, snaptocardinaldirection); // Stitch geometry - General.Map.Map.StitchGeometry(true); + General.Map.Map.StitchGeometry(General.Settings.MergeGeometryMode); // Snap to map format accuracy General.Map.Map.SnapAllToAccuracy(); diff --git a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs index f8607ebd..17bc3b9f 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs @@ -1645,8 +1645,11 @@ namespace CodeImp.DoomBuilder.BuilderModes } } + //mxd. We'll need sidedefs marked by StitchGeometry, not all sidedefs from selection... + General.Map.Map.ClearMarkedSidedefs(false); + // Stitch geometry - General.Map.Map.StitchGeometry(true); + General.Map.Map.StitchGeometry(General.Settings.MergeGeometryMode); // Snap to map format accuracy General.Map.Map.SnapAllToAccuracy(General.Map.UDMF && usepreciseposition);