From 5d1492c5c25d0ff9d3f5677da07c6f305e9e00cf Mon Sep 17 00:00:00 2001 From: biwa <6475593+biwa@users.noreply.github.com> Date: Sat, 30 Jan 2021 22:01:55 +0100 Subject: [PATCH] Added visual sloping for vertices (has an extra action to toggle visual vertex slope picking) --- Source/Core/Rendering/Renderer3D.cs | 16 +- Source/Core/Rendering/VisualSlopeHandle.cs | 40 ++++- Source/Core/VisualModes/VisualMode.cs | 38 +++- Source/Core/VisualModes/VisualSlope.cs | 10 ++ .../Plugins/BuilderModes/BuilderModes.csproj | 1 + .../BuilderModes/Resources/Actions.cfg | 14 +- .../VisualModes/BaseVisualMode.cs | 168 ++++++++++++++---- .../VisualModes/VisualSidedefSlope.cs | 29 ++- 8 files changed, 256 insertions(+), 60 deletions(-) diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs index 1f0a69b9..90d2f284 100755 --- a/Source/Core/Rendering/Renderer3D.cs +++ b/Source/Core/Rendering/Renderer3D.cs @@ -667,12 +667,20 @@ namespace CodeImp.DoomBuilder.Rendering world = handle.Position; graphics.SetUniform(UniformName.world, ref world); - graphics.SetUniform(UniformName.slopeHandleLength, (float)handle.Length); graphics.SetUniform(UniformName.vertexColor, color.ToColorValue()); - graphics.SetVertexBuffer(visualslopehandle.Geometry); - graphics.Draw(PrimitiveType.TriangleList, 0, 2); - + if (handle.Type == VisualSlopeType.Line) + { + graphics.SetUniform(UniformName.slopeHandleLength, (float)handle.Length); + graphics.SetVertexBuffer(visualslopehandle.LineGeometry); + graphics.Draw(PrimitiveType.TriangleList, 0, 2); + } + else if (handle.Type == VisualSlopeType.Vertex) + { + graphics.SetUniform(UniformName.slopeHandleLength, 1.0f); + graphics.SetVertexBuffer(visualslopehandle.VertexGeometry); + graphics.Draw(PrimitiveType.TriangleList, 0, 1); + } } // Done diff --git a/Source/Core/Rendering/VisualSlopeHandle.cs b/Source/Core/Rendering/VisualSlopeHandle.cs index 7b01a2d3..8bee60e7 100644 --- a/Source/Core/Rendering/VisualSlopeHandle.cs +++ b/Source/Core/Rendering/VisualSlopeHandle.cs @@ -10,14 +10,16 @@ namespace CodeImp.DoomBuilder.Rendering { #region ================== Variables - private VertexBuffer geometry; + private VertexBuffer linegeometry; + private VertexBuffer vertexgeometry; private bool isdisposed; #endregion #region ================== Properties - public VertexBuffer Geometry { get { return geometry; } } + public VertexBuffer LineGeometry { get { return linegeometry; } } + public VertexBuffer VertexGeometry { get { return vertexgeometry; } } #endregion @@ -37,8 +39,8 @@ namespace CodeImp.DoomBuilder.Rendering // Not already disposed? if (!isdisposed) { - if (geometry != null) - geometry.Dispose(); + if (linegeometry != null) + linegeometry.Dispose(); // Unregister resource General.Map.Graphics.UnregisterResource(this); @@ -70,18 +72,38 @@ namespace CodeImp.DoomBuilder.Rendering v0, v2, v3 }; - geometry = new VertexBuffer(); - General.Map.Graphics.SetBufferData(geometry, vertices); + linegeometry = new VertexBuffer(); + General.Map.Graphics.SetBufferData(linegeometry, vertices); + + v0 = new WorldVertex(0.0f, 0.0f, 0.1f); + v1 = new WorldVertex(4.0f, -8.0f, 0.1f); + v2 = new WorldVertex(-4.0f, -8.0f, 0.1f); + + v0.c = PixelColor.INT_WHITE; + v1.c = v2.c = PixelColor.INT_WHITE_NO_ALPHA; + + vertices = new[] + { + v0, v1, v2 + }; + + vertexgeometry = new VertexBuffer(); + General.Map.Graphics.SetBufferData(vertexgeometry, vertices); } // This is called before a device is reset // (when resized or display adapter was changed) public void UnloadResource() { - if (geometry != null) - geometry.Dispose(); + if (linegeometry != null) + linegeometry.Dispose(); - geometry = null; + linegeometry = null; + + if (vertexgeometry != null) + vertexgeometry.Dispose(); + + vertexgeometry = null; } #endregion diff --git a/Source/Core/VisualModes/VisualMode.cs b/Source/Core/VisualModes/VisualMode.cs index e587564b..a02d63cf 100755 --- a/Source/Core/VisualModes/VisualMode.cs +++ b/Source/Core/VisualModes/VisualMode.cs @@ -33,7 +33,8 @@ namespace CodeImp.DoomBuilder.VisualModes public enum PickingMode { Default, - SlopeHandles + SidedefSlopeHandles, + VertexSlopeHandles } /// @@ -82,6 +83,8 @@ namespace CodeImp.DoomBuilder.VisualModes protected Dictionary allthings; protected Dictionary allsectors; protected Dictionary> allslopehandles; + protected Dictionary> sidedefslopehandles; + protected Dictionary> vertexslopehandles; protected List visibleblocks; protected List visiblethings; protected List visiblesectors; @@ -96,6 +99,8 @@ namespace CodeImp.DoomBuilder.VisualModes public VisualBlockMap BlockMap { get { return blockmap; } } public Dictionary VisualVertices { get { return vertices; } } //mxd public Dictionary> AllSlopeHandles { get { return allslopehandles; } } + public Dictionary> SidedefSlopeHandles { get { return sidedefslopehandles; } } + public Dictionary> VertexSlopeHandles { get { return vertexslopehandles; } } // Rendering public IRenderer3D Renderer { get { return renderer; } } @@ -115,6 +120,8 @@ namespace CodeImp.DoomBuilder.VisualModes this.allsectors = new Dictionary(General.Map.Map.Sectors.Count); this.allthings = new Dictionary(General.Map.Map.Things.Count); this.allslopehandles = new Dictionary>(General.Map.Map.Sectors.Count); + this.sidedefslopehandles = new Dictionary>(General.Map.Map.Sectors.Count); + this.vertexslopehandles = new Dictionary>(General.Map.Map.Sectors.Count); this.visibleblocks = new List(); this.visiblesectors = new List(50); this.visiblegeometry = new List(200); @@ -735,8 +742,13 @@ namespace CodeImp.DoomBuilder.VisualModes foreach(VisualGeometry g in vs.FixedGeometry) pickables.Add(g); // Add slope handles - if (General.Map.UDMF && pickingmode == PickingMode.SlopeHandles && allslopehandles.ContainsKey(General.Map.VisualCamera.Sector)) - pickables.AddRange(allslopehandles[General.Map.VisualCamera.Sector]); + if (General.Map.UDMF) + { + if (pickingmode == PickingMode.SidedefSlopeHandles && sidedefslopehandles.ContainsKey(General.Map.VisualCamera.Sector)) + pickables.AddRange(sidedefslopehandles[General.Map.VisualCamera.Sector]); + else if (pickingmode == PickingMode.VertexSlopeHandles && vertexslopehandles.ContainsKey(General.Map.VisualCamera.Sector)) + pickables.AddRange(vertexslopehandles[General.Map.VisualCamera.Sector]); + } } // Go for all lines to see which ones we intersect @@ -783,8 +795,13 @@ namespace CodeImp.DoomBuilder.VisualModes } // Add slope handles - if (General.Map.UDMF && pickingmode == PickingMode.SlopeHandles && allslopehandles.ContainsKey(ld.Front.Sector)) - pickables.AddRange(allslopehandles[ld.Front.Sector]); + if (General.Map.UDMF) + { + if (pickingmode == PickingMode.SidedefSlopeHandles && sidedefslopehandles.ContainsKey(ld.Front.Sector)) + pickables.AddRange(sidedefslopehandles[ld.Front.Sector]); + else if (pickingmode == PickingMode.VertexSlopeHandles && vertexslopehandles.ContainsKey(ld.Front.Sector)) + pickables.AddRange(vertexslopehandles[ld.Front.Sector]); + } } // Add sidedef if on the front side @@ -824,8 +841,13 @@ namespace CodeImp.DoomBuilder.VisualModes } // Add slope handles - if (General.Map.UDMF && pickingmode == PickingMode.SlopeHandles && allslopehandles.ContainsKey(ld.Back.Sector)) - pickables.AddRange(allslopehandles[ld.Back.Sector]); + if (General.Map.UDMF) + { + if (pickingmode == PickingMode.SidedefSlopeHandles && sidedefslopehandles.ContainsKey(ld.Back.Sector)) + pickables.AddRange(sidedefslopehandles[ld.Back.Sector]); + else if (pickingmode == PickingMode.VertexSlopeHandles && vertexslopehandles.ContainsKey(ld.Back.Sector)) + pickables.AddRange(vertexslopehandles[ld.Back.Sector]); + } } // Add sidedef if on the front side @@ -891,7 +913,7 @@ namespace CodeImp.DoomBuilder.VisualModes // If picking mode is for slope handles only return slope handles. We have to do it this // way because otherwise it's possible to pick slope handles through other geometry - if (pickingmode == PickingMode.SlopeHandles && !(result.picked is VisualSlope)) + if (pickingmode != PickingMode.Default && !(result.picked is VisualSlope)) result.picked = null; // Done diff --git a/Source/Core/VisualModes/VisualSlope.cs b/Source/Core/VisualModes/VisualSlope.cs index 64c45bcf..0035141d 100644 --- a/Source/Core/VisualModes/VisualSlope.cs +++ b/Source/Core/VisualModes/VisualSlope.cs @@ -5,6 +5,12 @@ using CodeImp.DoomBuilder.Rendering; namespace CodeImp.DoomBuilder.VisualModes { + public enum VisualSlopeType + { + Line, + Vertex + } + public abstract class VisualSlope : IVisualPickable { #region ================== Variables @@ -24,6 +30,7 @@ namespace CodeImp.DoomBuilder.VisualModes // Was changed? private bool changed; + protected VisualSlopeType type; protected double length; private Matrix position; @@ -51,6 +58,8 @@ namespace CodeImp.DoomBuilder.VisualModes public bool Changed { get { return changed; } set { changed = value; } } + public VisualSlopeType Type { get { return type; } } + public double Length { get { return length; } } public Matrix Position { get { return position; } } @@ -99,6 +108,7 @@ namespace CodeImp.DoomBuilder.VisualModes } public virtual void Update() {} + public virtual Vector3D GetPivotPoint() { return new Vector3D(); } public void SetPosition(Line2D line, Plane plane) { diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj index 34fb4428..ce7ed03f 100755 --- a/Source/Plugins/BuilderModes/BuilderModes.csproj +++ b/Source/Plugins/BuilderModes/BuilderModes.csproj @@ -519,6 +519,7 @@ + diff --git a/Source/Plugins/BuilderModes/Resources/Actions.cfg b/Source/Plugins/BuilderModes/Resources/Actions.cfg index 92ee1742..06316010 100755 --- a/Source/Plugins/BuilderModes/Resources/Actions.cfg +++ b/Source/Plugins/BuilderModes/Resources/Actions.cfg @@ -1418,9 +1418,19 @@ visualpaintselect togglevisualslopepicking { - title = "Toggle Visual Slope Picking"; + title = "Toggle Visual Sidedef Slope Picking"; category = "visual"; - description = "Toggles picking visual slope handles."; + description = "Toggles picking visual sidedef slope handles."; + allowkeys = true; + allowmouse = true; + allowscroll = false; +} + +togglevisualvertexslopepicking +{ + title = "Toggle Visual Vertex Slope Picking"; + category = "visual"; + description = "Toggles picking visual vertex slope handles."; allowkeys = true; allowmouse = true; allowscroll = false; diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index a186a86b..c6df2a0e 100755 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -449,7 +449,38 @@ namespace CodeImp.DoomBuilder.BuilderModes if (!allslopehandles.ContainsKey(sd.Sector)) allslopehandles.Add(sd.Sector, new List()); + if (!sidedefslopehandles.ContainsKey(sd.Sector)) + sidedefslopehandles.Add(sd.Sector, new List()); + allslopehandles[sd.Sector].Add(handle); + sidedefslopehandles[sd.Sector].Add(handle); + + return handle; + } + + internal VisualSlope CreateVisualSlopeHandle(SectorLevel level, Vertex v, Sector s, bool up) + { + VisualVertexSlope handle = new VisualVertexSlope(this, level, v, s, up); + + /* + if (!allslopehandles.ContainsKey(level.sector)) + allslopehandles.Add(level.sector, new List()); + + if (!vertexslopehandles.ContainsKey(level.sector)) + vertexslopehandles.Add(level.sector, new List()); + + allslopehandles[level.sector].Add(handle); + vertexslopehandles[level.sector].Add(handle); + */ + + if (!allslopehandles.ContainsKey(s)) + allslopehandles.Add(s, new List()); + + if (!vertexslopehandles.ContainsKey(s)) + vertexslopehandles.Add(s, new List()); + + allslopehandles[s].Add(handle); + vertexslopehandles[s].Add(handle); return handle; } @@ -496,16 +527,23 @@ namespace CodeImp.DoomBuilder.BuilderModes if (newtarget.picked is VisualSidedefSlope) { // Get the smart pivot handle for the targeted slope handle, so that it can be drawn - VisualSidedefSlope handle = VisualSidedefSlope.GetSmartPivotHandle((VisualSidedefSlope)newtarget.picked, this); + VisualSlope handle = VisualSidedefSlope.GetSmartPivotHandle((VisualSidedefSlope)newtarget.picked, this); if (handle != null) handle.SmartPivot = true; } - else if(target.picked is VisualSidedefSlope) + else if(newtarget.picked is VisualVertexSlope) + { + // Get the smart pivot handle for the targeted slope handle, so that it can be drawn + VisualSlope handle = VisualVertexSlope.GetSmartPivotHandle((VisualVertexSlope)newtarget.picked, this); + if (handle != null) + handle.SmartPivot = true; + } + else if(target.picked is VisualSlope) { // Clear smart pivot handles, otherwise it will keep being displayed foreach (KeyValuePair> kvp in allslopehandles) - foreach (VisualSidedefSlope checkhandle in kvp.Value) + foreach (VisualSlope checkhandle in kvp.Value) checkhandle.SmartPivot = false; } } @@ -580,7 +618,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Also update slope handles if (allslopehandles.ContainsKey(vs.Key)) - foreach (VisualSidedefSlope handle in allslopehandles[vs.Key]) + foreach (VisualSlope handle in allslopehandles[vs.Key]) handle.Update(); } } @@ -1266,46 +1304,93 @@ namespace CodeImp.DoomBuilder.BuilderModes foreach (KeyValuePair> kvp in allslopehandles) { foreach (VisualSlope handle in kvp.Value) - if (handle != null) - if (handle.Selected) RemoveSelectedObject((VisualSidedefSlope)handle); + if (handle != null && handle.Selected) + if(handle is VisualSidedefSlope) + RemoveSelectedObject((VisualSidedefSlope)handle); + else + RemoveSelectedObject((VisualVertexSlope)handle); kvp.Value.Clear(); } allslopehandles.Clear(); + sidedefslopehandles.Clear(); + vertexslopehandles.Clear(); BuildSlopeHandles(General.Map.Map.Sectors.ToList()); } private void BuildSlopeHandles(List sectors) { - if (General.Map.UDMF) + if (!General.Map.UDMF) + return; + + foreach (Sector s in sectors) { - foreach (Sector s in sectors) + if (s.IsDisposed) + continue; + + SectorData sectordata = GetSectorData(s); + sectordata.Update(); + + // Clear old data + if (allslopehandles.ContainsKey(s)) allslopehandles.Remove(s); + if (sidedefslopehandles.ContainsKey(s)) sidedefslopehandles.Remove(s); + if (vertexslopehandles.ContainsKey(s)) vertexslopehandles.Remove(s); + + + // Create visual sidedef slope handles + foreach (Sidedef sidedef in s.Sidedefs) { - if (s.IsDisposed) + // Create handles for the regular floor and ceiling + CreateVisualSlopeHandle(sectordata.Floor, sidedef, true); + CreateVisualSlopeHandle(sectordata.Ceiling, sidedef, false); + + // Create handles for 3D floors + if (sectordata.ExtraFloors.Count > 0) { - continue; + foreach (Effect3DFloor floor in sectordata.ExtraFloors) + { + CreateVisualSlopeHandle(floor.Floor, sidedef, false); + CreateVisualSlopeHandle(floor.Ceiling, sidedef, true); + } } + } + } + // Create visual vertex slope handles + foreach(Vertex v in General.Map.Map.Vertices) + { + if (v.IsDisposed || v.Linedefs.Count == 0) + continue; + + HashSet vertexsectors = new HashSet(); + + // Find all sectors that have lines connected to this vertex + foreach(Linedef ld in v.Linedefs) + { + if (ld.IsDisposed) + continue; + + if (ld.Front != null && !ld.Front.Sector.IsDisposed) vertexsectors.Add(ld.Front.Sector); + if (ld.Back != null && !ld.Front.Sector.IsDisposed) vertexsectors.Add(ld.Back.Sector); + } + + foreach(Sector s in vertexsectors) + { SectorData sectordata = GetSectorData(s); - sectordata.Update(); - if (allslopehandles.ContainsKey(s)) - allslopehandles.Remove(s); + // Create handles for the regular floor and ceiling + CreateVisualSlopeHandle(sectordata.Floor, v, s, true); + CreateVisualSlopeHandle(sectordata.Ceiling, v, s, false); - foreach (Sidedef sidedef in s.Sidedefs) + // Create handles for 3D floors + if (sectordata.ExtraFloors.Count > 0) { - VisualSlope handle = CreateVisualSlopeHandle(sectordata.Floor, sidedef, true); - handle = CreateVisualSlopeHandle(sectordata.Ceiling, sidedef, false); - - if (sectordata.ExtraFloors.Count > 0) + foreach (Effect3DFloor floor in sectordata.ExtraFloors) { - foreach (Effect3DFloor floor in sectordata.ExtraFloors) - { - handle = CreateVisualSlopeHandle(floor.Floor, sidedef, false); - handle = CreateVisualSlopeHandle(floor.Ceiling, sidedef, true); - } + CreateVisualSlopeHandle(floor.Floor, v, s, false); + CreateVisualSlopeHandle(floor.Ceiling, v, s, true); } } } @@ -1606,6 +1691,12 @@ namespace CodeImp.DoomBuilder.BuilderModes { allslopehandles[s].Clear(); allslopehandles.Remove(s); + + sidedefslopehandles[s].Clear(); + sidedefslopehandles.Remove(s); + + vertexslopehandles[s].Clear(); + vertexslopehandles.Remove(s); } // Rebuild slope handles for the changed sectors @@ -2388,7 +2479,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { foreach (KeyValuePair> kvp in allslopehandles) { - foreach (VisualSidedefSlope handle in kvp.Value) + foreach (VisualSlope handle in kvp.Value) { handle.Selected = false; handle.Pivot = false; @@ -2549,7 +2640,7 @@ namespace CodeImp.DoomBuilder.BuilderModes int startheight = (int)Math.Round(selectedhandles[0].GetCenterPoint().z); int targetheight = int.MaxValue; - foreach (KeyValuePair> kvp in allslopehandles) + foreach (KeyValuePair> kvp in sidedefslopehandles) { foreach (VisualSidedefSlope handle in kvp.Value) { @@ -2790,7 +2881,7 @@ namespace CodeImp.DoomBuilder.BuilderModes int startheight = (int)Math.Round(selectedhandles[0].GetCenterPoint().z); int targetheight = int.MinValue; - foreach (KeyValuePair> kvp in allslopehandles) + foreach (KeyValuePair> kvp in sidedefslopehandles) { foreach (VisualSidedefSlope handle in kvp.Value) { @@ -4230,21 +4321,38 @@ namespace CodeImp.DoomBuilder.BuilderModes } [BeginAction("togglevisualslopepicking")] - public void ToggleVisualSlopePicking() + public void ToggleVisualSidedefSlopePicking() { - if (pickingmode != PickingMode.SlopeHandles) - pickingmode = PickingMode.SlopeHandles; + if (pickingmode != PickingMode.SidedefSlopeHandles) + pickingmode = PickingMode.SidedefSlopeHandles; else { pickingmode = PickingMode.Default; // Clear smart pivot handles, otherwise it will keep being displayed foreach (KeyValuePair> kvp in allslopehandles) - foreach (VisualSidedefSlope checkhandle in kvp.Value) + foreach (VisualSlope checkhandle in kvp.Value) checkhandle.SmartPivot = false; } } + [BeginAction("togglevisualvertexslopepicking")] + public void ToggleVisualVertexSlopePicking() + { + if (pickingmode != PickingMode.VertexSlopeHandles) + pickingmode = PickingMode.VertexSlopeHandles; + else + { + pickingmode = PickingMode.Default; + + // Clear smart pivot handles, otherwise it will keep being displayed + foreach (KeyValuePair> kvp in allslopehandles) + foreach (VisualSlope checkhandle in kvp.Value) + checkhandle.SmartPivot = false; + } + } + + [BeginAction("resetslope")] public void ResetSlope() { diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualSidedefSlope.cs b/Source/Plugins/BuilderModes/VisualModes/VisualSidedefSlope.cs index 64078877..f628be52 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualSidedefSlope.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualSidedefSlope.cs @@ -48,6 +48,8 @@ namespace CodeImp.DoomBuilder.VisualModes this.level = level; this.up = up; + type = VisualSlopeType.Line; + // length = sidedef.Line.Length; Update(); @@ -182,9 +184,11 @@ namespace CodeImp.DoomBuilder.VisualModes if (selectedsectors.Count == 0) { // No sectors selected, so find all handles that belong to the same level - foreach (VisualSidedefSlope checkhandle in mode.AllSlopeHandles[starthandle.Sidedef.Sector]) + foreach (VisualSidedefSlope checkhandle in mode.SidedefSlopeHandles[starthandle.Sidedef.Sector]) + { if (checkhandle != starthandle && checkhandle.Level == starthandle.Level) potentialhandles.Add(checkhandle); + } } else { @@ -195,15 +199,17 @@ namespace CodeImp.DoomBuilder.VisualModes sectors.Add(bvgs.Sector.Sector); foreach (Sector s in sectors) - foreach (VisualSidedefSlope checkhandle in mode.AllSlopeHandles[s]) - if(checkhandle != starthandle) + foreach (VisualSidedefSlope checkhandle in mode.SidedefSlopeHandles[s]) + { + if (checkhandle != starthandle) foreach (BaseVisualGeometrySector bvgs in selectedsectors) if (bvgs.Level == checkhandle.Level) potentialhandles.Add(checkhandle); + } } foreach (KeyValuePair> kvp in mode.AllSlopeHandles) - foreach (VisualSidedefSlope checkhandle in kvp.Value) + foreach (VisualSlope checkhandle in kvp.Value) checkhandle.SmartPivot = false; // Sort potential handles by their angle difference to the start handle. That means that handles with less angle difference will be at the beginning of the list @@ -296,6 +302,15 @@ namespace CodeImp.DoomBuilder.VisualModes if (vs != null) vs.UpdateSectorGeometry(true); } + /// + /// Gets the pivor point for this slope handle + /// + /// The pivot point as Vector3D + public override Vector3D GetPivotPoint() + { + return new Vector3D(sidedef.Line.Line.GetCoordinatesAt(0.5), level.plane.GetZ(sidedef.Line.Line.GetCoordinatesAt(0.5))); + } + #endregion #region ================== Events @@ -321,7 +336,7 @@ namespace CodeImp.DoomBuilder.VisualModes // TODO: doing this every time is kind of stupid. Maybe store the pivot handle in the mode? foreach (KeyValuePair> kvp in mode.AllSlopeHandles) { - foreach (VisualSidedefSlope handle in kvp.Value) + foreach (VisualSlope handle in kvp.Value) { if (handle.Pivot) { @@ -344,12 +359,12 @@ namespace CodeImp.DoomBuilder.VisualModes mode.CreateUndo("Change slope"); Plane originalplane = level.plane; - Plane pivotplane = ((VisualSidedefSlope)pivothandle).Level.plane; + Plane pivotplane = pivothandle is VisualVertexSlope ? ((VisualVertexSlope)pivothandle).Level.plane : ((VisualSidedefSlope)pivothandle).Level.plane; // Build a new plane. p1 and p2 are the points of the slope handle that is modified, with the changed amound added; p3 is on the line of the pivot handle Vector3D p1 = new Vector3D(sidedef.Line.Start.Position, originalplane.GetZ(sidedef.Line.Start.Position) + amount); Vector3D p2 = new Vector3D(sidedef.Line.End.Position, originalplane.GetZ(sidedef.Line.End.Position) + amount); - Vector3D p3 = new Vector3D(((VisualSidedefSlope)pivothandle).Sidedef.Line.Line.GetCoordinatesAt(0.5), pivotplane.GetZ(((VisualSidedefSlope)pivothandle).Sidedef.Line.Line.GetCoordinatesAt(0.5))); + Vector3D p3 = pivothandle.GetPivotPoint(); Plane plane = new Plane(p1, p2, p3, true);