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;
using System.Collections.Generic;
using System.Windows.Forms;
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;
using CodeImp.DoomBuilder.GZBuilder.Tools;
#endregion
namespace CodeImp.DoomBuilder.BuilderModes
{
[EditMode(DisplayName = "GZDB Visual Mode",
SwitchAction = "gzdbvisualmode", // Action name used to switch to this mode
ButtonImage = "VisualModeGZ.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 float PICK_INTERVAL = 80.0f;
private const float PICK_RANGE = 0.98f;
// Gravity
private const float GRAVITY = -0.06f;
#endregion
#region ================== Variables
// Gravity
private Vector3D gravity;
private float cameraflooroffset = 41f; // same as in doom
private float cameraceilingoffset = 10f;
// Object picking
private VisualPickResult target;
private float lastpicktime;
// 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 List<ThingCopyData> copyBuffer;
private Type lasthighlighttype; //mxd
private static bool gzdoomRenderingEffects = true; //mxd
//mxd. Moved here from Tools
private struct SidedefAlignJob
{
public Sidedef sidedef;
public Sidedef controlSide; //mxd
public float offsetx;
MaxED
committed
public float scaleY; //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;
}
//mxd. All sorts of hints
private string[] thingHints;
private string[] sidedefHints;
private string[] sectorHints;
private string[] vertexHints;
private string[] generalHints;
#endregion
#region ================== Properties
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
public override object HighlightedObject
{
get
{
// Geometry picked?
if(target.picked is VisualGeometry)
{
VisualGeometry pickedgeo = (target.picked as VisualGeometry);
if(pickedgeo.Sidedef != null)
return pickedgeo.Sidedef;
else if(pickedgeo.Sector != null)
return pickedgeo.Sector;
else
return null;
}
// Thing picked?
else if(target.picked is VisualThing)
{
VisualThing pickedthing = (target.picked as VisualThing);
return pickedthing.Thing;
}
else
{
return null;
}
}
}
public object HighlightedTarget { get { return target.picked; } } //mxd
public static bool GZDoomRenderingEffects { get { return gzdoomRenderingEffects; } } //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; } }
#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>();
//mxd
this.copyBuffer = new List<ThingCopyData>();
// We have no destructor
GC.SuppressFinalize(this);
}
// Disposer
public override void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Clean up
// 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;
}
// This removes a selected object
internal void RemoveSelectedObject(IVisualEventReceiver obj)
{
selectedobjects.Remove(obj);
selectionchanged = true;
}
// 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.
codeimp
committed
if((target.picked != null) && !target.picked.Selected && (BuilderPlug.Me.VisualModeClearSelection || (selectedobjects.Count == 0)))
// Single object, no selection
singleselection = true;
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);
// Reset changed flags
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
BaseVisualSector bvs = (vs.Value as BaseVisualSector);
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;
}
if(singleselection)
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();
actionresult.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);
else
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>();
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
if(vs.Value != null)
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);
foreach(Sidedef sd in vs.Key.Sidedefs)
List<VisualGeometry> sidedefgeos = bvs.GetSidedefGeometry(sd);
foreach(VisualGeometry sdg in sidedefgeos)
{
if(sdg.Selected) selectedobjects.Add((sdg as IVisualEventReceiver));
}
}
}
}
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
{
if(vt.Value != null)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
if(bvt.Selected) selectedobjects.Add(bvt);
}
//mxd
if(General.Map.UDMF && General.Settings.GZShowVisualVertices) {
foreach(KeyValuePair<Vertex, VisualVertexPair> pair in vertices) {
if(pair.Value.Vertex1.Selected)
selectedobjects.Add((BaseVisualVertex)pair.Value.Vertex1);
if(pair.Value.Vertex2.Selected)
selectedobjects.Add((BaseVisualVertex)pair.Value.Vertex2);
}
}
//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);
if(vs != null) allsectors.Add(s, vs);
return vs;
}
// This creates a visual sector
protected override VisualSector CreateVisualSector(Sector s)
{
BaseVisualSector vs = new BaseVisualSector(this, s);
if (vs != null) allsectors.Add(s, vs); //mxd
return vs;
}
// This creates a visual thing
protected override VisualThing CreateVisualThing(Thing t)
{
BaseVisualThing vt = new BaseVisualThing(this, t);
return vt.Setup() ? vt : null;
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
// 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);
// Should we update the info on panels?
bool updateinfo = (newtarget.picked != target.picked);
// Apply new target
target = newtarget;
// Show target info
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 = (target.picked as VisualGeometry);
// Sidedef?
if(pickedgeo is BaseVisualGeometrySidedef)
{
BaseVisualGeometrySidedef pickedsidedef = (pickedgeo as BaseVisualGeometrySidedef);
General.Interface.ShowLinedefInfo(pickedsidedef.GetControlLinedef()); //mxd
}
// Sector?
else if(pickedgeo is BaseVisualGeometrySector)
{
BaseVisualGeometrySector pickedsector = (pickedgeo as BaseVisualGeometrySector);
General.Interface.ShowSectorInfo(pickedsector.Level.sector);
}
General.Interface.HideInfo();
}
else if(target.picked is VisualThing)
{ // Thing picked?
VisualThing pickedthing = (target.picked as VisualThing);
General.Interface.ShowThingInfo(pickedthing.Thing);
}
else if(target.picked is VisualVertex) //mxd
{
VisualVertex pickedvert = (target.picked as VisualVertex);
General.Interface.ShowVertexInfo(pickedvert.Vertex);
}
}
else
{
General.Interface.HideInfo();
}
}
// This updates the VisualSectors and VisualThings that have their Changed property set
private void UpdateChangedObjects()
{
foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
{
if(vs.Value != null)
{
BaseVisualSector bvs = (BaseVisualSector)vs.Value;
if(bvs.Changed) bvs.Rebuild();
}
}
foreach(KeyValuePair<Thing, VisualThing> vt in allthings)
{
if(vt.Value != null)
{
BaseVisualThing bvt = (BaseVisualThing)vt.Value;
if(bvt.Changed) bvt.Rebuild();
}
//mxd
if(General.Map.UDMF) {
foreach(KeyValuePair<Vertex, VisualVertexPair> pair in vertices)
pair.Value.Update();
}
//mxd
protected override void moveSelectedThings(Vector2D direction, bool absolutePosition) {
List<VisualThing> visualThings = GetSelectedVisualThings(true);
if (visualThings.Count == 0) return;
PreAction(UndoGroup.ThingMove);
Vector3D[] coords = new Vector3D[visualThings.Count];
for (int i = 0; i < visualThings.Count; i++)
coords[i] = visualThings[i].Thing.Position;
//move things...
Vector3D[] translatedCoords = translateCoordinates(coords, direction, absolutePosition);
for (int i = 0; i < visualThings.Count; i++) {
BaseVisualThing t = visualThings[i] as BaseVisualThing;
t.OnMove(translatedCoords[i]);
}
PostAction();
}
//mxd
private Vector3D[] translateCoordinates(Vector3D[] coordinates, Vector2D direction, bool absolutePosition) {
if (coordinates.Length == 0) return null;
direction.x = (float)Math.Round(direction.x);
direction.y = (float)Math.Round(direction.y);
Vector3D[] translatedCoords = new Vector3D[coordinates.Length];
//move things...
if (!absolutePosition) { //...relatively (that's easy)
int camAngle = (int)Math.Round(Angle2D.RadToDeg(General.Map.VisualCamera.AngleXY));// * 180 / Math.PI);
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
translatedCoords[0] = new Vector3D(direction.x, direction.y, coordinates[0].z);
return translatedCoords;
}
//we need some reference
float minX = coordinates[0].x;
float maxX = minX;
float minY = coordinates[0].y;
float maxY = minY;
//get bounding coordinates for selected things
for (int i = 1; i < coordinates.Length; i++) {
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);
//move them
for (int i = 0; i < coordinates.Length; i++)
translatedCoords[i] = new Vector3D((float)Math.Round(direction.x - (selectionCenter.x - coordinates[i].x)), (float)Math.Round(direction.y - (selectionCenter.y - coordinates[i].y)), (float)Math.Round(coordinates[i].z));
return translatedCoords;
}
//mxd
internal void SelectSideParts(Sidedef side, bool toggleTop, bool toggleMid, bool toggleBottom, bool select, bool withSameTexture, bool withSameHeight) {
BaseVisualSector vs = GetVisualSector(side.Sector) as BaseVisualSector;
if(toggleTop && vs.Sides[side].upper != null &&
((select && !vs.Sides[side].upper.Selected) || (!select && vs.Sides[side].upper.Selected))) {
vs.Sides[side].upper.SelectNeighbours(select, withSameTexture, withSameHeight);
}
if(toggleMid && vs.Sides[side].middlesingle != null &&
((select && !vs.Sides[side].middlesingle.Selected) || (!select && vs.Sides[side].middlesingle.Selected))) {
vs.Sides[side].middlesingle.SelectNeighbours(select, withSameTexture, withSameHeight);
}
if(toggleMid && vs.Sides[side].middledouble != null &&
((select && !vs.Sides[side].middledouble.Selected) || (!select && vs.Sides[side].middledouble.Selected))) {
vs.Sides[side].middledouble.SelectNeighbours(select, withSameTexture, withSameHeight);
}
if(toggleBottom && vs.Sides[side].lower != null &&
((select && !vs.Sides[side].lower.Selected) || (!select && vs.Sides[side].lower.Selected))) {
vs.Sides[side].lower.SelectNeighbours(select, withSameTexture, withSameHeight);
}
}
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
//mxd
private void updateSelectionInfo() {
int numWalls = 0;
int numFloors = 0;
int numCeilings = 0;
int numThings = 0;
int numVerts = 0;
foreach(IVisualEventReceiver obj in selectedobjects) {
if(!obj.IsSelected()) 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++;
}
string result = "";
if(numWalls > 0) result = numWalls + (numWalls > 1 ? " sidedefs" : " sidedef");
if(numFloors > 0) result += (result.Length > 0 ? ", " : "") + numFloors + (numFloors > 1 ? " floors" : " floor");
if(numCeilings > 0) result += (result.Length > 0 ? ", " : "") + numCeilings + (numCeilings > 1 ? " ceilings" : " ceiling");
if(numThings > 0) result += (result.Length > 0 ? ", " : "") + numThings + (numThings > 1 ? " things" : " thing");
if(numVerts > 0) result += (result.Length > 0 ? ", " : "") + numVerts + (numVerts > 1 ? " vertices" : " vertex");
if(!string.IsNullOrEmpty(result)) {
int pos = result.LastIndexOf(",");
if(pos != -1) result = result.Remove(pos, 1).Insert(pos, " and");
result += " selected";
}
General.Interface.DisplayStatus(StatusType.Selection, result);
}
MaxED
committed
//mxd
internal void StartRealtimeInterfaceUpdate(SelectionType selectionType) {
if (selectionType == SelectionType.Sectors || selectionType == SelectionType.Linedefs || selectionType == SelectionType.All) {
General.Interface.OnEditFormValuesChanged += Interface_OnSectorEditFormValuesChanged;
} else if(selectionType == SelectionType.Things) {
General.Interface.OnEditFormValuesChanged += Interface_OnThingEditFormValuesChanged;
MaxED
committed
} else {
General.Interface.OnEditFormValuesChanged += Interface_OnEditFormValuesChanged;
MaxED
committed
}
}
//mxd
internal void StopRealtimeInterfaceUpdate(SelectionType selectionType) {
if(selectionType == SelectionType.Sectors || selectionType == SelectionType.Linedefs || selectionType == SelectionType.All) {
General.Interface.OnEditFormValuesChanged -= Interface_OnSectorEditFormValuesChanged;
} else if(selectionType == SelectionType.Things) {
General.Interface.OnEditFormValuesChanged -= Interface_OnThingEditFormValuesChanged;
MaxED
committed
} else {
General.Interface.OnEditFormValuesChanged -= Interface_OnEditFormValuesChanged;
}
}
#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];
}
// 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];
}
//mxd
internal VertexData GetVertexData(Vertex v) {
if(!vertexdata.ContainsKey(v))
vertexdata[v] = new VertexData(this, v);
return vertexdata[v];
}
//mxd
internal void UpdateVertexHandle(Vertex v) {
if(!vertices.ContainsKey(v))
vertices.Add(v, new VisualVertexPair(new BaseVisualVertex(this, v, true), new BaseVisualVertex(this, v, false)));
else
MaxED
committed
vertices[v].Changed = true;
// This rebuilds the sector data
// This requires that the blockmap is up-to-date!
internal void RebuildElementData()
{
Sector[] sectorsWithEffects = null;
if (!gzdoomRenderingEffects) {
//store all sectors with effects
sectorsWithEffects = new Sector[sectordata.Count];
sectordata.Keys.CopyTo(sectorsWithEffects, 0);
}
//remove all vertex handles from selection
if(vertices != null && vertices.Count > 0) {
foreach(IVisualEventReceiver i in selectedobjects){
if(i is BaseVisualVertex) RemoveSelectedObject(i);
}
}
Dictionary<int, List<Sector>> sectortags = new Dictionary<int, List<Sector>>();
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(sectorsWithEffects != null) {
for(int i = 0; i < sectorsWithEffects.Length; i++) {
// The visual sector associated is now outdated
if(VisualSectorExists(sectorsWithEffects[i])) {
BaseVisualSector vs = (BaseVisualSector)GetVisualSector(sectorsWithEffects[i]);
vs.UpdateSectorGeometry(true);
}
}
}
if(General.Map.UDMF) {
vertexdata = new Dictionary<Vertex, VertexData>(General.Map.Map.Vertices.Count); //mxd
vertices.Clear();
}
if (!gzdoomRenderingEffects) return; //mxd
// Find all sector who's tag is not 0 and hash them so that we can find them quicly
foreach(Sector s in General.Map.Map.Sectors)
{
if(s.Tag != 0)
{
if(!sectortags.ContainsKey(s.Tag)) sectortags[s.Tag] = new List<Sector>();
sectortags[s.Tag].Add(s);
}
}
// Find sectors with 3 vertices, because they can be sloped
foreach(Sector s in General.Map.Map.Sectors)
{
// ========== Thing vertex slope, vertices with UDMF vertex offsets ==========
if(s.Sidedefs.Count == 3)
{
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
if(General.Map.UDMF) //mxd
GetSectorData(s).AddEffectVertexOffset();
List<Thing> slopeceilingthings = new List<Thing>(3);
List<Thing> slopefloorthings = new List<Thing>(3);
foreach(Sidedef sd in s.Sidedefs) {
Vertex v = sd.IsFront ? sd.Line.End : sd.Line.Start;
// Check if a thing is at this vertex
VisualBlockEntry b = blockmap.GetBlock(blockmap.GetBlockCoordinates(v.Position));
foreach(Thing t in b.Things) {
if((Vector2D)t.Position == v.Position) {
if(t.Type == 1504)
slopefloorthings.Add(t);
else if(t.Type == 1505)
slopeceilingthings.Add(t);
}
}
}
// Slope any floor vertices?
if(slopefloorthings.Count > 0) {
SectorData sd = GetSectorData(s);
sd.AddEffectThingVertexSlope(slopefloorthings, true);
}
// Slope any ceiling vertices?
if(slopeceilingthings.Count > 0) {
SectorData sd = GetSectorData(s);
sd.AddEffectThingVertexSlope(slopeceilingthings, false);
}
}
}
// Find interesting linedefs (such as line slopes)
foreach(Linedef l in General.Map.Map.Linedefs)
{
// ========== Plane Align (see http://zdoom.org/wiki/Plane_Align) ==========
if(l.Action == 181)
{
// Slope front
if(((l.Args[0] == 1) || (l.Args[1] == 1)) && (l.Front != null))
{
SectorData sd = GetSectorData(l.Front.Sector);
sd.AddEffectLineSlope(l);
}
// Slope back
if(((l.Args[0] == 2) || (l.Args[1] == 2)) && (l.Back != null))
{
SectorData sd = GetSectorData(l.Back.Sector);
sd.AddEffectLineSlope(l);
}
}
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
// ========== Plane Copy (mxd) (see http://zdoom.org/wiki/Plane_Copy) ==========
else if(l.Action == 118)
{
//check sodding flags...
bool floorCopyToBack = false;
bool floorCopyToFront = false;
bool ceilingCopyToBack = false;
bool ceilingCopyToFront = false;
if(l.Args[4] > 0 && l.Args[4] != 3 && l.Args[4] != 12) {
floorCopyToBack = (l.Args[4] & 1) == 1;
floorCopyToFront = (l.Args[4] & 2) == 2;
ceilingCopyToBack = (l.Args[4] & 4) == 4;
ceilingCopyToFront = (l.Args[4] & 8) == 8;
}
// Copy slope to front sector
//Flags: Back floor to front sector or Back ceiling to front sector
if(l.Front != null) {
if((l.Args[0] > 0 || l.Args[1] > 0) || (floorCopyToFront && l.Args[2] > 0) || (ceilingCopyToFront && l.Args[3] > 0)) {
SectorData sd = GetSectorData(l.Front.Sector);
sd.AddEffectPlaneClopySlope(l, true);
}
}
// Copy slope to back sector
//Flags: Copy front floor to back sector or Front ceiling to back sector
if(l.Back != null) {
if((l.Args[2] > 0 || l.Args[3] > 0) || (floorCopyToBack && l.Args[0] > 0) || (ceilingCopyToBack && l.Args[1] > 0)) {
SectorData sd = GetSectorData(l.Back.Sector);
sd.AddEffectPlaneClopySlope(l, false);
}
}
}
// ========== Sector 3D floor (see http://zdoom.org/wiki/Sector_Set3dFloor) ==========
else if((l.Action == 160) && (l.Front != null))
{
//mxd. Added hi-tag/line ID check
int sectortag = (l.Args[1] & (int)Effect3DFloor.FloorTypes.HiTagIsLineID) != 0 ? l.Args[0] : l.Args[0] + (l.Args[4] << 8);
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
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
if(sectortags.ContainsKey(sectortag))
{
List<Sector> sectors = sectortags[sectortag];
foreach(Sector s in sectors)
{
SectorData sd = GetSectorData(s);
sd.AddEffect3DFloor(l);
}
}
}
// ========== Transfer Brightness (see http://zdoom.org/wiki/ExtraFloor_LightOnly) =========
else if((l.Action == 50) && (l.Front != null))
{
if(sectortags.ContainsKey(l.Args[0]))
{
List<Sector> sectors = sectortags[l.Args[0]];
foreach(Sector s in sectors)
{
SectorData sd = GetSectorData(s);
sd.AddEffectBrightnessLevel(l);
}
}
}
}
// Find interesting things (such as sector slopes)
foreach(Thing t in General.Map.Map.Things)
{
// ========== Copy slope ==========
if((t.Type == 9510) || (t.Type == 9511))
{
t.DetermineSector(blockmap);
if(t.Sector != null)
{
SectorData sd = GetSectorData(t.Sector);
sd.AddEffectCopySlope(t);
}
}
// ========== Thing line slope ==========
else if((t.Type == 9500) || (t.Type == 9501))
{
t.DetermineSector(blockmap);
if(t.Sector != null)
{
SectorData sd = GetSectorData(t.Sector);
sd.AddEffectThingLineSlope(t);
}
}
// ========== Thing slope ==========
else if((t.Type == 9502) || (t.Type == 9503))
{
t.DetermineSector(blockmap);
if(t.Sector != null)
{
SectorData sd = GetSectorData(t.Sector);
sd.AddEffectThingSlope(t);
}
}
}
}
#endregion
#region ================== Events
// Help!
public override void OnHelp()
{
General.ShowHelp("e_visual.html");
}
codeimp
committed
// When entering this mode
public override void OnEngage()
{
base.OnEngage();
//mxd
useSelectionFromClassicMode = BuilderPlug.Me.SyncSelection ? !General.Interface.ShiftState : General.Interface.ShiftState;
if(useSelectionFromClassicMode) updateSelectionInfo();
// Read settings
cameraflooroffset = General.Map.Config.ReadSetting("cameraflooroffset", cameraflooroffset);
cameraceilingoffset = General.Map.Config.ReadSetting("cameraceilingoffset", cameraceilingoffset);
RebuildElementData();
}
codeimp
committed
// When returning to another mode
public override void OnDisengage()
{
base.OnDisengage();
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//mxd
if(BuilderPlug.Me.SyncSelection ? !General.Interface.ShiftState : General.Interface.ShiftState) {
//clear previously selected stuff
General.Map.Map.ClearAllSelected();
//refill selection
List<Sector> selectedSectors = new List<Sector>();
List<Linedef> selectedLines = new List<Linedef>();
List<Vertex> selectedVertices = new List<Vertex>();
foreach(IVisualEventReceiver obj in selectedobjects) {
if(obj is BaseVisualThing) {
((BaseVisualThing)obj).Thing.Selected = true;
} else if(obj is VisualFloor || obj is VisualCeiling) {
VisualGeometry vg = (VisualGeometry)obj;
if(vg.Sector != null && vg.Sector.Sector != null && !selectedSectors.Contains(vg.Sector.Sector)) {
selectedSectors.Add(vg.Sector.Sector);
foreach(Sidedef s in vg.Sector.Sector.Sidedefs){
if(!selectedLines.Contains(s.Line))
selectedLines.Add(s.Line);
}
}
} else if(obj is VisualLower || obj is VisualUpper || obj is VisualMiddleDouble || obj is VisualMiddleSingle || obj is VisualMiddle3D) {
VisualGeometry vg = (VisualGeometry)obj;
if(vg.Sidedef != null && !selectedLines.Contains(vg.Sidedef.Line))
selectedLines.Add(vg.Sidedef.Line);
}
}
foreach(Sector s in selectedSectors)
s.Selected = true;
foreach(Linedef l in selectedLines) {
l.Selected = true;
if(!selectedVertices.Contains(l.Start))
selectedVertices.Add(l.Start);
if(!selectedVertices.Contains(l.End))
selectedVertices.Add(l.End);
}
foreach(Vertex v in selectedVertices)
v.Selected = true;
}