Ported visual sloping to UDB

This commit is contained in:
biwa 2019-12-31 00:08:17 +01:00
parent 1e90500a3f
commit ba713f7a25
14 changed files with 1002 additions and 65 deletions

View file

@ -246,6 +246,8 @@
<Compile Include="Rendering\Vector3.cs" />
<Compile Include="Rendering\Vector4.cs" />
<Compile Include="Rendering\VertexBuffer.cs" />
<Compile Include="Rendering\VisualSlopeHandle.cs" />
<Compile Include="VisualModes\VisualSlope.cs" />
<Compile Include="Windows\ThingStatisticsForm.cs">
<SubType>Form</SubType>
</Compile>

View file

@ -2181,6 +2181,7 @@ namespace CodeImp.DoomBuilder
// Update settings
renderer3d.CreateProjection();
renderer3d.UpdateVertexHandle(); //mxd
renderer3d.UpdateVisualSlopeHandle();
// Things filters
General.MainWindow.UpdateThingsFilters();

View file

@ -50,6 +50,7 @@ namespace CodeImp.DoomBuilder.Rendering
void AddSectorGeometry(VisualGeometry g);
void AddThingGeometry(VisualThing t);
void SetVisualVertices(List<VisualVertex> verts);
void SetVisualSlopeHandles(List<VisualSlope> handles);
void SetEventLines(List<Line3D> lines);
void RenderCrosshair();
void SetFogMode(bool usefog);

View file

