Added some missing files

Some refactoring regarding visual sloping
This commit is contained in:
biwa 2021-01-30 22:45:08 +01:00
parent 5d1492c5c2
commit 5bcb27e51f
7 changed files with 487 additions and 99 deletions

View file

@ -482,6 +482,7 @@
<Compile Include="VisualModes\BaseVisualGeometrySidedef.cs" />
<Compile Include="VisualModes\BaseVisualMode.cs" />
<Compile Include="VisualModes\BaseVisualSector.cs" />
<Compile Include="VisualModes\BaseVisualSlope.cs" />
<Compile Include="VisualModes\BaseVisualThing.cs" />
<Compile Include="VisualModes\BaseVisualVertex.cs" />
<Compile Include="VisualModes\Effect3DFloor.cs" />

View file

@ -480,6 +480,7 @@
<Compile Include="VisualModes\BaseVisualGeometrySidedef.cs" />
<Compile Include="VisualModes\BaseVisualMode.cs" />
<Compile Include="VisualModes\BaseVisualSector.cs" />
<Compile Include="VisualModes\BaseVisualSlope.cs" />
<Compile Include="VisualModes\BaseVisualThing.cs" />
<Compile Include="VisualModes\BaseVisualVertex.cs" />
<Compile Include="VisualModes\Effect3DFloor.cs" />
@ -517,6 +518,7 @@
<Compile Include="VisualModes\VisualSidedefParts.cs" />
<Compile Include="VisualModes\VisualSidedefSlope.cs" />
<Compile Include="VisualModes\VisualUpper.cs" />
<Compile Include="VisualModes\VisualVertexSlope.cs" />
<Compile Include="VisualModes\WallPolygon.cs" />
</ItemGroup>
<ItemGroup>

View file

@ -819,7 +819,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
if (General.Map.UDMF)
{
if (mode.AllSlopeHandles.ContainsKey(level.sector))
foreach (VisualSidedefSlope handle in mode.AllSlopeHandles[level.sector])
foreach (VisualSlope handle in mode.AllSlopeHandles[level.sector])
handle.Changed = true;
}
}

View file

@ -417,8 +417,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in allslopehandles)
{
foreach (VisualSlope handle in kvp.Value)
if (handle.Selected) selectedobjects.Add((VisualSidedefSlope)handle);
foreach (BaseVisualSlope handle in kvp.Value)
if (handle.Selected) selectedobjects.Add(handle);
}
}
@ -540,7 +540,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
else if(target.picked is VisualSlope)
{
// Clear smart pivot handles, otherwise it will keep being displayed
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in allslopehandles)
foreach (VisualSlope checkhandle in kvp.Value)
@ -1305,10 +1304,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
foreach (VisualSlope handle in kvp.Value)
if (handle != null && handle.Selected)
if(handle is VisualSidedefSlope)
RemoveSelectedObject((VisualSidedefSlope)handle);
else
RemoveSelectedObject((VisualVertexSlope)handle);
if (handle is BaseVisualSlope)
RemoveSelectedObject((BaseVisualSlope)handle);
kvp.Value.Clear();
}

