Newer
Older
#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.BuilderModes.Interface;
using CodeImp.DoomBuilder.Windows;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Actions;
using CodeImp.DoomBuilder.VisualModes;
using CodeImp.DoomBuilder.Config;
using CodeImp.DoomBuilder.Types;
using CodeImp.DoomBuilder.Data;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "Visual Mode",
SwitchAction = "gzdbvisualmode", // Action name used to switch to this mode
ButtonImage = "VisualMode.png", // Image resource name for the button
ButtonOrder = 1, // Position of the button (lower is more to the left)
ButtonGroup = "001_visual",
UseByDefault = true)]
public class BaseVisualMode : VisualMode
{
#region ================== Constants
// Object picking
private const long PICK_INTERVAL = 80;
private const long PICK_INTERVAL_PAINT_SELECT = 10; // biwa
// Gravity
private const float GRAVITY = -0.06f;
#endregion
#region ================== Variables
// Gravity
private Vector3D gravity;
biwa
committed
private double cameraflooroffset = 41.0; // same as in doom
private double cameraceilingoffset = 10.0;
// Object picking
private VisualPickResult target;
private long lastpicktime;
private readonly Timer selectioninfoupdatetimer; //mxd
// This keeps extra element info
private Dictionary<Sector, SectorData> sectordata;
private Dictionary<Thing, ThingData> thingdata;
private Dictionary<Vertex, VertexData> vertexdata; //mxd
//private Dictionary<Thing, EffectDynamicLight> lightdata; //mxd
// This is true when a selection was made because the action is performed
// on an object that was not selected. In this case the previous selection
// is cleared and the targeted object is temporarely selected to perform
// the action on. After the action is completed, the object is deselected.
// We keep these to determine if we need to make a new undo level
private bool selectionchanged;
private int lastundogroup;
private VisualActionResult actionresult;
private bool undocreated;
// List of selected objects when an action is performed
private List<IVisualEventReceiver> selectedobjects;
//mxd. Used in Cut/PasteSelection actions
private readonly List<ThingCopyData> copybuffer;
private Type lasthighlighttype;
// biwa. Info for paint selection
protected bool paintselectpressed;
protected Type paintselecttype = null;
protected IVisualPickable highlighted; // biwa
//mxd. Moved here from Tools
private struct SidedefAlignJob
{
public Sidedef sidedef;
public double offsetx;
public double scaleX; //mxd
public double scaleY; //mxd
private Sidedef controlside; //mxd
public Sidedef controlSide
{
get
{
return controlside;
}
set
{
controlside = value;
ceilingheight = (controlside.Index != sidedef.Index && controlside.Line.Args[1] == 0 ? controlside.Sector.FloorHeight : controlside.Sector.CeilHeight);
}
}
private int ceilingheight; //mxd
public int ceilingHeight { get { return ceilingheight; } } //mxd
// When this is true, the previous sidedef was on the left of
// this one and the texture X offset of this sidedef can be set
// directly. When this is false, the length of this sidedef
// must be subtracted from the X offset first.
public bool forward;
}
#endregion
#region ================== Properties
public override object HighlightedObject
{
get
{
// Geometry picked?
VisualGeometry vg = target.picked as VisualGeometry;
if(vg != null)
if(vg.Sidedef != null) return vg.Sidedef;
if(vg.Sector != null) return vg.Sector;
}
// Thing picked?
VisualThing vt = target.picked as VisualThing;
if(vt != null) return vt.Thing;
public object HighlightedTarget { get { return target.picked; } } //mxd
public bool UseSelectionFromClassicMode { get { return useSelectionFromClassicMode; } } //mxd
new public IRenderer3D Renderer { get { return renderer; } }
public bool IsSingleSelection { get { return singleselection; } }
public bool SelectionChanged { get { return selectionchanged; } set { selectionchanged |= value; } }
public bool PaintSelectPressed { get { return paintselectpressed; } } // biwa
public Type PaintSelectType { get { return paintselecttype; } set { paintselecttype = value; } } // biwa
public IVisualPickable Highlighted { get { return highlighted; } } // biwa
#endregion
#region ================== Constructor / Disposer
// Constructor
public BaseVisualMode()
{
// Initialize
this.gravity = new Vector3D(0.0f, 0.0f, 0.0f);
codeimp
committed
this.selectedobjects = new List<IVisualEventReceiver>();
this.copybuffer = new List<ThingCopyData>();
this.selectioninfoupdatetimer = new Timer();
selectioninfoupdatetimer.Interval = 100;
selectioninfoupdatetimer.Tick += SelectioninfoupdatetimerOnTick;
// We have no destructor
GC.SuppressFinalize(this);
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
selectioninfoupdatetimer.Dispose(); //mxd
// Done
base.Dispose();
}
}
#endregion
#region ================== Methods
codeimp
committed
// This calculates brightness level
codeimp
committed
internal int CalculateBrightness(int level)
codeimp
committed
{
codeimp
committed
return renderer.CalculateBrightness(level);
codeimp
committed
}
MaxED
committed
//mxd. This calculates brightness level with doom-style shading
internal int CalculateBrightness(int level, Sidedef sd)
{
return renderer.CalculateBrightness(level, sd);
}
codeimp
committed
codeimp
committed
// This adds a selected object
internal void AddSelectedObject(IVisualEventReceiver obj)
{
selectedobjects.Add(obj);
selectionchanged = true;
selectioninfoupdatetimer.Start(); //mxd
codeimp
committed
}
// This removes a selected object
internal void RemoveSelectedObject(IVisualEventReceiver obj)
{
selectedobjects.Remove(obj);
selectionchanged = true;
selectioninfoupdatetimer.Start(); //mxd
codeimp
committed
}
// This is called before an action is performed
public void PreAction(int multiselectionundogroup)
actionresult = new VisualActionResult();
PickTargetUnlocked();
// If the action is not performed on a selected object, clear the
// current selection and make a temporary selection for the target.
if ((target.picked != null) && !target.picked.Selected && (BuilderPlug.Me.VisualModeClearSelection || (selectedobjects.Count == 0)))
// Single object, no selection
singleselection = true;
// Only clear the selection if anything is selected, since it can be very time consuming on huge maps
if(BuilderPlug.Me.VisualModeClearSelection && selectedobjects.Count > 0)
ClearSelection();
undocreated = false;
singleselection = false;
// Check if we should make a new undo level
// We don't want to do this if this is the same action with the same
// selection and the action wants to group the undo levels
if((lastundogroup != multiselectionundogroup) || (lastundogroup == UndoGroup.None) ||
(multiselectionundogroup == UndoGroup.None) || selectionchanged)
{
// We want to create a new undo level, but not just yet
lastundogroup = multiselectionundogroup;
undocreated = false;
}
else
// We don't want to make a new undo level (changes will be combined)
undocreated = true;
}
codeimp
committed
// Called before an action is performed. This does not make an undo level
private void PreActionNoChange()
{
actionresult = new VisualActionResult();
singleselection = false;
undocreated = false;
// This is called after an action is performed
if(!string.IsNullOrEmpty(actionresult.displaystatus))
General.Interface.DisplayStatus(StatusType.Action, actionresult.displaystatus);
ZZYZX
committed
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
ZZYZX
committed
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
foreach(VisualFloor vf in bvs.ExtraFloors) vf.Changed = false;
foreach(VisualCeiling vc in bvs.ExtraCeilings) vc.Changed = false;
foreach(VisualFloor vf in bvs.ExtraBackFloors) vf.Changed = false; //mxd
foreach(VisualCeiling vc in bvs.ExtraBackCeilings) vc.Changed = false; //mxd
bvs.Floor.Changed = false;
bvs.Ceiling.Changed = false;
}
// Only clear the selection if anything is selected, since it can be very time consuming on huge maps
if (singleselection && selectedobjects.Count > 0) ClearSelection();
UpdateChangedObjects();
ShowTargetInfo();
}
// This sets the result for an action
public void SetActionResult(VisualActionResult result)
{
actionresult = result;
}
// This sets the result for an action
public void SetActionResult(string displaystatus)
{
actionresult = new VisualActionResult {displaystatus = displaystatus};
}
// This creates an undo, when only a single selection is made
// When a multi-selection is made, the undo is created by the PreAction function
public int CreateUndo(string description, int group, int grouptag)
if(!undocreated)
{
undocreated = true;
if(singleselection)
return General.Map.UndoRedo.CreateUndo(description, this, group, grouptag);
return General.Map.UndoRedo.CreateUndo(description, this, UndoGroup.None, 0);
}
// This creates an undo, when only a single selection is made
// When a multi-selection is made, the undo is created by the PreAction function
public int CreateUndo(string description)
return CreateUndo(description, UndoGroup.None, 0);
}
// This makes a list of the selected object
codeimp
committed
private void RebuildSelectedObjectsList()
{
// Make list of selected objects
selectedobjects = new List<IVisualEventReceiver>();
ZZYZX
committed
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
ZZYZX
committed
if(vs.Value != null)
ZZYZX
committed
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if((bvs.Floor != null) && bvs.Floor.Selected) selectedobjects.Add(bvs.Floor);
if((bvs.Ceiling != null) && bvs.Ceiling.Selected) selectedobjects.Add(bvs.Ceiling);
// Also check extra floors
if (bvs.ExtraFloors.Count > 0)
foreach (VisualFloor vf in bvs.ExtraFloors)
if (vf.Selected) selectedobjects.Add(vf);
if (bvs.ExtraBackFloors.Count > 0)
foreach (VisualFloor vf in bvs.ExtraBackFloors)
if (vf.Selected) selectedobjects.Add(vf);
// Also check extra ceilings
if (bvs.ExtraCeilings.Count > 0)
foreach (VisualCeiling vc in bvs.ExtraCeilings)
if (vc.Selected) selectedobjects.Add(vc);
if (bvs.ExtraBackCeilings.Count > 0)
foreach (VisualCeiling vc in bvs.ExtraBackCeilings)
if (vc.Selected) selectedobjects.Add(vc);
foreach (Sidedef sd in vs.Key.Sidedefs)
ZZYZX
committed
List<VisualGeometry> sidedefgeos = bvs.GetSidedefGeometry(sd);
foreach(VisualGeometry sdg in sidedefgeos)
{
if(sdg.Selected) selectedobjects.Add((IVisualEventReceiver)sdg);
}
}
}
}
ZZYZX
committed
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
ZZYZX
committed
if(vt.Value != null)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
if(bvt.Selected) selectedobjects.Add(bvt);
}
if(General.Map.UDMF && General.Map.Config.VertexHeightSupport && General.Settings.GZShowVisualVertices)
{
foreach(KeyValuePair<Vertex, VisualVertexPair> pair in vertices)
{
if(pair.Value.CeilingVertex.Selected)
selectedobjects.Add((BaseVisualVertex)pair.Value.CeilingVertex);
if(pair.Value.FloorVertex.Selected)
selectedobjects.Add((BaseVisualVertex)pair.Value.FloorVertex);
if (General.Map.UDMF)
{
foreach (KeyValuePair<Sector, List<VisualSlope>> kvp in allslopehandles)
{
foreach (BaseVisualSlope handle in kvp.Value)
if (handle.Selected) selectedobjects.Add(handle);
//mxd
UpdateSelectionInfo();
//mxd. Need this to apply changes to 3d-floor even if control sector doesn't exist as BaseVisualSector
internal BaseVisualSector CreateBaseVisualSector(Sector s)
{
BaseVisualSector vs = new BaseVisualSector(this, s);
ZZYZX
committed
allsectors.Add(s, vs);
return vs;
}
// This creates a visual sector
protected override VisualSector CreateVisualSector(Sector s)
{
BaseVisualSector vs = new BaseVisualSector(this, s);
ZZYZX
committed
allsectors.Add(s, vs); //mxd
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>());
biwa
committed
if (!sidedefslopehandles.ContainsKey(sd.Sector))
sidedefslopehandles.Add(sd.Sector, new List<VisualSlope>());
biwa
committed
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
sidedefslopehandles[sd.Sector].Add(handle);
return handle;
}
internal VisualSlope CreateVisualSlopeHandle(SectorLevel level, Vertex v, Sector s, bool up)
{
VisualVertexSlope handle = new VisualVertexSlope(this, level, v, s, up);
/*
if (!allslopehandles.ContainsKey(level.sector))
allslopehandles.Add(level.sector, new List<VisualSlope>());
if (!vertexslopehandles.ContainsKey(level.sector))
vertexslopehandles.Add(level.sector, new List<VisualSlope>());
allslopehandles[level.sector].Add(handle);
vertexslopehandles[level.sector].Add(handle);
*/
if (!allslopehandles.ContainsKey(s))
allslopehandles.Add(s, new List<VisualSlope>());
if (!vertexslopehandles.ContainsKey(s))
vertexslopehandles.Add(s, new List<VisualSlope>());
allslopehandles[s].Add(handle);
vertexslopehandles[s].Add(handle);
// This creates a visual thing
protected override VisualThing CreateVisualThing(Thing t)
{
BaseVisualThing vt = new BaseVisualThing(this, t);
return vt.Setup() ? vt : null;
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
// This locks the target so that it isn't changed until unlocked
public void LockTarget()
{
locktarget = true;
}
// This unlocks the target so that is changes to the aimed geometry again
public void UnlockTarget()
{
locktarget = false;
}
// This picks a new target, if not locked
private void PickTargetUnlocked()
{
if(!locktarget) PickTarget();
}
// This picks a new target
private void PickTarget()
{
// Find the object we are aiming at
Vector3D start = General.Map.VisualCamera.Position;
Vector3D delta = General.Map.VisualCamera.Target - General.Map.VisualCamera.Position;
delta = delta.GetFixedLength(General.Settings.ViewDistance * PICK_RANGE);
VisualPickResult newtarget = PickObject(start, start + delta);
VisualSlope pickedhandle = null;
// Should we update the info on panels?
bool updateinfo = (newtarget.picked != target.picked);
// Operating on slope handles is potentially expensive, so only do it it absolutely necessary (i.e. when a new slope handle was selected)
if (updateinfo)
{
if (target.picked is VisualSlope) // Old target
{
// Remove all smart pivot handles from being processed. There should only be exactly one, but better save than sorry
List<VisualSlope> sph = new List<VisualSlope>();
foreach (VisualSlope vs in usedslopehandles)
{
if(vs.SmartPivot && !(vs.Selected || vs.Pivot))
sph.Add(vs);
vs.SmartPivot = false;
}
foreach (VisualSlope vs in sph)
usedslopehandles.Remove(vs);
// Don't render old slope handle anymore
if (!((VisualSlope)target.picked).Selected && !((VisualSlope)target.picked).Pivot)
usedslopehandles.Remove((VisualSlope)target.picked);
usedslopehandles.Add((VisualSlope)newtarget.picked);
pickedhandle = ((VisualSlope)newtarget.picked);
}
}
// Apply new target
target = newtarget;
// Get the smart pivot handle for the targeted slope handle, so that it can be drawn. We have to do it after the current
// target is set because otherwise it might get wrong results if the old target was a floor/ceiling
if (pickedhandle != null)
{
VisualSlope handle = pickedhandle.GetSmartPivotHandle();
if (handle != null)
{
handle.SmartPivot = true;
usedslopehandles.Add(handle);
}
}
if (updateinfo)
ShowTargetInfo();
}
// This shows the picked target information
public void ShowTargetInfo()
{
// Any result?
if(target.picked != null)
{
// Geometry picked?
if(target.picked is VisualGeometry)
{
VisualGeometry pickedgeo = (VisualGeometry)target.picked;
// Sidedef?
if(pickedgeo is BaseVisualGeometrySidedef)
{
BaseVisualGeometrySidedef pickedsidedef = (BaseVisualGeometrySidedef)pickedgeo;
General.Interface.ShowLinedefInfo(pickedsidedef.GetControlLinedef(), pickedsidedef.Sidedef); //mxd
}
// Sector?
else if(pickedgeo is BaseVisualGeometrySector)
{
BaseVisualGeometrySector pickedsector = (BaseVisualGeometrySector)pickedgeo;
bool isceiling = (pickedsector is VisualCeiling); //mxd
General.Interface.ShowSectorInfo(pickedsector.Level.sector, isceiling, !isceiling);
General.Interface.HideInfo();
// Thing picked?
{
VisualThing pickedthing = (VisualThing)target.picked;
General.Interface.ShowThingInfo(pickedthing.Thing);
//mxd. Vertex picked?
else if(target.picked is VisualVertex)
VisualVertex pickedvert = (VisualVertex)target.picked;
}
}
else
{
General.Interface.HideInfo();
}
}
// This updates the VisualSectors and VisualThings that have their Changed property set
private void UpdateChangedObjects()
ZZYZX
committed
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
ZZYZX
committed
if(vs.Value != null)
{
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if(bvs.Changed)
{
bvs.Rebuild();
// Also update slope handles
if (allslopehandles.ContainsKey(vs.Key))
biwa
committed
foreach (VisualSlope handle in allslopehandles[vs.Key])
ZZYZX
committed
}
ZZYZX
committed
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
ZZYZX
committed
if(vt.Value != null)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
if(bvt.Changed) bvt.Rebuild();
}
if(General.Map.UDMF && General.Map.Config.VertexHeightSupport)
foreach(KeyValuePair<Vertex, VisualVertexPair> pair in vertices)
pair.Value.Update();
}
//mxd. Update event lines (still better than updating them on every frame redraw)
renderer.SetEventLines(LinksCollector.GetHelperShapes(General.Map.ThingsFilter.VisibleThings, blockmap));
MaxED
committed
protected override void MoveSelectedThings(Vector2D direction, bool absoluteposition)
MaxED
committed
List<VisualThing> visualthings = GetSelectedVisualThings(true);
if(visualthings.Count == 0) return;
PreAction(UndoGroup.ThingMove);
MaxED
committed
Vector3D[] coords = new Vector3D[visualthings.Count];
for(int i = 0; i < visualthings.Count; i++)
coords[i] = visualthings[i].Thing.Position;
//move things...
MaxED
committed
Vector3D[] translatedcoords = TranslateCoordinates(coords, direction, absoluteposition);
for(int i = 0; i < visualthings.Count; i++)
BaseVisualThing t = (BaseVisualThing)visualthings[i];
MaxED
committed
t.OnMove(translatedcoords[i]);
MaxED
committed
// Things may've changed sectors...
FillBlockMap();
PostAction();
}
MaxED
committed
private static Vector3D[] TranslateCoordinates(Vector3D[] coordinates, Vector2D direction, bool absolutePosition)
if(coordinates.Length == 0) return null;
direction.x = Math.Round(direction.x);
direction.y = Math.Round(direction.y);
Vector3D[] translatedCoords = new Vector3D[coordinates.Length];
//move things...
if(!absolutePosition) //...relatively (that's easy)
MaxED
committed
{
int camAngle = (int)Math.Round(Angle2D.RadToDeg(General.Map.VisualCamera.AngleXY));
int sector = General.ClampAngle(camAngle - 45) / 90;
direction = direction.GetRotated(sector * Angle2D.PIHALF);
for(int i = 0; i < coordinates.Length; i++)
translatedCoords[i] = coordinates[i] + new Vector3D(direction);
return translatedCoords;
}
//...to specified location preserving relative positioning (that's harder)
if(coordinates.Length == 1) //just move it there
MaxED
committed
{
translatedCoords[0] = new Vector3D(direction.x, direction.y, coordinates[0].z);
return translatedCoords;
}
//we need some reference
double minX = coordinates[0].x;
double maxX = minX;
double minY = coordinates[0].y;
double maxY = minY;
//get bounding coordinates for selected things
for(int i = 1; i < coordinates.Length; i++)
MaxED
committed
{
if(coordinates[i].x < minX)
minX = coordinates[i].x;
else if(coordinates[i].x > maxX)
maxX = coordinates[i].x;
if(coordinates[i].y < minY)
minY = coordinates[i].y;
else if(coordinates[i].y > maxY)
maxY = coordinates[i].y;
}
Vector2D selectionCenter = new Vector2D(minX + (maxX - minX) / 2, minY + (maxY - minY) / 2);
for(int i = 0; i < coordinates.Length; i++)
translatedCoords[i] = new Vector3D(Math.Round(direction.x - (selectionCenter.x - coordinates[i].x)), Math.Round(direction.y - (selectionCenter.y - coordinates[i].y)), Math.Round(coordinates[i].z));
return translatedCoords;
}
public override void UpdateSelectionInfo()
// Collect info
int numWalls = 0;
int numFloors = 0;
int numCeilings = 0;
int numThings = 0;
int numVerts = 0;
foreach(IVisualEventReceiver obj in selectedobjects)
{
if(!obj.Selected) continue;
if(obj is BaseVisualThing) numThings++;
else if(obj is BaseVisualVertex) numVerts++;
else if(obj is VisualCeiling) numCeilings++;
else if(obj is VisualFloor) numFloors++;
else if(obj is VisualMiddleSingle || obj is VisualMiddleDouble || obj is VisualLower || obj is VisualUpper || obj is VisualMiddle3D || obj is VisualMiddleBack)
numWalls++;
}
List<string> results = new List<string>();
if(numWalls > 0) results.Add(numWalls + (numWalls > 1 ? " sidedefs" : " sidedef"));
if(numFloors > 0) results.Add(numFloors + (numFloors > 1 ? " floors" : " floor"));
if(numCeilings > 0) results.Add(numCeilings + (numCeilings > 1 ? " ceilings" : " ceiling"));
if(numThings > 0) results.Add(numThings + (numThings > 1 ? " things" : " thing"));
if(numVerts > 0) results.Add(numVerts + (numVerts > 1 ? " vertices" : " vertex"));
// Display results
string result = string.Empty;
if(results.Count > 0)
result = string.Join(", ", results.ToArray());
int pos = result.LastIndexOf(",", StringComparison.Ordinal);
if(pos != -1) result = result.Remove(pos, 1).Insert(pos, " and");
result += " selected.";
General.Interface.DisplayStatus(StatusType.Selection, result);
MaxED
committed
//mxd
MaxED
committed
internal void StartRealtimeInterfaceUpdate(SelectionType selectiontype)
{
switch(selectiontype)
MaxED
committed
{
case SelectionType.All:
case SelectionType.Linedefs:
case SelectionType.Sectors:
General.Interface.OnEditFormValuesChanged += Interface_OnSectorEditFormValuesChanged;
break;
case SelectionType.Things:
General.Interface.OnEditFormValuesChanged += Interface_OnThingEditFormValuesChanged;
break;
default:
General.Interface.OnEditFormValuesChanged += Interface_OnEditFormValuesChanged;
break;
MaxED
committed
}
}
//mxd
MaxED
committed
internal void StopRealtimeInterfaceUpdate(SelectionType selectiontype)
{
switch(selectiontype)
MaxED
committed
{
case SelectionType.All:
case SelectionType.Linedefs:
case SelectionType.Sectors:
General.Interface.OnEditFormValuesChanged -= Interface_OnSectorEditFormValuesChanged;
break;
case SelectionType.Things:
General.Interface.OnEditFormValuesChanged -= Interface_OnThingEditFormValuesChanged;
break;
default:
General.Interface.OnEditFormValuesChanged -= Interface_OnEditFormValuesChanged;
break;
MaxED
committed
}
}
private List<VisualSidedefSlope> GetSlopeHandlePair()
{
List<VisualSidedefSlope> handles = GetSelectedSlopeHandles();
// No handles selected, try to slope between highlighted handle and it smart pivot
if (handles.Count == 0 && HighlightedTarget is VisualSidedefSlope)
{
//VisualSidedefSlope handle = VisualSidedefSlope.GetSmartPivotHandle((VisualSidedefSlope)HighlightedTarget, this);
VisualSidedefSlope handle = (VisualSidedefSlope)((VisualSidedefSlope)HighlightedTarget).GetSmartPivotHandle();
if (handle == null)
{
General.Interface.DisplayStatus(StatusType.Warning, "Couldn't find a smart pivot handle.");
return handles;
}
handles.Add((VisualSidedefSlope)HighlightedTarget);
handles.Add(handle);
}
// One handle selected, try to slope between it and the highlighted handle or the selected one's smart pivot
else if (handles.Count == 1)
{
if (HighlightedTarget == handles[0] || !(HighlightedTarget is VisualSidedefSlope))
{
VisualSidedefSlope handle;
if (HighlightedTarget is VisualSidedefSlope)
handle = (VisualSidedefSlope)((VisualSidedefSlope)HighlightedTarget).GetSmartPivotHandle();
handle = (VisualSidedefSlope)(handles[0].GetSmartPivotHandle());
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
if (handle == null)
{
General.Interface.DisplayStatus(StatusType.Warning, "Couldn't find a smart pivot handle.");
return handles;
}
handles.Add(handle);
}
else
{
handles.Add((VisualSidedefSlope)HighlightedTarget);
}
}
// Return if more than two handles are selected
else if (handles.Count > 2)
{
General.Interface.DisplayStatus(StatusType.Warning, "Too many slope handles selected.");
return handles;
}
// Everything else
else if (handles.Count != 2)
{
General.Interface.DisplayStatus(StatusType.Warning, "No slope handles selected or highlighted.");
return handles;
}
return handles;
}
#region ================== Extended Methods
// This requests a sector's extra data
internal SectorData GetSectorData(Sector s)
{
// Make fresh sector data when it doesn't exist yet
if(!sectordata.ContainsKey(s))
sectordata[s] = new SectorData(this, s);
return sectordata[s];
}
//mxd. This requests a sector's extra data or null if given sector doesn't have it
internal SectorData GetSectorDataEx(Sector s)
{
return (sectordata.ContainsKey(s) ? sectordata[s] : null);
}
// This requests a things's extra data
internal ThingData GetThingData(Thing t)
{
// Make fresh sector data when it doesn't exist yet
if(!thingdata.ContainsKey(t))
thingdata[t] = new ThingData(this, t);
return thingdata[t];
}
MaxED
committed
internal VertexData GetVertexData(Vertex v)
{
if(!vertexdata.ContainsKey(v))
vertexdata[v] = new VertexData(this, v);
return vertexdata[v];
}
MaxED
committed
internal BaseVisualVertex GetVisualVertex(Vertex v, bool floor)
{
if(!vertices.ContainsKey(v))
vertices.Add(v, new VisualVertexPair(new BaseVisualVertex(this, v, false), new BaseVisualVertex(this, v, true)));
return (floor ? (BaseVisualVertex)vertices[v].FloorVertex : (BaseVisualVertex)vertices[v].CeilingVertex);
}
MaxED
committed
internal void UpdateVertexHandle(Vertex v)
{
vertices.Add(v, new VisualVertexPair(new BaseVisualVertex(this, v, false), new BaseVisualVertex(this, v, true)));
MaxED
committed
vertices[v].Changed = true;
// This rebuilds the sector data
// This requires that the blockmap is up-to-date!
internal void RebuildElementData()
{
HashSet<Sector> effectsectors = null; //mxd
List<Linedef>[] slopelinedefpass = new List<Linedef>[] { new List<Linedef>(), new List<Linedef>() };
List<Thing>[] slopethingpass = new List<Thing>[] { new List<Thing>(), new List<Thing>() };
if (!General.Settings.EnhancedRenderingEffects) //mxd
MaxED
committed
{
// Store all sectors with effects
MaxED
committed
if(sectordata != null && sectordata.Count > 0)
effectsectors = new HashSet<Sector>(sectordata.Keys);
// Remove all vertex handles from selection
MaxED
committed
if(vertices != null && vertices.Count > 0)
{
for (int i = 0; i < selectedobjects.Count; i++)
{
if (selectedobjects[i] is BaseVisualVertex)
{
RemoveSelectedObject(selectedobjects[i]);
i--;
}
}
Dictionary<int, List<Sector>> sectortags = new Dictionary<int, List<Sector>>();
Dictionary<int, List<Thing>> thingtags = new Dictionary<int, List<Thing>>();
Dictionary<int, List<Linedef>> linetags = new Dictionary<int, List<Linedef>>();
sectordata = new Dictionary<Sector, SectorData>(General.Map.Map.Sectors.Count);
thingdata = new Dictionary<Thing, ThingData>(General.Map.Map.Things.Count);
//mxd. Rebuild all sectors with effects
if(effectsectors != null)
MaxED
committed
{
foreach(Sector s in effectsectors)
MaxED
committed
{
if(!VisualSectorExists(s)) continue;
// The visual sector associated is now outdated
BaseVisualSector vs = (BaseVisualSector)GetVisualSector(s);
vs.UpdateSectorGeometry(true);
}
}
MaxED
committed
if(General.Map.UDMF)
{
vertexdata = new Dictionary<Vertex, VertexData>(General.Map.Map.Vertices.Count); //mxd
vertices.Clear();
}
if(!General.Settings.EnhancedRenderingEffects) return; //mxd
// Find all sector who's tag is not 0 and hash them so that we can find them quickly
foreach(Sector s in General.Map.Map.Sectors)