@ -63,7 +63,10 @@ namespace CodeImp.DoomBuilder.Rendering
//mxd
private VisualVertexHandle vertexhandle;
private int[] lightOffsets;
// Slope handle
private VisualSlopeHandle visualslopehandle;
// Crosshair
private FlatVertex[] crosshairverts;
private bool crosshairbusy;
@ -111,6 +114,9 @@ namespace CodeImp.DoomBuilder.Rendering
//mxd. Visual vertices
private List<VisualVertex> visualvertices;
// Visual slope handles
private List<VisualSlope> visualslopehandles;
//mxd. Event lines
private List<Line3D> eventlines;
@ -165,7 +171,8 @@ namespace CodeImp.DoomBuilder.Rendering
{
// Clean up
if(vertexhandle != null) vertexhandle.Dispose(); //mxd
if (visualslopehandle != null) visualslopehandle.Dispose();
// Done
base.Dispose();
}
@ -231,8 +238,17 @@ namespace CodeImp.DoomBuilder.Rendering
}
}
internal void UpdateVisualSlopeHandle()
{
if (visualslopehandle != null)
{
visualslopehandle.UnloadResource();
visualslopehandle.ReloadResource();
}
}
#endregion
#region ================== Presentation
// This creates the projection
@ -343,7 +359,10 @@ namespace CodeImp.DoomBuilder.Rendering
//mxd. Crate vertex handle
if(vertexhandle == null) vertexhandle = new VisualVertexHandle();
// Create slope handle
if (visualslopehandle == null) visualslopehandle = new VisualSlopeHandle();
// Ready
return true;
}
@ -491,8 +510,12 @@ namespace CodeImp.DoomBuilder.Rendering
//mxd. Visual vertices
RenderVertices();
// Slope handles
if (General.Map.UDMF /* && General.Settings.ShowVisualSlopeHandles */)
RenderSlopeHandles();
//mxd. Event lines
if(General.Settings.GZShowEventLines) RenderArrows(eventlines);
if (General.Settings.GZShowEventLines) RenderArrows(eventlines);
// Remove references
graphics.SetTexture(null);
@ -659,6 +682,54 @@ namespace CodeImp.DoomBuilder.Rendering
graphics.SetUniform(UniformName.texturefactor, new Color4(1f, 1f, 1f, 1f));
}
private void RenderSlopeHandles()
{
/*
if (visualslopehandles == null) return;
graphics.SetAlphaBlendEnable(true);
graphics.SetAlphaTestEnable(false);
graphics.SetZWriteEnable(false);
graphics.SetSourceBlend(Blend.SourceAlpha);
graphics.SetDestinationBlend(Blend.SourceAlpha);
graphics.Shaders.World3D.BeginPass(18);
// world = Matrix.Identity;
// ApplyMatrices3D();
foreach (VisualSlope handle in visualslopehandles)
{
PixelColor color = General.Colors.Vertices;
if (handle.Pivot)
color = General.Colors.Guideline;
else if (handle.Selected)
color = General.Colors.Selection3D;
else if (handle == highlighted)
color = General.Colors.Highlight3D;
else if (handle.SmartPivot)
color = General.Colors.Vertices;
world = handle.Position;
ApplyMatrices3D();
handle.Update(color);
graphics.Shaders.World3D.VertexColor = color.ToColorValue();
graphics.Shaders.World3D.SlopeHandleLength = handle.Length;
graphics.Shaders.World3D.ApplySettings();
// graphics.Device.SetStreamSource(0, handle.GeoBuffer, 0, WorldVertex.Stride);
graphics.Device.SetStreamSource(0, visualslopehandle.Geometry, 0, WorldVertex.Stride);
graphics.Device.DrawPrimitives(PrimitiveType.TriangleList, 0, 2);
}
// Done
graphics.SetUniform(UniformName.texturefactor, new Color4(1f, 1f, 1f, 1f));
*/
}
//mxd
private void RenderArrows(ICollection<Line3D> lines)
{
@ -1966,6 +2037,8 @@ namespace CodeImp.DoomBuilder.Rendering
//mxd
public void SetVisualVertices(List<VisualVertex> verts) { visualvertices = verts; }
public void SetVisualSlopeHandles(List<VisualSlope> handles) { visualslopehandles = handles; }
//mxd
public void SetEventLines(List<Line3D> lines) { eventlines = lines; }

View file

@ -0,0 +1,89 @@
#region ================== Namespaces
using System;
#endregion
namespace CodeImp.DoomBuilder.Rendering
{
internal sealed class VisualSlopeHandle : IDisposable, IRenderResource
{
#region ================== Variables
private VertexBuffer geometry;
private bool isdisposed;
#endregion
#region ================== Properties
public VertexBuffer Geometry { get { return geometry; } }
#endregion
#region ================== Constructor / Disposer
public VisualSlopeHandle()
{
// Create geometry
ReloadResource();
// Register as source
General.Map.Graphics.RegisterResource(this);
}
public void Dispose()
{
// Not already disposed?
if (!isdisposed)
{
if (geometry != null)
geometry.Dispose();
// Unregister resource
General.Map.Graphics.UnregisterResource(this);
// Done
isdisposed = true;
}
}
#endregion
#region ================== Methods
// This is called resets when the device is reset
// (when resized or display adapter was changed)
public void ReloadResource()
{
WorldVertex v0 = new WorldVertex(0.0f, 0.0f, 0.5f);
WorldVertex v1 = new WorldVertex(1.0f, 0.0f, 0.5f);
WorldVertex v2 = new WorldVertex(1.0f, 8.0f, 0.5f);
WorldVertex v3 = new WorldVertex(0.0f, 8.0f, 0.5f);
v0.c = v1.c = PixelColor.INT_WHITE;
v2.c = v3.c = PixelColor.INT_WHITE_NO_ALPHA;
WorldVertex[] vertices = new[]
{
v2, v1, v0,
v3, v2, v0
};
geometry = new VertexBuffer();
General.Map.Graphics.SetBufferData(geometry, vertices);
}
// This is called before a device is reset
// (when resized or display adapter was changed)
public void UnloadResource()
{
if (geometry != null)
geometry.Dispose();
geometry = null;
}
#endregion
}
}

View file

@ -72,6 +72,7 @@ namespace CodeImp.DoomBuilder.VisualModes
protected VisualBlockMap blockmap;
protected Dictionary<Thing, VisualThing> allthings;
protected Dictionary<Sector, VisualSector> allsectors;
protected Dictionary<Sector, List<VisualSlope>> allslopehandles;
protected List<VisualBlockEntry> visibleblocks;
protected List<VisualThing> visiblethings;
protected List<VisualSector> visiblesectors;
@ -85,6 +86,7 @@ namespace CodeImp.DoomBuilder.VisualModes
public bool ProcessThings { get { return processthings; } set { processthings = value; } }
public VisualBlockMap BlockMap { get { return blockmap; } }
public Dictionary<Vertex, VisualVertexPair> VisualVertices { get { return vertices; } } //mxd
public Dictionary<Sector, List<VisualSlope>> AllSlopeHandles { get { return allslopehandles; } }
// Rendering
public IRenderer3D Renderer { get { return renderer; } }
@ -103,6 +105,7 @@ namespace CodeImp.DoomBuilder.VisualModes
this.blockmap = new VisualBlockMap();
this.allsectors = new Dictionary<Sector, VisualSector>(General.Map.Map.Sectors.Count);
this.allthings = new Dictionary<Thing, VisualThing>(General.Map.Map.Things.Count);
this.allslopehandles = new Dictionary<Sector, List<VisualSlope>>(General.Map.Map.Sectors.Count);
this.visibleblocks = new List<VisualBlockEntry>();
this.visiblesectors = new List<VisualSector>(50);
this.visiblegeometry = new List<VisualGeometry>(200);
@ -223,8 +226,14 @@ namespace CodeImp.DoomBuilder.VisualModes
// Dispose
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
if(vt.Value != null) vt.Value.Dispose();
if(vt.Value != null) vt.Value.Dispose();
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in allslopehandles)
{
foreach (VisualSlope handle in kvp.Value)
if (handle != null) handle.Dispose();
}
// Apply camera position to thing
General.Map.VisualCamera.ApplyToThing();
@ -720,6 +729,10 @@ namespace CodeImp.DoomBuilder.VisualModes
VisualSector vs = allsectors[General.Map.VisualCamera.Sector];
sectors.Add(General.Map.VisualCamera.Sector, vs);
foreach(VisualGeometry g in vs.FixedGeometry) pickables.Add(g);
// Add slope handles
if (General.Map.UDMF && General.Interface.AltState && allslopehandles.ContainsKey(General.Map.VisualCamera.Sector))
pickables.AddRange(allslopehandles[General.Map.VisualCamera.Sector]);
}
// Go for all lines to see which ones we intersect
@ -764,6 +777,10 @@ namespace CodeImp.DoomBuilder.VisualModes
if(g.Triangles > 0)
pickables.Add(g);
}
// Add slope handles
if (General.Map.UDMF /* && General.Settings.ShowVisualSlopeHandles */ && General.Interface.AltState && allslopehandles.ContainsKey(ld.Front.Sector))
pickables.AddRange(allslopehandles[ld.Front.Sector]);
}
// Add sidedef if on the front side
@ -801,6 +818,10 @@ namespace CodeImp.DoomBuilder.VisualModes
if(g.Triangles > 0)
pickables.Add(g);
}
// Add slope handles
if (General.Map.UDMF /* && General.Settings.ShowVisualSlopeHandles */ && General.Interface.AltState && allslopehandles.ContainsKey(ld.Back.Sector))
pickables.AddRange(allslopehandles[ld.Back.Sector]);
}
// Add sidedef if on the front side

View file