View file

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CodeImp.DoomBuilder.BuilderModes;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
namespace CodeImp.DoomBuilder.VisualModes
{
internal abstract class BaseVisualSlope : VisualSlope, IVisualEventReceiver
{
#region ================== Variables
protected readonly BaseVisualMode mode;
protected readonly SectorLevel level;
protected Vector3D pickintersect;
protected double pickrayu;
protected readonly bool up;
protected Plane plane;
#endregion
#region ================== Properties
public SectorLevel Level { get { return level; } }
#endregion
#region ================== Constructor
public BaseVisualSlope(BaseVisualMode mode, SectorLevel level, bool up)
{
this.mode = mode;
this.level = level;
this.up = up;
}
#endregion
#region ================== Events
// Select or deselect
public void OnSelectEnd()
{
if (this.selected)
{
this.selected = false;
mode.RemoveSelectedObject(this);
}
else
{
if (this.pivot)
{
General.Interface.DisplayStatus(Windows.StatusType.Warning, "It is not allowed to mark pivot slope handles as selected.");
return;
}
this.selected = true;
mode.AddSelectedObject(this);
}
}
public void OnEditEnd()
{
// We can only have one pivot handle, so remove it from all first
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in mode.AllSlopeHandles)
{
foreach (VisualSlope handle in kvp.Value)
{
if (handle == mode.HighlightedTarget)
{
if (handle.Selected)
General.Interface.DisplayStatus(Windows.StatusType.Warning, "It is not allowed to mark selected slope handles as pivot slope handles.");
else
handle.Pivot = !handle.Pivot;
}
else
handle.Pivot = false;
}
}
}
public abstract void OnChangeTargetHeight(int amount);
// Return texture name
public string GetTextureName() { return ""; }
// Unused
public void OnSelectBegin() { }
public void OnEditBegin() { }
public void OnChangeTargetBrightness(bool up) { }
public void OnChangeTextureOffset(int horizontal, int vertical, bool doSurfaceAngleCorrection) { }
public void OnSelectTexture() { }
public void OnCopyTexture() { }
public void OnPasteTexture() { }
public void OnCopyTextureOffsets() { }
public void OnPasteTextureOffsets() { }
public void OnTextureAlign(bool alignx, bool aligny) { }
public void OnToggleUpperUnpegged() { }
public void OnToggleLowerUnpegged() { }
public void OnProcess(long deltatime) { }
public void OnTextureFloodfill() { }
public void OnInsert() { }
public void OnTextureFit(FitTextureOptions options) { } //mxd
public void ApplyTexture(string texture) { }
public void ApplyUpperUnpegged(bool set) { }
public void ApplyLowerUnpegged(bool set) { }
public void SelectNeighbours(bool select, bool withSameTexture, bool withSameHeight) { } //mxd
public virtual void OnPaintSelectEnd() { } // biwa
public void OnChangeScale(int x, int y) { }
public void OnResetTextureOffset() { }
public void OnResetLocalTextureOffset() { }
public void OnCopyProperties() { }
public void OnPasteProperties(bool usecopysetting) { }
public void OnDelete() { }
public void OnPaintSelectBegin() { }
public void OnMouseMove(MouseEventArgs e) { }
#endregion
}
}

View file

