2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
|
|
* This program is released under GNU General Public License
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Namespaces
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Windows.Forms;
|
|
|
|
using CodeImp.DoomBuilder.Map;
|
|
|
|
using CodeImp.DoomBuilder.Rendering;
|
|
|
|
using CodeImp.DoomBuilder.Geometry;
|
2013-03-18 13:52:27 +00:00
|
|
|
using CodeImp.DoomBuilder.Data;
|
2013-04-11 09:27:16 +00:00
|
|
|
using CodeImp.DoomBuilder.Types;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
namespace CodeImp.DoomBuilder.BuilderModes
|
|
|
|
{
|
|
|
|
public abstract class DragGeometryMode : BaseClassicMode
|
|
|
|
{
|
|
|
|
#region ================== Constants
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Variables
|
|
|
|
|
|
|
|
// Mouse position on map where dragging started
|
|
|
|
private Vector2D dragstartmappos;
|
|
|
|
|
2014-07-11 10:46:10 +00:00
|
|
|
//mxd. Offset from nearest grid intersection to dragstartmappos
|
|
|
|
private Vector2D dragstartoffset;
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Item used as reference for snapping to the grid
|
|
|
|
protected Vertex dragitem;
|
|
|
|
private Vector2D dragitemposition;
|
|
|
|
|
|
|
|
// List of old vertex positions
|
|
|
|
private List<Vector2D> oldpositions;
|
2014-01-13 08:06:56 +00:00
|
|
|
private List<Vector2D> oldthingpositions; //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// List of selected items
|
|
|
|
protected ICollection<Vertex> selectedverts;
|
2014-01-13 08:06:56 +00:00
|
|
|
protected ICollection<Thing> selectedthings; //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// List of non-selected items
|
|
|
|
protected ICollection<Vertex> unselectedverts;
|
2014-01-13 08:06:56 +00:00
|
|
|
protected ICollection<Thing> unselectedthings; //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2014-07-18 15:11:37 +00:00
|
|
|
// List of things, which should be moved
|
2024-01-06 14:15:39 +00:00
|
|
|
protected ICollection<Thing> thingstodrag; //mxd
|
2014-07-18 15:11:37 +00:00
|
|
|
|
2013-04-11 09:27:16 +00:00
|
|
|
//mxd. List of sectors
|
2015-04-14 19:43:12 +00:00
|
|
|
private List<Sector> selectedsectors;
|
2013-04-11 09:27:16 +00:00
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// List of unstable lines
|
|
|
|
protected ICollection<Linedef> unstablelines;
|
|
|
|
|
|
|
|
// List of unselected lines
|
|
|
|
protected ICollection<Linedef> snaptolines;
|
|
|
|
|
|
|
|
// Text labels for all unstable lines
|
|
|
|
protected LineLengthLabel[] labels;
|
2015-09-25 13:20:53 +00:00
|
|
|
|
|
|
|
//mxd. Undo description
|
|
|
|
protected string undodescription = "Drag geometry";
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Keep track of view changes
|
|
|
|
private float lastoffsetx;
|
|
|
|
private float lastoffsety;
|
|
|
|
private float lastscale;
|
|
|
|
|
|
|
|
// Options
|
|
|
|
private bool snaptogrid; // SHIFT to toggle
|
|
|
|
private bool snaptonearest; // CTRL to enable
|
2014-07-11 10:46:10 +00:00
|
|
|
private bool snaptogridincrement; //mxd. ALT to toggle
|
2015-07-09 22:32:12 +00:00
|
|
|
private bool snaptocardinaldirection; //mxd. ALT-SHIFT to enable
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Properties
|
|
|
|
|
|
|
|
// Just keep the base mode button checked
|
|
|
|
public override string EditModeButtonName { get { return General.Editing.PreviousStableMode.Name; } }
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
|
|
|
|
// Disposer
|
|
|
|
public override void Dispose()
|
|
|
|
{
|
|
|
|
// Not already disposed?
|
|
|
|
if(!isdisposed)
|
|
|
|
{
|
|
|
|
// Clean up
|
|
|
|
if(labels != null)
|
|
|
|
foreach(LineLengthLabel l in labels) l.Dispose();
|
|
|
|
|
|
|
|
// Done
|
|
|
|
base.Dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Methods
|
|
|
|
|
|
|
|
// Constructor to start dragging immediately
|
|
|
|
protected void StartDrag(Vector2D dragstartmappos)
|
|
|
|
{
|
|
|
|
// Initialize
|
|
|
|
this.dragstartmappos = dragstartmappos;
|
|
|
|
|
|
|
|
Cursor.Current = Cursors.AppStarting;
|
2009-06-11 21:21:20 +00:00
|
|
|
|
|
|
|
// We don't want to record this for undoing while we move the geometry around.
|
|
|
|
// This will be set back to normal when we're done.
|
|
|
|
General.Map.UndoRedo.IgnorePropChanges = true;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2014-01-13 08:06:56 +00:00
|
|
|
// Make list of selected vertices and things
|
2009-04-19 18:07:22 +00:00
|
|
|
selectedverts = General.Map.Map.GetMarkedVertices(true);
|
2014-01-13 08:06:56 +00:00
|
|
|
selectedthings = General.Map.Map.GetSelectedThings(true); //mxd
|
2024-01-06 14:15:39 +00:00
|
|
|
|
|
|
|
// Only set the things to drag if they weren't set by the inherited modes
|
|
|
|
if(thingstodrag == null)
|
|
|
|
thingstodrag = (BuilderPlug.Me.SyncronizeThingEdit ? selectedthings : new List<Thing>()); //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2014-01-13 08:06:56 +00:00
|
|
|
// Make list of non-selected vertices and things
|
|
|
|
// Non-selected vertices will be used for snapping to nearest items
|
2009-04-19 18:07:22 +00:00
|
|
|
unselectedverts = General.Map.Map.GetMarkedVertices(false);
|
2014-01-13 08:06:56 +00:00
|
|
|
unselectedthings = new List<Thing>(); //mxd
|
|
|
|
foreach(Thing t in General.Map.ThingsFilter.VisibleThings) if(!t.Selected) unselectedthings.Add(t);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Get the nearest vertex for snapping
|
|
|
|
dragitem = MapSet.NearestVertex(selectedverts, dragstartmappos);
|
2014-07-11 10:46:10 +00:00
|
|
|
|
|
|
|
//mxd. Get drag offset
|
2014-09-30 19:46:33 +00:00
|
|
|
dragstartoffset = General.Map.Grid.SnappedToGrid(dragitem.Position) - dragitem.Position;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Lines to snap to
|
|
|
|
snaptolines = General.Map.Map.LinedefsFromMarkedVertices(true, false, false);
|
|
|
|
|
|
|
|
// Make old positions list
|
|
|
|
// We will use this as reference to move the vertices, or to move them back on cancel
|
|
|
|
oldpositions = new List<Vector2D>(selectedverts.Count);
|
|
|
|
foreach(Vertex v in selectedverts) oldpositions.Add(v.Position);
|
|
|
|
|
2014-01-13 08:06:56 +00:00
|
|
|
//mxd
|
2014-07-18 15:11:37 +00:00
|
|
|
oldthingpositions = new List<Vector2D>(thingstodrag.Count);
|
|
|
|
foreach(Thing t in thingstodrag) oldthingpositions.Add(t.Position);
|
2014-01-13 08:06:56 +00:00
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Also keep old position of the dragged item
|
|
|
|
dragitemposition = dragitem.Position;
|
|
|
|
|
|
|
|
// Keep view information
|
|
|
|
lastoffsetx = renderer.OffsetX;
|
|
|
|
lastoffsety = renderer.OffsetY;
|
|
|
|
lastscale = renderer.Scale;
|
|
|
|
|
|
|
|
// Make list of unstable lines only
|
|
|
|
// These will have their length displayed during the drag
|
|
|
|
unstablelines = MapSet.UnstableLinedefsFromVertices(selectedverts);
|
|
|
|
|
2013-04-11 09:27:16 +00:00
|
|
|
//mxd. Collect selected sectors
|
2014-12-03 23:15:26 +00:00
|
|
|
if(General.Map.UDMF)
|
|
|
|
{
|
2013-04-11 09:27:16 +00:00
|
|
|
ICollection<Linedef> selectedLines = General.Map.Map.LinedefsFromMarkedVertices(false, true, false);
|
|
|
|
List<Sector> affectedSectors = new List<Sector>();
|
2014-12-03 23:15:26 +00:00
|
|
|
foreach(Linedef l in selectedLines)
|
|
|
|
{
|
2013-04-11 09:27:16 +00:00
|
|
|
if(l.Front != null && l.Front.Sector != null && !affectedSectors.Contains(l.Front.Sector))
|
|
|
|
affectedSectors.Add(l.Front.Sector);
|
|
|
|
if(l.Back != null && l.Back.Sector != null && !affectedSectors.Contains(l.Back.Sector))
|
|
|
|
affectedSectors.Add(l.Back.Sector);
|
|
|
|
}
|
|
|
|
|
2015-04-14 19:43:12 +00:00
|
|
|
selectedsectors = new List<Sector>();
|
2014-12-03 23:15:26 +00:00
|
|
|
foreach(Sector s in affectedSectors)
|
|
|
|
{
|
2013-04-11 09:27:16 +00:00
|
|
|
bool selected = true;
|
2014-12-03 23:15:26 +00:00
|
|
|
foreach(Sidedef side in s.Sidedefs)
|
|
|
|
{
|
|
|
|
if(!selectedLines.Contains(side.Line))
|
|
|
|
{
|
2013-04-11 09:27:16 +00:00
|
|
|
selected = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-14 19:43:12 +00:00
|
|
|
if(selected) selectedsectors.Add(s);
|
2013-04-11 09:27:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Make text labels
|
|
|
|
labels = new LineLengthLabel[unstablelines.Count];
|
|
|
|
int index = 0;
|
|
|
|
foreach(Linedef l in unstablelines)
|
|
|
|
labels[index++] = new LineLengthLabel(l.Start.Position, l.End.Position);
|
|
|
|
|
|
|
|
Cursor.Current = Cursors.Default;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This moves the selected geometry relatively
|
|
|
|
// Returns true when geometry has actually moved
|
2015-07-09 22:32:12 +00:00
|
|
|
private bool MoveGeometryRelative(Vector2D offset, bool snapgrid, bool snapgridincrement, bool snapnearest, bool snapcardinal)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2015-07-09 22:32:12 +00:00
|
|
|
//mxd. If snap to cardinal directions is enabled, modify the offset
|
|
|
|
if(snapcardinal)
|
|
|
|
{
|
2020-05-21 12:20:02 +00:00
|
|
|
double angle = Angle2D.DegToRad((General.ClampAngle((int)Angle2D.RadToDeg(offset.GetAngle()) + 44)) / 90 * 90);
|
2015-07-09 22:32:12 +00:00
|
|
|
offset = new Vector2D(0, -offset.GetLength()).GetRotated(angle);
|
Fixed, Draw Lines/Rectangle/Circle/Curve modes: line length labels displayed incorrect length.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: line length labels are now displayed the same way as in Draw modes.
Changed, Drag Linedefs/Vertices/Sectors/Things modes: "lock movement to cardinal directions" mode (Alt-Shift-Drag) now locks movement in 4 directions instead of 8 and doesn't snap map elements to nearest grid intersections when they are not aligned to it.
Added, Visual mode, GZDoom, DECORATE: FORCEXYBILLBOARD flag is now supported.
Added, Visual mode, GLOOME, DECORATE: FLOORSPRITE, CEILSPRITE, WALLSPRITE, ROLLSPRITE and STICKTOPLANE flags are now supported (implementation is somewhat broken ATM and probably doesn't work the same way as in GLOOME, because Windows build with most these features is nowhere to be found...).
Fixed, Visual mode: in some cases Thing brightness was calculated incorrectly.
Updated ZDoom_DECORATE.cfg.
2015-08-25 22:05:14 +00:00
|
|
|
snapgridincrement = true; // We don't want to move the geometry away from the cardinal directions
|
2015-07-09 22:32:12 +00:00
|
|
|
}
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
Vector2D oldpos = dragitem.Position;
|
|
|
|
Vector2D anchorpos = dragitemposition + offset;
|
2010-08-13 18:32:21 +00:00
|
|
|
Vector2D tl, br;
|
2010-01-02 22:06:40 +00:00
|
|
|
|
|
|
|
// don't move if the offset contains invalid data
|
2015-12-27 21:54:50 +00:00
|
|
|
if(!offset.IsFinite()) return false;
|
2010-08-13 18:32:21 +00:00
|
|
|
|
|
|
|
// Find the outmost vertices
|
|
|
|
tl = br = oldpositions[0];
|
2015-12-27 21:54:50 +00:00
|
|
|
for(int i = 0; i < oldpositions.Count; i++)
|
2010-08-13 18:32:21 +00:00
|
|
|
{
|
2015-12-27 21:54:50 +00:00
|
|
|
if(oldpositions[i].x < tl.x) tl.x = (int)oldpositions[i].x;
|
|
|
|
if(oldpositions[i].x > br.x) br.x = (int)oldpositions[i].x;
|
|
|
|
if(oldpositions[i].y > tl.y) tl.y = (int)oldpositions[i].y;
|
|
|
|
if(oldpositions[i].y < br.y) br.y = (int)oldpositions[i].y;
|
2010-08-13 18:32:21 +00:00
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Snap to nearest?
|
|
|
|
if(snapnearest)
|
|
|
|
{
|
|
|
|
// Find nearest unselected vertex within range
|
2009-05-20 15:03:08 +00:00
|
|
|
Vertex nv = MapSet.NearestVertexSquareRange(unselectedverts, anchorpos, BuilderPlug.Me.StitchRange / renderer.Scale);
|
2009-04-19 18:07:22 +00:00
|
|
|
if(nv != null)
|
|
|
|
{
|
|
|
|
// Move the dragged item
|
|
|
|
dragitem.Move(nv.Position);
|
|
|
|
|
|
|
|
// Adjust the offset
|
|
|
|
offset = nv.Position - dragitemposition;
|
|
|
|
|
|
|
|
// Do not snap to grid!
|
|
|
|
snapgrid = false;
|
2014-07-11 10:46:10 +00:00
|
|
|
snaptogridincrement = false; //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Find the nearest unselected line within range
|
2009-05-20 15:03:08 +00:00
|
|
|
Linedef nl = MapSet.NearestLinedefRange(snaptolines, anchorpos, BuilderPlug.Me.StitchRange / renderer.Scale);
|
2009-04-19 18:07:22 +00:00
|
|
|
if(nl != null)
|
|
|
|
{
|
|
|
|
// Snap to grid?
|
2014-07-18 15:11:37 +00:00
|
|
|
if(snapgrid || snapgridincrement)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
|
|
|
// Get grid intersection coordinates
|
2019-01-14 18:07:08 +00:00
|
|
|
List<Vector2D> coords = nl.GetGridIntersections(snapgridincrement ? dragstartoffset : new Vector2D(),
|
|
|
|
General.Map.Grid.GridRotate, General.Map.Grid.GridOriginX, General.Map.Grid.GridOriginY);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2014-09-22 19:01:51 +00:00
|
|
|
// mxd. Do the rest only if we actually have some coordinates
|
2015-12-28 15:01:53 +00:00
|
|
|
if(coords.Count > 0)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2014-09-22 19:01:51 +00:00
|
|
|
// Find nearest grid intersection
|
2020-05-21 12:20:02 +00:00
|
|
|
double found_distance = double.MaxValue;
|
2014-09-22 19:01:51 +00:00
|
|
|
Vector2D found_coord = new Vector2D();
|
|
|
|
|
2015-12-28 15:01:53 +00:00
|
|
|
foreach(Vector2D v in coords)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2014-09-22 19:01:51 +00:00
|
|
|
Vector2D delta = anchorpos - v;
|
2015-12-28 15:01:53 +00:00
|
|
|
if(delta.GetLengthSq() < found_distance)
|
2014-09-22 19:01:51 +00:00
|
|
|
{
|
|
|
|
found_distance = delta.GetLengthSq();
|
|
|
|
found_coord = v;
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
2014-09-22 19:01:51 +00:00
|
|
|
// Move the dragged item
|
|
|
|
dragitem.Move(found_coord);
|
|
|
|
|
|
|
|
// Align to line here
|
|
|
|
offset = found_coord - dragitemposition;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2014-09-22 19:01:51 +00:00
|
|
|
// Do not snap to grid anymore
|
|
|
|
snapgrid = false;
|
|
|
|
snapgridincrement = false; //mxd
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Move the dragged item
|
|
|
|
dragitem.Move(nl.NearestOnLine(anchorpos));
|
|
|
|
|
|
|
|
// Align to line here
|
|
|
|
offset = nl.NearestOnLine(anchorpos) - dragitemposition;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 10:46:10 +00:00
|
|
|
// Snap to grid or grid increment?
|
|
|
|
if(snapgrid || snapgridincrement)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
|
|
|
// Move the dragged item
|
|
|
|
dragitem.Move(anchorpos);
|
|
|
|
|
2014-07-11 10:46:10 +00:00
|
|
|
// Snap item to grid increment
|
|
|
|
if(snapgridincrement) //mxd
|
|
|
|
{
|
2014-09-30 19:46:33 +00:00
|
|
|
dragitem.Move(General.Map.Grid.SnappedToGrid(dragitem.Position) - dragstartoffset);
|
2014-07-11 10:46:10 +00:00
|
|
|
}
|
|
|
|
else // Or to the grid itself
|
|
|
|
{
|
|
|
|
dragitem.SnapToGrid();
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Adjust the offset
|
|
|
|
offset += dragitem.Position - anchorpos;
|
|
|
|
}
|
|
|
|
|
2010-08-13 18:32:21 +00:00
|
|
|
// Make sure the offset is inside the map boundaries
|
2015-12-28 15:01:53 +00:00
|
|
|
if(offset.x + tl.x < General.Map.Config.LeftBoundary) offset.x = General.Map.Config.LeftBoundary - tl.x;
|
|
|
|
if(offset.x + br.x > General.Map.Config.RightBoundary) offset.x = General.Map.Config.RightBoundary - br.x;
|
|
|
|
if(offset.y + tl.y > General.Map.Config.TopBoundary) offset.y = General.Map.Config.TopBoundary - tl.y;
|
|
|
|
if(offset.y + br.y < General.Map.Config.BottomBoundary) offset.y = General.Map.Config.BottomBoundary - br.y;
|
2010-08-13 18:32:21 +00:00
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Drag item moved?
|
2014-07-11 10:46:10 +00:00
|
|
|
if((!snapgrid && !snapgridincrement) || (dragitem.Position != oldpos))
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2010-08-13 18:32:21 +00:00
|
|
|
int i = 0;
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Move selected geometry
|
|
|
|
foreach(Vertex v in selectedverts)
|
|
|
|
{
|
2014-07-11 10:46:10 +00:00
|
|
|
// Move vertex from old position relative to the mouse position change since drag start
|
|
|
|
v.Move(oldpositions[i++] + offset);
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
2014-01-13 08:06:56 +00:00
|
|
|
//mxd. Move selected things
|
|
|
|
i = 0;
|
2014-07-18 15:11:37 +00:00
|
|
|
foreach(Thing t in thingstodrag)
|
2014-07-11 10:46:10 +00:00
|
|
|
{
|
2014-01-13 08:06:56 +00:00
|
|
|
t.Move(oldthingpositions[i++] + offset);
|
|
|
|
}
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Update labels
|
|
|
|
int index = 0;
|
|
|
|
foreach(Linedef l in unstablelines)
|
|
|
|
labels[index++].Move(l.Start.Position, l.End.Position);
|
|
|
|
|
|
|
|
// Moved
|
|
|
|
return true;
|
|
|
|
}
|
2014-07-11 10:46:10 +00:00
|
|
|
|
|
|
|
// No changes
|
|
|
|
return false;
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
2013-03-18 13:52:27 +00:00
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Cancelled
|
|
|
|
public override void OnCancel()
|
|
|
|
{
|
|
|
|
// Move geometry back to original position
|
2015-07-09 22:32:12 +00:00
|
|
|
MoveGeometryRelative(new Vector2D(0f, 0f), false, false, false, false);
|
2009-06-11 21:21:20 +00:00
|
|
|
|
|
|
|
// Resume normal undo/redo recording
|
|
|
|
General.Map.UndoRedo.IgnorePropChanges = false;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// If only a single vertex was selected, deselect it now
|
|
|
|
if(selectedverts.Count == 1) General.Map.Map.ClearSelectedVertices();
|
|
|
|
|
|
|
|
// Update cached values
|
|
|
|
General.Map.Map.Update();
|
|
|
|
|
|
|
|
// Cancel base class
|
|
|
|
base.OnCancel();
|
|
|
|
|
|
|
|
// Return to vertices mode
|
|
|
|
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mode engages
|
|
|
|
public override void OnEngage()
|
|
|
|
{
|
|
|
|
base.OnEngage();
|
|
|
|
EnableAutoPanning();
|
|
|
|
renderer.SetPresentation(Presentation.Standard);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disenagaging
|
|
|
|
public override void OnDisengage()
|
|
|
|
{
|
|
|
|
base.OnDisengage();
|
|
|
|
DisableAutoPanning();
|
|
|
|
|
|
|
|
// When not cancelled
|
|
|
|
if(!cancelled)
|
|
|
|
{
|
|
|
|
Cursor.Current = Cursors.AppStarting;
|
|
|
|
|
|
|
|
// Move geometry back to original position
|
2015-07-09 22:32:12 +00:00
|
|
|
MoveGeometryRelative(new Vector2D(0f, 0f), false, false, false, false);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2009-06-11 21:21:20 +00:00
|
|
|
// Resume normal undo/redo recording
|
|
|
|
General.Map.UndoRedo.IgnorePropChanges = false;
|
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// Make undo for the dragging
|
2015-09-25 13:20:53 +00:00
|
|
|
General.Map.UndoRedo.CreateUndo(undodescription);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Move selected geometry to final position
|
2015-07-09 22:32:12 +00:00
|
|
|
MoveGeometryRelative(mousemappos - dragstartmappos, snaptogrid, snaptogridincrement, snaptonearest, snaptocardinaldirection);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Stitch geometry
|
2016-07-02 22:27:20 +00:00
|
|
|
if(snaptonearest) General.Map.Map.StitchGeometry(General.Settings.MergeGeometryMode);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Snap to map format accuracy
|
|
|
|
General.Map.Map.SnapAllToAccuracy();
|
2013-04-11 09:27:16 +00:00
|
|
|
|
2015-04-14 19:43:12 +00:00
|
|
|
//mxd. Update floor/ceiling texture offsets and slopes?
|
2020-05-03 15:25:07 +00:00
|
|
|
if (General.Map.UDMF)
|
2014-12-03 23:15:26 +00:00
|
|
|
{
|
2015-04-15 15:01:40 +00:00
|
|
|
Vector2D offset = dragitem.Position - dragitemposition;
|
2016-05-29 00:38:55 +00:00
|
|
|
|
|
|
|
// Sectors may've been created/removed when applying dragging...
|
|
|
|
HashSet<Sector> draggedsectors = new HashSet<Sector>(General.Map.Map.GetMarkedSectors(true));
|
2020-05-03 15:25:07 +00:00
|
|
|
foreach (Sector ss in selectedsectors) if (!ss.IsDisposed) draggedsectors.Add(ss);
|
|
|
|
|
|
|
|
// Sectors that have to be updated. They contain the dragged sectors, but also 3D floor control sectors
|
|
|
|
HashSet<Sector> updatesectors = new HashSet<Sector>(draggedsectors);
|
|
|
|
|
2024-05-27 15:08:03 +00:00
|
|
|
// Keep track of control sectors in general, and control sectors relevant to other dragged sectors
|
|
|
|
HashSet<Sector> controlsectors = new HashSet<Sector>();
|
|
|
|
HashSet<Sector> addcontrolsectors = new HashSet<Sector>();
|
|
|
|
|
2020-05-03 15:25:07 +00:00
|
|
|
// Check if the dragged sectors are referenced as 3D floors, and add the control sectors to the list of
|
|
|
|
// sectors that need updating
|
|
|
|
foreach (Linedef ld in General.Map.Map.Linedefs)
|
|
|
|
{
|
2023-09-14 20:17:57 +00:00
|
|
|
if (ld.Action < 100 && ld.Action >= 300) // SRB2 FOF types
|
2020-05-03 15:25:07 +00:00
|
|
|
continue;
|
|
|
|
|
2024-05-27 15:08:03 +00:00
|
|
|
if (ld.Args[0] == 0) // First argument of the action is the sector tag. 0 is not a valid value
|
|
|
|
continue;
|
|
|
|
|
|
|
|
controlsectors.Add(ld.Front.Sector);
|
|
|
|
|
2020-05-03 15:25:07 +00:00
|
|
|
foreach (Sector s in draggedsectors)
|
|
|
|
{
|
2024-05-27 15:08:03 +00:00
|
|
|
if (!s.Tags.Contains(ld.Args[0]))
|
2020-05-03 15:25:07 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
updatesectors.Add(ld.Front.Sector);
|
2024-05-27 15:08:03 +00:00
|
|
|
addcontrolsectors.Add(ld.Front.Sector);
|
2020-05-03 15:25:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-14 19:43:12 +00:00
|
|
|
// Update floor/ceiling texture offsets?
|
2020-05-03 15:25:07 +00:00
|
|
|
foreach (Sector s in updatesectors)
|
2014-12-03 23:15:26 +00:00
|
|
|
{
|
2020-05-03 15:25:07 +00:00
|
|
|
bool updateoffsets = (draggedsectors.Contains(s) && BuilderPlug.Me.LockSectorTextureOffsetsWhileDragging) || (!draggedsectors.Contains(s) && BuilderPlug.Me.Lock3DFloorSectorTextureOffsetsWhileDragging);
|
2024-05-27 15:08:03 +00:00
|
|
|
bool updateslopes = !((controlsectors.Contains(s) ^ addcontrolsectors.Contains(s)) && draggedsectors.Contains(s));
|
2016-05-29 00:38:55 +00:00
|
|
|
|
2020-05-03 15:25:07 +00:00
|
|
|
// Update texture offsets
|
|
|
|
if (updateoffsets)
|
2014-12-03 23:15:26 +00:00
|
|
|
{
|
2015-04-14 19:43:12 +00:00
|
|
|
s.Fields.BeforeFieldsChange();
|
2013-04-11 09:27:16 +00:00
|
|
|
|
2015-04-14 19:43:12 +00:00
|
|
|
// Update ceiling offset
|
2020-05-03 15:25:07 +00:00
|
|
|
if (s.LongCeilTexture != MapSet.EmptyLongName)
|
2014-12-03 23:15:26 +00:00
|
|
|
{
|
2015-04-14 19:43:12 +00:00
|
|
|
ImageData texture = General.Map.Data.GetFlatImage(s.CeilTexture);
|
2013-04-11 09:27:16 +00:00
|
|
|
|
2020-05-03 15:25:07 +00:00
|
|
|
if (texture != null)
|
2014-12-03 23:15:26 +00:00
|
|
|
{
|
2020-05-22 19:39:18 +00:00
|
|
|
double scalex = s.Fields.GetValue("xscaleceiling", 1.0);
|
|
|
|
double scaley = s.Fields.GetValue("yscaleceiling", 1.0);
|
2015-04-14 19:43:12 +00:00
|
|
|
|
2020-05-03 15:25:07 +00:00
|
|
|
if (scalex != 0 && scaley != 0)
|
2015-04-14 19:43:12 +00:00
|
|
|
{
|
2020-05-22 19:39:18 +00:00
|
|
|
Vector2D ceiloffset = new Vector2D(-offset.x, offset.y).GetRotated(-Angle2D.DegToRad((int)s.Fields.GetValue("rotationceiling", 0.0)));
|
|
|
|
ceiloffset.x += s.Fields.GetValue("xpanningceiling", 0.0);
|
|
|
|
ceiloffset.y += s.Fields.GetValue("ypanningceiling", 0.0);
|
2015-04-14 19:43:12 +00:00
|
|
|
|
|
|
|
int texturewidth = (int)Math.Round(texture.Width / scalex);
|
|
|
|
int textureheight = (int)Math.Round(texture.Height / scaley);
|
|
|
|
|
2021-11-28 14:52:09 +00:00
|
|
|
if (!s.Fields.ContainsKey("xpanningceiling")) s.Fields.Add("xpanningceiling", new UniValue(UniversalType.Float, ceiloffset.x % texturewidth));
|
|
|
|
else s.Fields["xpanningceiling"].Value = ceiloffset.x % texturewidth;
|
2015-04-14 19:43:12 +00:00
|
|
|
|
2021-11-28 14:52:09 +00:00
|
|
|
if (!s.Fields.ContainsKey("ypanningceiling")) s.Fields.Add("ypanningceiling", new UniValue(UniversalType.Float, ceiloffset.y % textureheight));
|
|
|
|
else s.Fields["ypanningceiling"].Value = ceiloffset.y % textureheight;
|
2015-04-14 19:43:12 +00:00
|
|
|
}
|
2013-04-11 09:27:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-14 19:43:12 +00:00
|
|
|
// Update floor offset
|
2020-05-03 15:25:07 +00:00
|
|
|
if (s.LongFloorTexture != MapSet.EmptyLongName)
|
2014-12-03 23:15:26 +00:00
|
|
|
{
|
2015-04-14 19:43:12 +00:00
|
|
|
ImageData texture = General.Map.Data.GetFlatImage(s.FloorTexture);
|
2020-05-03 15:25:07 +00:00
|
|
|
if (texture != null)
|
2014-12-03 23:15:26 +00:00
|
|
|
{
|
2020-05-22 19:39:18 +00:00
|
|
|
double scalex = s.Fields.GetValue("xscalefloor", 1.0);
|
|
|
|
double scaley = s.Fields.GetValue("yscalefloor", 1.0);
|
2015-04-14 19:43:12 +00:00
|
|
|
|
2020-05-03 15:25:07 +00:00
|
|
|
if (scalex != 0 && scaley != 0)
|
2015-04-14 19:43:12 +00:00
|
|
|
{
|
2020-05-22 19:39:18 +00:00
|
|
|
Vector2D flooroffset = new Vector2D(-offset.x, offset.y).GetRotated(-Angle2D.DegToRad((int)s.Fields.GetValue("rotationfloor", 0.0)));
|
|
|
|
flooroffset.x += s.Fields.GetValue("xpanningfloor", 0.0);
|
|
|
|
flooroffset.y += s.Fields.GetValue("ypanningfloor", 0.0);
|
2015-04-14 19:43:12 +00:00
|
|
|
|
|
|
|
int texturewidth = (int)Math.Round(texture.Width / scalex);
|
|
|
|
int textureheight = (int)Math.Round(texture.Height / scaley);
|
|
|
|
|
2021-11-28 14:52:09 +00:00
|
|
|
if (!s.Fields.ContainsKey("xpanningfloor")) s.Fields.Add("xpanningfloor", new UniValue(UniversalType.Float, flooroffset.x % texturewidth));
|
|
|
|
else s.Fields["xpanningfloor"].Value = flooroffset.x % texturewidth;
|
2015-04-14 19:43:12 +00:00
|
|
|
|
2021-11-28 14:52:09 +00:00
|
|
|
if (!s.Fields.ContainsKey("ypanningfloor")) s.Fields.Add("ypanningfloor", new UniValue(UniversalType.Float, flooroffset.y % textureheight));
|
|
|
|
else s.Fields["ypanningfloor"].Value = flooroffset.y % textureheight;
|
2015-04-14 19:43:12 +00:00
|
|
|
}
|
2013-04-11 09:27:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-05-27 15:08:03 +00:00
|
|
|
|
2024-05-24 17:58:53 +00:00
|
|
|
if (updateslopes)
|
2015-04-14 19:43:12 +00:00
|
|
|
{
|
2024-05-24 17:58:53 +00:00
|
|
|
// Update floor slope?
|
|
|
|
if (s.FloorSlope.GetLengthSq() > 0 && !double.IsNaN(s.FloorSlopeOffset / s.FloorSlope.z))
|
|
|
|
{
|
|
|
|
Plane floor = new Plane(s.FloorSlope, s.FloorSlopeOffset);
|
|
|
|
Vector2D center = new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2);
|
|
|
|
s.FloorSlopeOffset = -Vector3D.DotProduct(s.FloorSlope, new Vector3D(center + offset, floor.GetZ(center)));
|
|
|
|
}
|
2015-04-14 19:43:12 +00:00
|
|
|
|
2024-05-24 17:58:53 +00:00
|
|
|
// Update ceiling slope?
|
|
|
|
if (s.CeilSlope.GetLengthSq() > 0 && !double.IsNaN(s.CeilSlopeOffset / s.CeilSlope.z))
|
|
|
|
{
|
|
|
|
Plane ceiling = new Plane(s.CeilSlope, s.CeilSlopeOffset);
|
|
|
|
Vector2D center = new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2);
|
|
|
|
s.CeilSlopeOffset = -Vector3D.DotProduct(s.CeilSlope, new Vector3D(center + offset, ceiling.GetZ(center)));
|
|
|
|
}
|
2015-04-14 19:43:12 +00:00
|
|
|
}
|
|
|
|
}
|
2016-05-18 20:31:40 +00:00
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2016-05-18 20:31:40 +00:00
|
|
|
// Update cached values
|
|
|
|
General.Map.Map.Update();
|
2016-05-16 14:04:04 +00:00
|
|
|
|
2016-05-18 20:31:40 +00:00
|
|
|
//mxd. Let the plugins know
|
|
|
|
General.Editing.AcceptMode();
|
2016-05-16 14:04:04 +00:00
|
|
|
|
2016-05-18 20:31:40 +00:00
|
|
|
// Done
|
|
|
|
Cursor.Current = Cursors.Default;
|
|
|
|
General.Map.IsChanged = true;
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This checks if the view offset/zoom changed and updates the check
|
|
|
|
protected bool CheckViewChanged()
|
|
|
|
{
|
|
|
|
// View changed?
|
2013-12-23 12:02:58 +00:00
|
|
|
bool viewchanged = (renderer.OffsetX != lastoffsetx || renderer.OffsetY != lastoffsety || renderer.Scale != lastscale);
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Keep view information
|
|
|
|
lastoffsetx = renderer.OffsetX;
|
|
|
|
lastoffsety = renderer.OffsetY;
|
|
|
|
lastscale = renderer.Scale;
|
|
|
|
|
|
|
|
// Return result
|
|
|
|
return viewchanged;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This updates the dragging
|
|
|
|
private void Update()
|
|
|
|
{
|
2015-07-09 22:32:12 +00:00
|
|
|
snaptocardinaldirection = (General.Interface.ShiftState && General.Interface.AltState); //mxd
|
|
|
|
snaptogrid = (snaptocardinaldirection || General.Interface.ShiftState ^ General.Interface.SnapToGrid);
|
2009-04-19 18:07:22 +00:00
|
|
|
snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
|
2015-07-09 22:32:12 +00:00
|
|
|
snaptogridincrement = (!snaptocardinaldirection && General.Interface.AltState); //mxd
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// Move selected geometry
|
2015-07-09 22:32:12 +00:00
|
|
|
if(MoveGeometryRelative(mousemappos - dragstartmappos, snaptogrid, snaptogridincrement, snaptonearest, snaptocardinaldirection))
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
|
|
|
// Update cached values
|
|
|
|
General.Map.Map.Update(true, false);
|
|
|
|
|
|
|
|
// Redraw
|
2009-06-11 21:21:20 +00:00
|
|
|
UpdateRedraw();
|
|
|
|
renderer.Present();
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-11 21:21:20 +00:00
|
|
|
// This redraws only the required things
|
2014-01-23 13:36:51 +00:00
|
|
|
protected virtual void UpdateRedraw() { }
|
2013-12-23 12:02:58 +00:00
|
|
|
|
2009-04-19 18:07:22 +00:00
|
|
|
// When edit button is released
|
|
|
|
protected override void OnEditEnd()
|
|
|
|
{
|
|
|
|
// Just return to base mode, Disengage will be called automatically.
|
|
|
|
General.Editing.ChangeMode(General.Editing.PreviousStableMode.Name);
|
|
|
|
|
|
|
|
base.OnEditEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mouse moving
|
|
|
|
public override void OnMouseMove(MouseEventArgs e)
|
|
|
|
{
|
|
|
|
base.OnMouseMove(e);
|
Added, Visual mode, GLDEFS, GLOOME: subtractive glow is now supported.
Changed, Visual mode: changed thing fog calculation logic. Should be closer to GZDoom now.
Fixed, GLDEFS parser: "height" texture parameter was not treated as optional.
Fixed, text lump parsers: in some cases incorrect line number was displayed in error and warning messages.
Fixed, Visual mode: glow effect was not applied to sectors with 3 sidedefs.
Fixed, Visual mode: in some cases glow effect was not updated when replacing textures.
Fixed, general interface: "Full Brightness" button state was not updated during map loading.
Fixed, Drag Linedefs/Vertices/Sectors/Things modes: positions of line length labels were not updated while panning the view.
Cosmetic: added a bunch of new icons.
Cosmetic: changed Visual mode crosshair.
2015-08-27 20:46:49 +00:00
|
|
|
|
|
|
|
//mxd. Skip most of update jazz while panning
|
|
|
|
if(panning)
|
|
|
|
{
|
|
|
|
// Update labels
|
|
|
|
int index = 0;
|
2015-12-28 15:01:53 +00:00
|
|
|
foreach(Linedef l in unstablelines)
|
Added, Visual mode, GLDEFS, GLOOME: subtractive glow is now supported.
Changed, Visual mode: changed thing fog calculation logic. Should be closer to GZDoom now.
Fixed, GLDEFS parser: "height" texture parameter was not treated as optional.
Fixed, text lump parsers: in some cases incorrect line number was displayed in error and warning messages.
Fixed, Visual mode: glow effect was not applied to sectors with 3 sidedefs.
Fixed, Visual mode: in some cases glow effect was not updated when replacing textures.
Fixed, general interface: "Full Brightness" button state was not updated during map loading.
Fixed, Drag Linedefs/Vertices/Sectors/Things modes: positions of line length labels were not updated while panning the view.
Cosmetic: added a bunch of new icons.
Cosmetic: changed Visual mode crosshair.
2015-08-27 20:46:49 +00:00
|
|
|
labels[index++].Move(l.Start.Position, l.End.Position);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Update();
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
// When a key is released
|
|
|
|
public override void OnKeyUp(KeyEventArgs e)
|
|
|
|
{
|
|
|
|
base.OnKeyUp(e);
|
|
|
|
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
|
2014-07-11 10:46:10 +00:00
|
|
|
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge)) ||
|
2015-07-09 22:32:12 +00:00
|
|
|
(snaptogridincrement != General.Interface.AltState) ||
|
|
|
|
(snaptocardinaldirection != (General.Interface.AltState && General.Interface.ShiftState))) Update();
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// When a key is pressed
|
|
|
|
public override void OnKeyDown(KeyEventArgs e)
|
|
|
|
{
|
|
|
|
base.OnKeyDown(e);
|
|
|
|
if((snaptogrid != (General.Interface.ShiftState ^ General.Interface.SnapToGrid)) ||
|
2014-07-11 10:46:10 +00:00
|
|
|
(snaptonearest != (General.Interface.CtrlState ^ General.Interface.AutoMerge)) ||
|
2015-07-09 22:32:12 +00:00
|
|
|
(snaptogridincrement != General.Interface.AltState) ||
|
|
|
|
(snaptocardinaldirection != (General.Interface.AltState && General.Interface.ShiftState))) Update();
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|