@ -0,0 +1,126 @@
using System;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Rendering;
namespace CodeImp.DoomBuilder.VisualModes
{
public abstract class VisualSlope : IVisualPickable, IDisposable
{
#region ================== Variables
// Disposing
private bool isdisposed;
// Selected?
protected bool selected;
// Pivot?
protected bool pivot;
// Smart Pivot?
protected bool smartpivot;
// Was changed?
private bool changed;
protected float length;
private Matrix position;
#endregion
#region ================== Properties
/// <summary>
/// Selected or not? This is only used by the core to determine what color to draw it with.
/// </summary>
public bool Selected { get { return selected; } set { selected = value; } }
/// <summary>
/// Pivot or not? This is only used by the core to determine what color to draw it with.
/// </summary>
public bool Pivot { get { return pivot; } set { pivot = value; } }
/// <summary>
/// Disposed or not?
/// </summary>
public bool IsDisposed { get { return isdisposed; } }
public bool SmartPivot { get { return smartpivot; } set { smartpivot = value; } }
public bool Changed { get { return changed; } set { changed = value; } }
public float Length { get { return length; } }
public Matrix Position { get { return position; } }
#endregion
#region ================== Constructor / Destructor
public VisualSlope()
{
// Register as resource
// General.Map.Graphics.RegisterResource(this);
pivot = false;
smartpivot = false;
}
// Disposer
public virtual void Dispose()
{
// Not already disposed?
}
#endregion
#region ================== Methods
// This is called before a device is reset (when resized or display adapter was changed)
public void UnloadResource()
{
}
// This is called resets when the device is reset
// (when resized or display adapter was changed)
public void ReloadResource()
{
}
/// <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 virtual bool PickFastReject(Vector3D from, Vector3D to, Vector3D dir)
{
return true;
}
/// <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 virtual bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
{
return true;
}
public virtual bool Update(PixelColor color)
{
return true;
}
public void SetPosition(Vector3D pos, Geometry.Plane plane, float angle)
{
Matrix translate = Matrix.Translation(pos.x, pos.y, pos.z);
Vector3 v = new Vector3(plane.Normal.x, plane.Normal.y, plane.Normal.z);
// Matrix rotate = Matrix.RotationAxis(v, angle);
//position = Matrix.Multiply(rotate, translate);
}
#endregion
}
}

View file

@ -495,6 +495,7 @@
<Compile Include="VisualModes\VisualMiddleDouble.cs" />
<Compile Include="VisualModes\VisualMiddleSingle.cs" />
<Compile Include="VisualModes\VisualSidedefParts.cs" />
<Compile Include="VisualModes\VisualSidedefSlope.cs" />
<Compile Include="VisualModes\VisualUpper.cs" />
<Compile Include="VisualModes\WallPolygon.cs" />
</ItemGroup>

View file

@ -1405,3 +1405,14 @@ visualpaintselect
disregardcontrol = true;
disregardalt = true;
}
selectvisualslopepivot
{
title = "Select Visual Slope Pivot";
category = "visual";
description = "Selects a visual slope handle to act as the pivot for sloping actions.";
allowkeys = true;
allowmouse = true;
allowscroll = false;
default = 262146; // Alt-RMB
}

View file