@ -11,17 +11,11 @@ using CodeImp.DoomBuilder.Rendering;
namespace CodeImp.DoomBuilder.VisualModes
{
internal class VisualSidedefSlope : VisualSlope, IVisualEventReceiver
internal class VisualSidedefSlope : BaseVisualSlope // VisualSlope, IVisualEventReceiver
{
#region ================== Variables
private readonly BaseVisualMode mode;
private readonly Sidedef sidedef;
private readonly SectorLevel level;
private readonly bool up;
private Vector3D pickintersect;
private double pickrayu;
private Plane plane;
#endregion
@ -34,24 +28,17 @@ namespace CodeImp.DoomBuilder.VisualModes
#region ================== Properties
public Sidedef Sidedef { get { return sidedef; } }
public SectorLevel Level { get { return level; } }
public int NormalizedAngleDeg { get { return (sidedef.Line.AngleDeg >= 180) ? (sidedef.Line.AngleDeg - 180) : sidedef.Line.AngleDeg; } }
#endregion
#region ================== Constructor / Destructor
public VisualSidedefSlope(BaseVisualMode mode, SectorLevel level, Sidedef sidedef, bool up) : base()
public VisualSidedefSlope(BaseVisualMode mode, SectorLevel level, Sidedef sidedef, bool up) : base(mode, level, up)
{
this.mode = mode;
this.sidedef = sidedef;
this.level = level;
this.up = up;
type = VisualSlopeType.Line;
// length = sidedef.Line.Length;
Update();
// We have no destructor
@ -315,7 +302,7 @@ namespace CodeImp.DoomBuilder.VisualModes
#region ================== Events
public void OnChangeTargetHeight(int amount)
public override void OnChangeTargetHeight(int amount)
{
VisualSlope pivothandle = null;
List<IVisualEventReceiver> selectedsectors = mode.GetSelectedObjects(true, false, false, false, false);
@ -375,81 +362,6 @@ namespace CodeImp.DoomBuilder.VisualModes
mode.SetActionResult("Changed slope.");
}
// Select or deselect
public void OnSelectEnd()
{
if (this.selected)
{
this.selected = false;
mode.RemoveSelectedObject(this);
}
else
{
if(this.pivot)
{
General.Interface.DisplayStatus(Windows.StatusType.Warning, "It is not allowed to mark pivot slope handles as selected.");
return;
}
this.selected = true;
mode.AddSelectedObject(this);
}
}
public void OnEditEnd()
{
// We can only have one pivot handle, so remove it from all first
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in mode.AllSlopeHandles)
{
foreach (VisualSlope handle in kvp.Value)
{
if (handle == mode.HighlightedTarget)
{
if (handle.Selected)
General.Interface.DisplayStatus(Windows.StatusType.Warning, "It is not allowed to mark selected slope handles as pivot slope handles.");
else
handle.Pivot = !handle.Pivot;
}
else
handle.Pivot = false;
}
}
}
// Return texture name
public string GetTextureName() { return ""; }
// Unused
public void OnSelectBegin() { }
public void OnEditBegin() { }
public void OnChangeTargetBrightness(bool up) { }
public void OnChangeTextureOffset(int horizontal, int vertical, bool doSurfaceAngleCorrection) { }
public void OnSelectTexture() { }
public void OnCopyTexture() { }
public void OnPasteTexture() { }
public void OnCopyTextureOffsets() { }
public void OnPasteTextureOffsets() { }
public void OnTextureAlign(bool alignx, bool aligny) { }
public void OnToggleUpperUnpegged() { }
public void OnToggleLowerUnpegged() { }
public void OnProcess(long deltatime) { }
public void OnTextureFloodfill() { }
public void OnInsert() { }
public void OnTextureFit(FitTextureOptions options) { } //mxd
public void ApplyTexture(string texture) { }
public void ApplyUpperUnpegged(bool set) { }
public void ApplyLowerUnpegged(bool set) { }
public void SelectNeighbours(bool select, bool withSameTexture, bool withSameHeight) { } //mxd
public virtual void OnPaintSelectEnd() { } // biwa
public void OnChangeScale(int x, int y) { }
public void OnResetTextureOffset() { }
public void OnResetLocalTextureOffset() { }
public void OnCopyProperties() { }
public void OnPasteProperties(bool usecopysetting) { }
public void OnDelete() { }
public void OnPaintSelectBegin() { }
public void OnMouseMove(MouseEventArgs e) { }
#endregion
}
}

View file