@ -873,8 +873,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
if(vs != null) vs.UpdateSectorGeometry(true);
// Visual slope handles need to be updated, too
if (General.Map.UDMF)
{
if (mode.AllSlopeHandles.ContainsKey(level.sector))
foreach (VisualSidedefSlope handle in mode.AllSlopeHandles[level.sector])
handle.Changed = true;
}
}
// Sector brightness change
public virtual void OnChangeTargetBrightness(bool up)
{

View file

@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using CodeImp.DoomBuilder.BuilderModes.Interface;
using CodeImp.DoomBuilder.Windows;
@ -392,6 +393,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
if (General.Map.UDMF)
{
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in allslopehandles)
{
foreach (VisualSlope handle in kvp.Value)
if (handle.Selected) selectedobjects.Add((VisualSidedefSlope)handle);
}
}
//mxd
UpdateSelectionInfo();
}
@ -411,7 +421,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
allsectors.Add(s, vs); //mxd
return vs;
}
internal VisualSlope CreateVisualSlopeHandle(SectorLevel level, Sidedef sd, bool up)
{
VisualSidedefSlope handle = new VisualSidedefSlope(this, level, sd, up);
if (!allslopehandles.ContainsKey(sd.Sector))
allslopehandles.Add(sd.Sector, new List<VisualSlope>());
allslopehandles[sd.Sector].Add(handle);
return handle;
}
// This creates a visual thing
protected override VisualThing CreateVisualThing(Thing t)
{
@ -512,7 +534,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(vs.Value != null)
{
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if(bvs.Changed) bvs.Rebuild();
if(bvs.Changed)
{
bvs.Rebuild();
// Also update slope handles
if (allslopehandles.ContainsKey(vs.Key))
foreach (VisualSidedefSlope handle in allslopehandles[vs.Key])
handle.Setup();
}
}
}
@ -1121,6 +1151,45 @@ namespace CodeImp.DoomBuilder.BuilderModes
break;
}
}
// Visual slope handles
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in allslopehandles)
{
foreach (VisualSlope handle in kvp.Value)
if (handle != null)
{
if (handle.Selected) RemoveSelectedObject((VisualSidedefSlope)handle);
handle.Dispose();
}
kvp.Value.Clear();
}
allslopehandles.Clear();
if (General.Map.UDMF /* && General.Settings.ShowVisualSlopeHandles */)
{
foreach (Sector s in General.Map.Map.Sectors)
{
SectorData sectordata = GetSectorData(s);
sectordata.Update();
foreach (Sidedef sidedef in s.Sidedefs)
{
VisualSlope handle = CreateVisualSlopeHandle(sectordata.Floor, sidedef, true);
handle = CreateVisualSlopeHandle(sectordata.Ceiling, sidedef, false);
if (sectordata.ExtraFloors.Count > 0)
{
foreach (Effect3DFloor floor in sectordata.ExtraFloors)
{
handle = CreateVisualSlopeHandle(floor.Floor, sidedef, false);
handle = CreateVisualSlopeHandle(floor.Ceiling, sidedef, true);
}
}
}
}
}
}
#endregion
@ -1361,7 +1430,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
renderer.SetVisualVertices(verts);
}
// Visual slope handles
List<VisualSlope> handles = new List<VisualSlope>();
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in allslopehandles)
foreach (VisualSlope handle in kvp.Value)
if (handle.Selected || handle.Pivot || /* handle.SmartPivot || */ target.picked == handle)
handles.Add(handle);
renderer.SetVisualSlopeHandles(handles);
// Done rendering geometry
renderer.FinishGeometry();
@ -1660,7 +1738,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Apply texture offsets
public void ApplyTextureOffsetChange(int dx, int dy)
{
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false, false);
//mxd. Because Upper/Middle/Lower textures offsets should be threated separately in UDMF
//MaxW. But they're not for Eternity, so this needs its own config setting
@ -1702,7 +1780,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void ApplyFlatOffsetChange(int dx, int dy)
{
HashSet<int> donesectors = new HashSet<int>();
List<IVisualEventReceiver> objs = GetSelectedObjects(true, false, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, false, false, false, false);
foreach(IVisualEventReceiver i in objs)
{
BaseVisualGeometrySector bvs = (BaseVisualGeometrySector)i;
@ -1759,7 +1837,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Apply upper unpegged flag
public void ApplyUpperUnpegged(bool set)
{
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false, false);
foreach(IVisualEventReceiver i in objs)
{
i.ApplyUpperUnpegged(set);
@ -1769,7 +1847,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Apply lower unpegged flag
public void ApplyLowerUnpegged(bool set)
{
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false, false);
foreach(IVisualEventReceiver i in objs)
{
i.ApplyLowerUnpegged(set);
@ -1784,12 +1862,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
if(General.Map.Config.MixTexturesFlats)
{
// Apply on all compatible types
objs = GetSelectedObjects(true, true, false, false);
objs = GetSelectedObjects(true, true, false, false, false);
}
else
{
// We don't want to mix textures and flats, so apply only on the appropriate type
objs = GetSelectedObjects(flat, !flat, false, false);
objs = GetSelectedObjects(flat, !flat, false, false, false);
}
foreach(IVisualEventReceiver i in objs)
@ -1799,7 +1877,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
// This returns all selected objects
internal List<IVisualEventReceiver> GetSelectedObjects(bool includesectors, bool includesidedefs, bool includethings, bool includevertices)
internal List<IVisualEventReceiver> GetSelectedObjects(bool includesectors, bool includesidedefs, bool includethings, bool includevertices, bool includeslopehandles)
{
List<IVisualEventReceiver> objs = new List<IVisualEventReceiver>();
foreach(IVisualEventReceiver i in selectedobjects)
@ -1808,6 +1886,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
else if(includesidedefs && (i is BaseVisualGeometrySidedef)) objs.Add(i);
else if(includethings && (i is BaseVisualThing)) objs.Add(i);
else if(includevertices && (i is BaseVisualVertex)) objs.Add(i); //mxd
else if (includeslopehandles && (i is VisualSlope)) objs.Add(i); // biwa
}
// Add highlight?
@ -1818,6 +1897,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
else if(includesidedefs && (i is BaseVisualGeometrySidedef)) objs.Add(i);
else if(includethings && (i is BaseVisualThing)) objs.Add(i);
else if(includevertices && (i is BaseVisualVertex)) objs.Add(i); //mxd
else if (includeslopehandles && (i is VisualSlope)) objs.Add(i); // biwa
}
return objs;
@ -2068,14 +2148,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
#region ================== Actions
// [ZZ] I moved this out of ClearSelection because "cut selection" action needs this to only affect things.
private void ClearSelection(bool clearsectors, bool clearsidedefs, bool clearthings, bool clearvertices, bool displaystatus)
private void ClearSelection(bool clearsectors, bool clearsidedefs, bool clearthings, bool clearvertices, bool clearslopehandles, bool displaystatus)
{
selectedobjects.RemoveAll(obj =>
{
return ((obj is BaseVisualGeometrySector && clearsectors) ||
(obj is BaseVisualGeometrySidedef && clearsidedefs) ||
(obj is BaseVisualThing && clearthings) ||
(obj is BaseVisualVertex && clearvertices));
(obj is BaseVisualVertex && clearvertices) ||
(obj is VisualSlope && clearslopehandles));
});
//
@ -2126,8 +2207,24 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
}
//mxd
if (displaystatus)
// biwa
if (clearslopehandles)
{
if (General.Map.UDMF)
{
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in allslopehandles)
{
foreach (VisualSidedefSlope handle in kvp.Value)
{
handle.Selected = false;
handle.Pivot = false;
}
}
}
}
//mxd
if (displaystatus)
{
General.Interface.DisplayStatus(StatusType.Selection, string.Empty);
}
@ -2136,7 +2233,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
[BeginAction("clearselection", BaseAction = true)]
public void ClearSelection()
{
ClearSelection(true, true, true, true, true);
ClearSelection(true, true, true, true, true, true);
}
[BeginAction("visualselect", BaseAction = true)]
@ -2196,8 +2293,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void RaiseSector8()
{
PreAction(UndoGroup.SectorHeightChange);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true);
foreach(IVisualEventReceiver i in objs) i.OnChangeTargetHeight(8);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true, true);
bool hasvisualslopehandles = objs.Any(o => o is VisualSlope);
foreach (IVisualEventReceiver i in objs) // If slope handles are selected only apply the action to them
if (!hasvisualslopehandles || (hasvisualslopehandles && i is VisualSlope))
i.OnChangeTargetHeight(8);
PostAction();
}
@ -2205,45 +2305,56 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void LowerSector8()
{
PreAction(UndoGroup.SectorHeightChange);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true);
foreach(IVisualEventReceiver i in objs) i.OnChangeTargetHeight(-8);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true, true);
bool hasvisualslopehandles = objs.Any(o => o is VisualSlope);
foreach (IVisualEventReceiver i in objs) // If slope handles are selected only apply the action to them
if (!hasvisualslopehandles || (hasvisualslopehandles && i is VisualSlope))
i.OnChangeTargetHeight(-8);
PostAction();
}
[BeginAction("raisesector1")]
public void RaiseSector1() {
PreAction(UndoGroup.SectorHeightChange);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true);
foreach (IVisualEventReceiver i in objs)
i.OnChangeTargetHeight(1);
PostAction();
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true, true);
bool hasvisualslopehandles = objs.Any(o => o is VisualSlope);
foreach (IVisualEventReceiver i in objs) // If slope handles are selected only apply the action to them
if (!hasvisualslopehandles || (hasvisualslopehandles && i is VisualSlope))
i.OnChangeTargetHeight(1);
PostAction();
}
[BeginAction("lowersector1")]
public void LowerSector1() {
PreAction(UndoGroup.SectorHeightChange);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true);
foreach (IVisualEventReceiver i in objs)
i.OnChangeTargetHeight(-1);
PostAction();
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true, true);
bool hasvisualslopehandles = objs.Any(o => o is VisualSlope);
foreach (IVisualEventReceiver i in objs) // If slope handles are selected only apply the action to them
if (!hasvisualslopehandles || (hasvisualslopehandles && i is VisualSlope))
i.OnChangeTargetHeight(-1);
PostAction();
}
[BeginAction("raisesector128")]
public void RaiseSector128() {
PreAction(UndoGroup.SectorHeightChange);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true);
foreach (IVisualEventReceiver i in objs)
i.OnChangeTargetHeight(128);
PostAction();
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true, true);
bool hasvisualslopehandles = objs.Any(o => o is VisualSlope);
foreach (IVisualEventReceiver i in objs) // If slope handles are selected only apply the action to them
if (!hasvisualslopehandles || (hasvisualslopehandles && i is VisualSlope))
i.OnChangeTargetHeight(128);
PostAction();
}
[BeginAction("lowersector128")]
public void LowerSector128() {
PreAction(UndoGroup.SectorHeightChange);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true);
foreach (IVisualEventReceiver i in objs)
i.OnChangeTargetHeight(-128);
PostAction();
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true, true);
bool hasvisualslopehandles = objs.Any(o => o is VisualSlope);
foreach (IVisualEventReceiver i in objs) // If slope handles are selected only apply the action to them
if (!hasvisualslopehandles || (hasvisualslopehandles && i is VisualSlope))
i.OnChangeTargetHeight(-128);
PostAction();
}
@ -2800,7 +2911,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void RaiseBrightness8()
{
PreAction(UndoGroup.SectorBrightnessChange);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false, false);
foreach(IVisualEventReceiver i in objs) i.OnChangeTargetBrightness(true);
PostAction();
}
@ -2809,7 +2920,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void LowerBrightness8()
{
PreAction(UndoGroup.SectorBrightnessChange);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false, false);
foreach(IVisualEventReceiver i in objs) i.OnChangeTargetBrightness(false);
PostAction();
}
@ -2831,7 +2942,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
private void MoveTextureByOffset(int ox, int oy)
{
PreAction(UndoGroup.TextureOffsetChange);
IEnumerable<IVisualEventReceiver> objs = RemoveDuplicateSidedefs(GetSelectedObjects(true, true, false, false));
IEnumerable<IVisualEventReceiver> objs = RemoveDuplicateSidedefs(GetSelectedObjects(true, true, false, false, false));
foreach(IVisualEventReceiver i in objs) i.OnChangeTextureOffset(ox, oy, true);
PostAction();
}
@ -2848,7 +2959,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
private void ScaleTexture(int incrementx, int incrementy)
{
PreAction(UndoGroup.TextureScaleChange);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, false, false);
foreach(IVisualEventReceiver i in objs) i.OnChangeScale(incrementx, incrementy);
PostAction();
}
@ -2878,7 +2989,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void TexturePaste()
{
PreAction(UndoGroup.None);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false, false);
foreach(IVisualEventReceiver i in objs) i.OnPasteTexture();
PostAction();
}
@ -2980,7 +3091,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
General.Map.Map.ClearMarkedSidedefs(false);
//get selection
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false, false);
//align
foreach(IVisualEventReceiver i in objs)
@ -3016,7 +3127,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
PreAction(UndoGroup.None);
// Get selection
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false, false);
List<BaseVisualGeometrySidedef> sides = new List<BaseVisualGeometrySidedef>();
foreach(IVisualEventReceiver i in objs)
{
@ -3068,7 +3179,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void ResetTexture()
{
PreAction(UndoGroup.None);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, false, false);
foreach(IVisualEventReceiver i in objs) i.OnResetTextureOffset();
PostAction();
}
@ -3077,7 +3188,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void ResetLocalOffsets()
{
PreAction(UndoGroup.None);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, false, false);
foreach(IVisualEventReceiver i in objs) i.OnResetLocalTextureOffset();
PostAction();
}
@ -3102,7 +3213,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void TexturePasteOffsets()
{
PreAction(UndoGroup.None);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false, false);
foreach(IVisualEventReceiver i in objs) i.OnPasteTextureOffsets();
PostAction();
}
@ -3119,7 +3230,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void PasteProperties()
{
PreAction(UndoGroup.None);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true, false);
foreach(IVisualEventReceiver i in objs) i.OnPasteProperties(false);
PostAction();
}
@ -3134,7 +3245,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
var selection = new List<IVisualEventReceiver>();
// Sectors selected?
var obj = GetSelectedObjects(true, false, false, false);
var obj = GetSelectedObjects(true, false, false, false, false);
if(obj.Count > 0)
{
targettypes.Add(MapElementType.SECTOR);
@ -3153,7 +3264,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
// Sidedefs selected?
obj = GetSelectedObjects(false, true, false, false);
obj = GetSelectedObjects(false, true, false, false, false);
if(obj.Count > 0)
{
targettypes.Add(MapElementType.SIDEDEF);
@ -3172,7 +3283,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
// Things selected?
obj = GetSelectedObjects(false, false, true, false);
obj = GetSelectedObjects(false, false, true, false, false);
if(obj.Count > 0)
{
targettypes.Add(MapElementType.THING);
@ -3191,7 +3302,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
}
// Vertices selected?
obj = GetSelectedObjects(false, false, false, true);
obj = GetSelectedObjects(false, false, false, true, false);
if(obj.Count > 0)
{
targettypes.Add(MapElementType.VERTEX);
@ -3267,7 +3378,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
public void Delete()
{
PreAction(UndoGroup.None);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true);
List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, true, true, false);
foreach (IVisualEventReceiver i in objs)
{
if (i is BaseVisualThing)
@ -3283,7 +3394,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
[BeginAction("copyselection", BaseAction = true)]
public void CopySelection()
{
List<IVisualEventReceiver> objs = GetSelectedObjects(false, false, true, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(false, false, true, false, false);
if(objs.Count == 0) return;
copybuffer.Clear();
@ -3308,7 +3419,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
CreateUndo("Cut " + rest);
General.Interface.DisplayStatus(StatusType.Info, "Cut " + rest);
List<IVisualEventReceiver> objs = GetSelectedObjects(false, false, true, false);
List<IVisualEventReceiver> objs = GetSelectedObjects(false, false, true, false, false);
foreach(IVisualEventReceiver i in objs)
{
BaseVisualThing thing = (BaseVisualThing)i;
@ -3322,7 +3433,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
General.Map.ThingsFilter.Update();
// [ZZ] Clear selected things.
ClearSelection(false, false, true, false, false);
ClearSelection(false, false, true, false, false, false);
// Update event lines
renderer.SetEventLines(LinksCollector.GetHelperShapes(General.Map.ThingsFilter.VisibleThings, blockmap));
@ -3398,7 +3509,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
PreAction(UndoGroup.ThingAngleChange);
List<IVisualEventReceiver> selection = GetSelectedObjects(true, false, true, false);
List<IVisualEventReceiver> selection = GetSelectedObjects(true, false, true, false, false);
if(selection.Count == 0) return;
foreach(IVisualEventReceiver obj in selection)
@ -3460,7 +3571,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
PreAction(UndoGroup.ThingPitchChange);
List<IVisualEventReceiver> selection = GetSelectedObjects(false, false, true, false);
List<IVisualEventReceiver> selection = GetSelectedObjects(false, false, true, false, false);
if(selection.Count == 0) return;
foreach(IVisualEventReceiver obj in selection)
@ -3491,7 +3602,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
{
PreAction(UndoGroup.ThingRollChange);
List<IVisualEventReceiver> selection = GetSelectedObjects(false, false, true, false);
List<IVisualEventReceiver> selection = GetSelectedObjects(false, false, true, false, false);
if(selection.Count == 0) return;
foreach(IVisualEventReceiver obj in selection)
@ -3862,6 +3973,24 @@ namespace CodeImp.DoomBuilder.BuilderModes
GetTargetEventReceiver(true).OnPaintSelectEnd();
}
// biwa
[BeginAction("selectvisualslopepivot")]
public void SelectVisualSlopePivot()
{
if (target.picked is VisualSlope)
{
// We can only have one pivot handle, so remove it from all first
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in allslopehandles)
{
foreach (VisualSlope handle in kvp.Value)
if (target.picked != handle)
handle.Pivot = false;
}
((VisualSlope)target.picked).Pivot = !((VisualSlope)target.picked).Pivot;
}
}
#endregion
#region ================== Texture Alignment

View file

@ -391,6 +391,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd. Modify slope offset?
if(level.sector.CeilSlope.GetLengthSq() > 0)
{
/*
Vector3D center = new Vector3D(level.sector.BBox.X + level.sector.BBox.Width / 2,
level.sector.BBox.Y + level.sector.BBox.Height / 2,
level.sector.CeilHeight);
@ -401,6 +402,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
false);
level.sector.CeilSlopeOffset = p.Offset;
*/
level.sector.CeilSlopeOffset -= level.sector.CeilSlope.z * amount;
}
}

View file

@ -351,6 +351,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
//mxd. Modify slope offset?
if(level.sector.FloorSlope.GetLengthSq() > 0)
{
/*
Vector3D center = new Vector3D(level.sector.BBox.X + level.sector.BBox.Width / 2,
level.sector.BBox.Y + level.sector.BBox.Height / 2,
level.sector.FloorHeight);
@ -361,6 +362,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
true);
level.sector.FloorSlopeOffset = p.Offset;
*/
level.sector.FloorSlopeOffset -= level.sector.FloorSlope.z * amount;
}
}

View file

@ -0,0 +1,467 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using CodeImp.DoomBuilder.BuilderModes;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
namespace CodeImp.DoomBuilder.VisualModes
{
internal class VisualSidedefSlope : VisualSlope, IVisualEventReceiver
{
#region ================== Variables
private readonly BaseVisualMode mode;
private readonly Sidedef sidedef;
private readonly SectorLevel level;
private readonly bool up;
private RectangleF bbox;
private Vector3D pickintersect;
private float pickrayu;
private Plane plane;
#endregion
#region ================== Constants
private const int SIZE = 8;
#endregion
#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()
{
this.mode = mode;
this.sidedef = sidedef;
this.level = level;
this.up = up;
length = sidedef.Line.Length;
plane = new Plane(level.plane.Normal, level.plane.Offset - 0.1f);
if (!up)
plane = plane.GetInverted();
bbox = CreateBoundingBox();
// We have no destructor
GC.SuppressFinalize(this);
}
#endregion
#region ================== Methods
private RectangleF CreateBoundingBox()
{
Line2D l = sidedef.Line.Line;
float left = l.v1.x;
float right = l.v1.x;
float top = l.v1.y;
float bottom = l.v1.y;
if (l.v2.x < left) left = l.v2.x;
if (l.v2.x > right) right = l.v2.x;
if (l.v2.y > bottom) bottom = l.v2.y;
if (l.v2.y < top) top = l.v2.y;
return new RectangleF(left - SIZE, top - SIZE, right - left + SIZE*2, bottom - top + SIZE*2);
}
public bool Setup() { return Setup(General.Colors.Vertices); }
public bool Setup(PixelColor color)
{
if (sidedef == null)
return false;
plane = new Plane(level.plane.Normal, level.plane.Offset - 0.1f);
if (!up)
plane = plane.GetInverted();
Linedef ld = sidedef.Line;
SectorData sd = mode.GetSectorData(sidedef.Sector);
// Make vertices
WorldVertex[] verts = new WorldVertex[6];
Vector2D offset = ld.Line.GetPerpendicular().GetNormal()*SIZE * (sidedef.IsFront ? -1 : 1);
// Line2D line = new Line2D(ld.Line.GetCoordinatesAt(ld.LengthInv * SIZE), ld.Line.GetCoordinatesAt(1.0f - (ld.LengthInv * SIZE)));
Line2D line = ld.Line;
return true;
}
public override bool Update(PixelColor color)
{
UpdatePosition();
return Setup(color);
}
/// <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 ((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 float u_ray)
{
u_ray = pickrayu;
Sidedef sd = MapSet.NearestSidedef(sidedef.Sector.Sidedefs, pickintersect);
if (sd == sidedef) {
float side = sd.Line.SideOfLine(pickintersect);
if ((side <= 0.0f && sd.IsFront) || (side > 0.0f && !sd.IsFront))
{
if (sidedef.Line.DistanceTo(pickintersect, true) <= SIZE)
return true;
}
}
return false;
}
public void UpdatePosition()
{
float angle;
Vector3D pos;
if (sidedef.IsFront)
{
pos = sidedef.Line.End.Position;
pos.z = plane.GetZ(pos);
angle = sidedef.Line.Angle + (float)Math.PI / 2.0f;
if (angle > (float)Math.PI * 2.0f)
angle -= 2.0f * (float)Math.PI;
}
else
{
pos = sidedef.Line.Start.Position;
pos.z = plane.GetZ(pos);
angle = sidedef.Line.Angle - (float)Math.PI / 2.0f;
if (angle < 0.0f)
angle += 2.0f * (float)Math.PI;
}
SetPosition(pos, level.plane, angle);
}
internal VisualSidedefSlope GetSmartPivotHandle(VisualSidedefSlope starthandle)
{
VisualSidedefSlope handle = starthandle;
List<VisualSidedefSlope> potentialhandles = new List<VisualSidedefSlope>();
int angle = starthandle.sidedef.Line.AngleDeg;
int anglediff = 180;
float distance = 0.0f;
if (angle >= 180) angle -= 180;
List<IVisualEventReceiver> selectedsectors = mode.GetSelectedObjects(true, false, false, false, false);
if (selectedsectors.Count == 0)
{
foreach (VisualSidedefSlope checkhandle in mode.AllSlopeHandles[starthandle.Sidedef.Sector])
if (checkhandle != starthandle && checkhandle.Level == starthandle.Level)
potentialhandles.Add(checkhandle);
}
else
{
HashSet<Sector> sectors = new HashSet<Sector>();
// Debug.WriteLine("\nAll levels:");
foreach(Sector s in General.Map.Map.Sectors)
{
SectorData sd = mode.GetSectorData(s);
// Debug.WriteLine(sd.Floor.GetHashCode());
// Debug.WriteLine(sd.Ceiling.GetHashCode());
}
// Debug.WriteLine("\nLevels of selected sectors:");
foreach (BaseVisualGeometrySector bvgs in selectedsectors)
{
sectors.Add(bvgs.Sector.Sector);
// Debug.WriteLine(bvgs.Level.GetHashCode());
}
// Debug.WriteLine("\nChecking levels:");
foreach (Sector s in sectors)
foreach (VisualSidedefSlope checkhandle in mode.AllSlopeHandles[s])
if(checkhandle != starthandle)
foreach (BaseVisualGeometrySector bvgs in selectedsectors)
{
if (bvgs.Level == checkhandle.Level)
{
potentialhandles.Add(checkhandle);
// Debug.WriteLine(checkhandle.Level.GetHashCode() + " <-- OK!");
}
//else
// Debug.WriteLine(checkhandle.Level.GetHashCode());
}
}
//Debug.WriteLine("\npotential lines:");
//foreach (VisualSidedefSlopeHandle vssh in potentialhandles)
// Debug.WriteLine(vssh.Sidedef.Line);
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in mode.AllSlopeHandles)
{
foreach (VisualSidedefSlope checkhandle in kvp.Value)
checkhandle.SmartPivot = false;
}
List<VisualSidedefSlope> anglediffsortedhandles = potentialhandles.OrderBy(h => Math.Abs(starthandle.NormalizedAngleDeg - h.NormalizedAngleDeg)).ToList();
//Debug.WriteLine("\nSorted by angle diff:");
//foreach (VisualSidedefSlopeHandle vssh in anglediffsortedhandles)
// Debug.WriteLine(vssh.Sidedef.Line + " (" + Math.Abs(starthandle.NormalizedAngleDeg - vssh.NormalizedAngleDeg) + ")");
//Debug.WriteLine("\nSorted by distance:");
//foreach (VisualSidedefSlopeHandle vssh in anglediffsortedhandles.Where(h => h.NormalizedAngleDeg == anglediffsortedhandles[0].NormalizedAngleDeg).OrderByDescending(h => Math.Abs(Vector2D.Distance(h.Sidedef.Line.GetCenterPoint(), starthandle.sidedef.Line.GetCenterPoint()))))
// Debug.WriteLine(vssh.Sidedef.Line + " (" + Math.Abs(Vector2D.Distance(vssh.Sidedef.Line.GetCenterPoint(), starthandle.sidedef.Line.GetCenterPoint())) + ")");
if (anglediffsortedhandles.Count > 0)
{
// handle = anglediffsortedhandles.Where(h => h.NormalizedAngleDeg == anglediffsortedhandles[0].NormalizedAngleDeg).OrderByDescending(h => Math.Abs(Vector2D.Distance(h.Sidedef.Line.GetCenterPoint(), starthandle.sidedef.Line.GetCenterPoint()))).First();
handle = anglediffsortedhandles.Where(h => h.NormalizedAngleDeg == anglediffsortedhandles[0].NormalizedAngleDeg).OrderByDescending(h => Math.Abs(starthandle.Sidedef.Line.Line.GetDistanceToLine(h.sidedef.Line.GetCenterPoint(), false))).First();
}
// Debug.WriteLine("\nDecided on " + handle.Sidedef.Line + "(" + handle.Level.type + ")");
/*
foreach (VisualSidedefSlopeHandle checkhandle in potentialhandles)
{
checkhandle.SmartPivot = false;
if (checkhandle == starthandle) continue;
int checkangle = checkhandle.Sidedef.Line.AngleDeg;
if (checkangle >= 180) checkangle -= 180;
int checkanglediff = Math.Abs(angle - checkangle);
if (checkanglediff <= anglediff)
{
// Compute distance between starthandle and checkhandle
if (handle != null)
{
float checkdistance = Math.Abs(Vector2D.Distance(handle.Sidedef.Line.GetCenterPoint(), checkhandle.Sidedef.Line.GetCenterPoint()));
if (checkdistance > distance)
{
anglediff = checkanglediff;
handle = checkhandle;
distance = checkdistance;
}
}
else
{
anglediff = checkanglediff;
handle = checkhandle;
distance = Math.Abs(Vector2D.Distance(handle.Sidedef.Line.GetCenterPoint(), checkhandle.Sidedef.Line.GetCenterPoint()));
}
}
}
*/
if (handle == starthandle)
return null;
if(handle != null)
handle.SmartPivot = true;
return handle;
}
#endregion
#region ================== Events
public 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);
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in mode.AllSlopeHandles)
{
foreach (VisualSidedefSlope handle in kvp.Value)
{
if (handle.Pivot)
{
pivothandle = handle;
break;
}
}
}
if(pivothandle == null)
{
pivothandle = GetSmartPivotHandle(this);
}
if (pivothandle == null)
return;
mode.CreateUndo("Change slope");
SectorData sd = mode.GetSectorData(sidedef.Sector);
SectorData sdpivot = mode.GetSectorData(level.sector);
Plane originalplane = level.plane;
Plane pivotplane = ((VisualSidedefSlope)pivothandle).Level.plane;
Vector3D p1 = new Vector3D(sidedef.Line.Start.Position, (float)Math.Round(originalplane.GetZ(sidedef.Line.Start.Position)));
Vector3D p2 = new Vector3D(sidedef.Line.End.Position, (float)Math.Round(originalplane.GetZ(sidedef.Line.End.Position)));
Vector3D p3 = new Vector3D(((VisualSidedefSlope)pivothandle).Sidedef.Line.Line.GetCoordinatesAt(0.5f), (float)Math.Round(pivotplane.GetZ(((VisualSidedefSlope)pivothandle).Sidedef.Line.Line.GetCoordinatesAt(0.5f))));
p1 += new Vector3D(0f, 0f, amount);
p2 += new Vector3D(0f, 0f, amount);
Plane plane = new Plane(p1, p2, p3, true);
foreach (SectorLevel l in levels)
{
if (up)
{
l.sector.FloorSlope = plane.Normal;
l.sector.FloorSlopeOffset = plane.Offset;
Vector2D center = new Vector2D(l.sector.BBox.X + l.sector.BBox.Width / 2,
l.sector.BBox.Y + l.sector.BBox.Height / 2);
l.sector.FloorHeight = (int)new Plane(l.sector.FloorSlope, l.sector.FloorSlopeOffset).GetZ(center);
}
else
{
plane = plane.GetInverted();
l.sector.CeilSlope = plane.Normal;
l.sector.CeilSlopeOffset = plane.Offset;
Vector2D center = new Vector2D(l.sector.BBox.X + l.sector.BBox.Width / 2,
l.sector.BBox.Y + l.sector.BBox.Height / 2);
l.sector.CeilHeight = (int)new Plane(l.sector.CeilSlope, l.sector.CeilSlopeOffset).GetZ(center);
}
// Rebuild sector
BaseVisualSector vs;
if (mode.VisualSectorExists(l.sector))
{
vs = (BaseVisualSector)mode.GetVisualSector(l.sector);
}
else
{
vs = mode.CreateBaseVisualSector(l.sector);
}
if (vs != null) vs.UpdateSectorGeometry(true);
}
mode.SetActionResult("Changed slope.");
}
// Select or deselect
public void OnSelectEnd()
{
if (this.selected)
{
this.selected = false;
mode.RemoveSelectedObject(this);
}
else
{
this.selected = true;
mode.AddSelectedObject(this);
}
}
// 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 OnEditEnd() { }
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
}
}