@ -0,0 +1,351 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using CodeImp.DoomBuilder.BuilderModes;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
namespace CodeImp.DoomBuilder.VisualModes
{
/// <summary>
/// Stores the normalized angle (clockwise from the vertex) and if the original line's front points in a clockwise or counter clockwise direction
/// </summary>
internal struct LineAngleInfo
{
public double angle;
public bool clockwise;
public LineAngleInfo(Linedef ld, Vertex v, Sector s)
{
Line2D line;
if (ld.Start == v)
{
line = ld.Line;
clockwise = true;
}
else
{
line = new Line2D(ld.End.Position, ld.Start.Position);
clockwise = false;
}
angle = line.GetAngle();
if (ld.Front.Sector != s)
clockwise = !clockwise;
}
}
internal class VisualVertexSlope : BaseVisualSlope
{
#region ================== Variables
private readonly Vertex vertex;
private readonly Sector sector;
private double angle;
#endregion
#region ================== Properties
public Vertex Vertex { get { return vertex; } }
public Sector Sector { get { return sector; } }
#endregion
#region ================== Constructor / Destructor
public VisualVertexSlope(BaseVisualMode mode, SectorLevel level, Vertex vertex, Sector sector, bool up) : base(mode, level, up)
{
this.vertex = vertex;
this.sector = sector;
type = VisualSlopeType.Vertex;
ComputeAngle();
Update();
GC.SuppressFinalize(this);
}
#endregion
#region ================== Methods
private void ComputeAngle()
{
List<LineAngleInfo> lines = new List<LineAngleInfo>();
List<double> angles = new List<double>();
// Special case handling
if (vertex.Linedefs.Count == 0) // should never happen
{
angle = 0.0;
return;
}
else if (vertex.Linedefs.Count == 1)
{
angle = vertex.Linedefs.First().Angle + Angle2D.PIHALF;
return;
}
// Get all lines that we have to take into account. Ignore linedefs where both sides
// don't belong to the sector or don't belong to the sector
foreach (Linedef ld in vertex.Linedefs)
{
if (ld.IsDisposed)
continue;
else
{
bool frontsame = false;
bool backsame = false;
if (ld.Front != null && ld.Front.Sector == sector)
frontsame = true;
if (ld.Back != null && ld.Back.Sector == sector)
backsame = true;
if (frontsame == backsame)
continue;
}
lines.Add(new LineAngleInfo(ld, vertex, sector));
}
// Special case handling
if(lines.Count == 0)
{
angle = lines[0].angle;
return;
}
// Sort lines by their normalized angle
lines.Sort((a, b) => a.angle.CompareTo(b.angle));
// Get the other line we want to compute the angle between
int other = 1;
if (!lines[0].clockwise)
other = lines.Count - 1;
Vector2D v1 = Vector2D.FromAngle(lines[0].angle);
Vector2D v2 = Vector2D.FromAngle(lines[other].angle);
angle = lines[0].angle + (Math.Atan2(v2.y, v2.x) - Math.Atan2(v1.y, v1.x)) / 2.0;
// If the first line is going clockwise we have to add 180°
if (lines[0].clockwise)
angle += Angle2D.PI;
// Add 90° to get it in line with Doom's angles
angle += Angle2D.PIHALF;
// Also need to modify the angle for ceilings
if (level.type == SectorLevelType.Ceiling)
angle += Angle2D.PI;
angle = Angle2D.Normalized(angle);
}
public override void Update()
{
plane = new Plane(level.plane.Normal, level.plane.Offset - 0.1f);
if (!up)
plane = plane.GetInverted();
UpdatePosition();
}
public void UpdatePosition()
{
Vector2D av = Vector2D.FromAngle(angle);
SetPosition(new Line2D(vertex.Position, vertex.Position + av), level.plane);
}
/// <summary>
/// Finds a slope handle to pivot around. It takes the vertex that's furthest away from the given handle
/// </summary>
/// <param name="starthandle">The slope handle to start from (the one we need to find a pivot handle for)</param>
/// <returns></returns>
public static VisualVertexSlope GetSmartPivotHandle(VisualVertexSlope starthandle, BaseVisualMode mode)
{
VisualVertexSlope handle = starthandle;
List<VisualVertexSlope> potentialhandles = new List<VisualVertexSlope>();
List<IVisualEventReceiver> selectedsectors = mode.GetSelectedObjects(true, false, false, false, false);
if (selectedsectors.Count == 0)
{
// No sectors selected, so find all handles that belong to the same level
foreach (VisualVertexSlope checkhandle in mode.VertexSlopeHandles[starthandle.Sector])
{
if (checkhandle != starthandle && checkhandle.Level == starthandle.Level)
potentialhandles.Add(checkhandle);
}
}
else
{
// Sectors are selected, get all handles from those sectors that have the same level
HashSet<Sector> sectors = new HashSet<Sector>();
foreach (BaseVisualGeometrySector bvgs in selectedsectors)
sectors.Add(bvgs.Sector.Sector);
foreach (Sector s in sectors)
foreach (VisualVertexSlope checkhandle in mode.VertexSlopeHandles[s])
{
if (checkhandle != starthandle)
foreach (BaseVisualGeometrySector bvgs in selectedsectors)
if (bvgs.Level == checkhandle.Level)
potentialhandles.Add(checkhandle);
}
}
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in mode.AllSlopeHandles)
foreach (VisualSlope checkhandle in kvp.Value)
checkhandle.SmartPivot = false;
handle = potentialhandles.OrderByDescending(h => Vector2D.Distance(h.Vertex.Position, starthandle.vertex.Position)).First();
if (handle == starthandle)
return null;
return handle;
}
/// <summary>
/// This is called when the thing must be tested for line intersection. This should reject
/// as fast as possible to rule out all geometry that certainly does not touch the line.
/// </summary>
public override bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
{
if (vertex.IsDisposed || sector.IsDisposed)
return false;
RectangleF bbox = sector.BBox;
if ((up && plane.Distance(from) > 0.0f) || (!up && plane.Distance(from) < 0.0f))
{
if (plane.GetIntersection(from, to, ref pickrayu))
{
if (pickrayu > 0.0f)
{
pickintersect = from + (to - from) * pickrayu;
return ((pickintersect.x >= bbox.Left) && (pickintersect.x <= bbox.Right) &&
(pickintersect.y >= bbox.Top) && (pickintersect.y <= bbox.Bottom));
}
}
}
return false;
}
/// <summary>
/// This is called when the thing must be tested for line intersection. This should perform
/// accurate hit detection and set u_ray to the position on the ray where this hits the geometry.
/// </summary>
public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref double u_ray)
{
u_ray = pickrayu;
Sidedef sd = MapSet.NearestSidedef(sector.Sidedefs, pickintersect);
Vertex v = MapSet.NearestVertex(new Vertex[] { sd.Line.Start, sd.Line.End }, pickintersect);
if (v == vertex)
{
double side = sd.Line.SideOfLine(pickintersect);
if ((side <= 0.0f && sd.IsFront) || (side > 0.0f && !sd.IsFront))
return true;
}
return false;
}
/// <summary>
/// Gets the pivor point for this slope handle
/// </summary>
/// <returns>The pivot point as Vector3D</returns>
public override Vector3D GetPivotPoint()
{
return new Vector3D(vertex.Position, level.plane.GetZ(vertex.Position));
}
#endregion
#region ================== Events
public override void OnChangeTargetHeight(int amount)
{
VisualSlope pivothandle = null;
List<IVisualEventReceiver> selectedsectors = mode.GetSelectedObjects(true, false, false, false, false);
List<SectorLevel> levels = new List<SectorLevel>();
if (selectedsectors.Count == 0)
levels.Add(level);
else
{
foreach (BaseVisualGeometrySector bvgs in selectedsectors)
levels.Add(bvgs.Level);
if (!levels.Contains(level))
levels.Add(level);
}
// Try to find a slope handle the user set to be the pivot handle
// TODO: doing this every time is kind of stupid. Maybe store the pivot handle in the mode?
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in mode.AllSlopeHandles)
{
foreach (VisualSlope handle in kvp.Value)
{
if (handle.Pivot)
{
pivothandle = handle;
break;
}
}
}
// User didn't set a pivot handle, try to find the smart pivot handle
if (pivothandle == null)
pivothandle = GetSmartPivotHandle(this, mode);
// Still no pivot handle, cancle
if (pivothandle == null)
return;
pivothandle.SmartPivot = true;
mode.CreateUndo("Change slope");
Plane originalplane = level.plane;
// Build a new plane. Since we only got 2 points (the pivot point of the pivot handle and the vertex slope vertex) we need
// to create a third point. That's done by getting the perpendicular of the line between the aforementioned 2 points, then
// add the perpendicular to the vertex position of the vertex slope vertex
Vector3D p3 = pivothandle.GetPivotPoint();
Vector2D perp = new Line2D(vertex.Position, p3).GetPerpendicular();
Vector3D p1 = new Vector3D(vertex.Position, originalplane.GetZ(vertex.Position) + amount);
Vector3D p2 = new Vector3D(vertex.Position + perp, originalplane.GetZ(vertex.Position + perp) + amount);
Plane plane = new Plane(p1, p2, p3, true);
// Apply slope to surfaces
foreach (SectorLevel l in levels)
VisualSidedefSlope.ApplySlope(l, plane, mode);
mode.SetActionResult("Changed slope.");
}
#endregion
}
}