mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-27 14:12:16 +00:00
2458ea3d32
Changed, internal: made TextLabel and IRenderer2D public properties compatible with DB2 implementation. Fixed some more cases when sidedefs belonging to linedefs, which were moved on top of existing linedefs, were incorrectly reassigned when applying Edit Selection and Drag Geometry modes. Fixed, Map Analysis mode: error checks must be updated after switching map format.
785 lines
23 KiB
C#
785 lines
23 KiB
C#
|
|
#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 CodeImp.DoomBuilder.IO;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using CodeImp.DoomBuilder.Data;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.Map
|
|
{
|
|
public sealed class Sidedef : MapElement
|
|
{
|
|
#region ================== Variables
|
|
|
|
// Map
|
|
private MapSet map;
|
|
|
|
// List items
|
|
private LinkedListNode<Sidedef> sectorlistitem;
|
|
|
|
// Owner
|
|
private Linedef linedef;
|
|
|
|
// Sector
|
|
private Sector sector;
|
|
|
|
// Properties
|
|
private int offsetx;
|
|
private int offsety;
|
|
private string texnamehigh;
|
|
private string texnamemid;
|
|
private string texnamelow;
|
|
private long longtexnamehigh;
|
|
private long longtexnamemid;
|
|
private long longtexnamelow;
|
|
|
|
//mxd. UDMF properties
|
|
private Dictionary<string, bool> flags;
|
|
|
|
// Clone
|
|
private int serializedindex;
|
|
|
|
#endregion
|
|
|
|
#region ================== Properties
|
|
|
|
public MapSet Map { get { return map; } }
|
|
public bool IsFront { get { return (linedef != null) && (this == linedef.Front); } }
|
|
public Linedef Line { get { return linedef; } }
|
|
public Sidedef Other { get { return (this == linedef.Front ? linedef.Back : linedef.Front); } }
|
|
public Sector Sector { get { return sector; } }
|
|
internal Dictionary<string, bool> Flags { get { return flags; } } //mxd
|
|
public float Angle { get { return (IsFront ? linedef.Angle : Angle2D.Normalized(linedef.Angle + Angle2D.PI)); } }
|
|
public int OffsetX { get { return offsetx; } set { BeforePropsChange(); offsetx = value; } }
|
|
public int OffsetY { get { return offsety; } set { BeforePropsChange(); offsety = value; } }
|
|
public string HighTexture { get { return texnamehigh; } }
|
|
public string MiddleTexture { get { return texnamemid; } }
|
|
public string LowTexture { get { return texnamelow; } }
|
|
public long LongHighTexture { get { return longtexnamehigh; } }
|
|
public long LongMiddleTexture { get { return longtexnamemid; } }
|
|
public long LongLowTexture { get { return longtexnamelow; } }
|
|
internal int SerializedIndex { get { return serializedindex; } set { serializedindex = value; } }
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
// Constructor
|
|
internal Sidedef(MapSet map, int listindex, Linedef l, bool front, Sector s)
|
|
{
|
|
// Initialize
|
|
this.elementtype = MapElementType.SIDEDEF; //mxd
|
|
this.map = map;
|
|
this.listindex = listindex;
|
|
this.texnamehigh = "-";
|
|
this.texnamemid = "-";
|
|
this.texnamelow = "-";
|
|
this.longtexnamehigh = MapSet.EmptyLongName;
|
|
this.longtexnamemid = MapSet.EmptyLongName;
|
|
this.longtexnamelow = MapSet.EmptyLongName;
|
|
this.flags = new Dictionary<string, bool>(StringComparer.Ordinal); //mxd
|
|
|
|
// Attach linedef
|
|
this.linedef = l;
|
|
if(l != null)
|
|
{
|
|
if(front)
|
|
l.AttachFrontP(this);
|
|
else
|
|
l.AttachBackP(this);
|
|
}
|
|
|
|
// Attach sector
|
|
SetSectorP(s);
|
|
|
|
if(map == General.Map.Map)
|
|
General.Map.UndoRedo.RecAddSidedef(this);
|
|
|
|
// We have no destructor
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
// Disposer
|
|
public override void Dispose()
|
|
{
|
|
// Not already disposed?
|
|
if(!isdisposed)
|
|
{
|
|
// Already set isdisposed so that changes can be prohibited
|
|
isdisposed = true;
|
|
|
|
if(map == General.Map.Map)
|
|
General.Map.UndoRedo.RecRemSidedef(this);
|
|
|
|
// Remove from main list
|
|
map.RemoveSidedef(listindex);
|
|
|
|
// Detach from linedef
|
|
if(linedef != null) linedef.DetachSidedefP(this);
|
|
|
|
// Detach from sector
|
|
SetSectorP(null);
|
|
|
|
// Clean up
|
|
sectorlistitem = null;
|
|
linedef = null;
|
|
map = null;
|
|
sector = null;
|
|
|
|
//mxd. Restore isdisposed so base classes can do their disposal job
|
|
isdisposed = false;
|
|
|
|
// Dispose base
|
|
base.Dispose();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Management
|
|
|
|
// Call this before changing properties
|
|
protected override void BeforePropsChange()
|
|
{
|
|
if(map == General.Map.Map)
|
|
General.Map.UndoRedo.RecPrpSidedef(this);
|
|
}
|
|
|
|
// Serialize / deserialize (passive: this doesn't record)
|
|
new internal void ReadWrite(IReadWriteStream s)
|
|
{
|
|
if(!s.IsWriting) BeforePropsChange();
|
|
|
|
base.ReadWrite(s);
|
|
|
|
//mxd
|
|
if(s.IsWriting)
|
|
{
|
|
s.wInt(flags.Count);
|
|
|
|
foreach(KeyValuePair<string, bool> f in flags)
|
|
{
|
|
s.wString(f.Key);
|
|
s.wBool(f.Value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int c;
|
|
s.rInt(out c);
|
|
|
|
flags = new Dictionary<string, bool>(c, StringComparer.Ordinal);
|
|
for(int i = 0; i < c; i++)
|
|
{
|
|
string t;
|
|
s.rString(out t);
|
|
bool b;
|
|
s.rBool(out b);
|
|
flags.Add(t, b);
|
|
}
|
|
}
|
|
|
|
s.rwInt(ref offsetx);
|
|
s.rwInt(ref offsety);
|
|
s.rwString(ref texnamehigh);
|
|
s.rwString(ref texnamemid);
|
|
s.rwString(ref texnamelow);
|
|
s.rwLong(ref longtexnamehigh);
|
|
s.rwLong(ref longtexnamemid);
|
|
s.rwLong(ref longtexnamelow);
|
|
}
|
|
|
|
// This copies all properties to another sidedef
|
|
public void CopyPropertiesTo(Sidedef s)
|
|
{
|
|
s.BeforePropsChange();
|
|
|
|
// Copy properties
|
|
s.offsetx = offsetx;
|
|
s.offsety = offsety;
|
|
s.texnamehigh = texnamehigh;
|
|
s.texnamemid = texnamemid;
|
|
s.texnamelow = texnamelow;
|
|
s.longtexnamehigh = longtexnamehigh;
|
|
s.longtexnamemid = longtexnamemid;
|
|
s.longtexnamelow = longtexnamelow;
|
|
s.flags = new Dictionary<string, bool>(flags); //mxd
|
|
base.CopyPropertiesTo(s);
|
|
}
|
|
|
|
// This changes sector
|
|
public void SetSector(Sector newsector)
|
|
{
|
|
if(map == General.Map.Map)
|
|
General.Map.UndoRedo.RecRefSidedefSector(this);
|
|
|
|
// Change sector
|
|
SetSectorP(newsector);
|
|
}
|
|
|
|
internal void SetSectorP(Sector newsector)
|
|
{
|
|
// Detach from sector
|
|
if(sector != null && !sector.IsDisposed) //mxd
|
|
sector.DetachSidedefP(sectorlistitem);
|
|
|
|
// Change sector
|
|
sector = newsector;
|
|
|
|
// Attach to sector
|
|
if(sector != null && !sector.IsDisposed) //mxd
|
|
sectorlistitem = sector.AttachSidedefP(this);
|
|
|
|
General.Map.IsChanged = true;
|
|
}
|
|
|
|
// This sets the linedef
|
|
public void SetLinedef(Linedef ld, bool front)
|
|
{
|
|
if(linedef != null) linedef.DetachSidedefP(this);
|
|
|
|
if(ld != null)
|
|
{
|
|
if(front)
|
|
ld.AttachFront(this);
|
|
else
|
|
ld.AttachBack(this);
|
|
}
|
|
}
|
|
|
|
// This sets the linedef (passive: this doesn't tell the linedef and doesn't record)
|
|
internal void SetLinedefP(Linedef ld)
|
|
{
|
|
linedef = ld;
|
|
}
|
|
|
|
//mxd. This translates UDMF fields back into the normal flags and activations
|
|
internal void TranslateFromUDMF()
|
|
{
|
|
// Try to translate UDMF texture offsets to regular ones
|
|
if(longtexnamemid != MapSet.EmptyLongName && MiddleRequired())
|
|
{
|
|
offsetx += (int)UniFields.GetFloat(this.Fields, "offsetx_mid");
|
|
offsety += (int)UniFields.GetFloat(this.Fields, "offsety_mid");
|
|
}
|
|
else if(longtexnamehigh != MapSet.EmptyLongName && HighRequired())
|
|
{
|
|
offsetx += (int)UniFields.GetFloat(this.Fields, "offsetx_top");
|
|
offsety += (int)UniFields.GetFloat(this.Fields, "offsety_top");
|
|
}
|
|
else if(longtexnamelow != MapSet.EmptyLongName && LowRequired())
|
|
{
|
|
offsetx += (int)UniFields.GetFloat(this.Fields, "offsetx_bottom");
|
|
offsety += (int)UniFields.GetFloat(this.Fields, "offsety_bottom");
|
|
}
|
|
|
|
// Clear UDMF-related properties
|
|
this.Fields.Clear();
|
|
this.Flags.Clear();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Methods
|
|
|
|
// This checks and returns a flag without creating it
|
|
public bool IsFlagSet(string flagname)
|
|
{
|
|
return (flags.ContainsKey(flagname) && flags[flagname]);
|
|
}
|
|
|
|
// This sets a flag
|
|
public void SetFlag(string flagname, bool value)
|
|
{
|
|
if(!flags.ContainsKey(flagname) || (IsFlagSet(flagname) != value))
|
|
{
|
|
BeforePropsChange();
|
|
flags[flagname] = value;
|
|
}
|
|
}
|
|
|
|
// This returns a copy of the flags dictionary
|
|
public Dictionary<string, bool> GetFlags()
|
|
{
|
|
return new Dictionary<string, bool>(flags);
|
|
}
|
|
|
|
// This clears all flags
|
|
public void ClearFlags()
|
|
{
|
|
BeforePropsChange();
|
|
flags.Clear();
|
|
}
|
|
|
|
// This removes textures that are not required
|
|
public void RemoveUnneededTextures(bool removemiddle)
|
|
{
|
|
RemoveUnneededTextures(removemiddle, false, false);
|
|
}
|
|
|
|
// This removes textures that are not required
|
|
public void RemoveUnneededTextures(bool removemiddle, bool force)
|
|
{
|
|
RemoveUnneededTextures(removemiddle, force, false);
|
|
}
|
|
|
|
// This removes textures that are not required
|
|
public void RemoveUnneededTextures(bool removemiddle, bool force, bool shiftmiddle)
|
|
{
|
|
bool changed = false; //mxd
|
|
|
|
// Check if the line or sectors have no action or tags because
|
|
// if they do, any texture on this side could be needed
|
|
if(force || ((linedef.Tag == 0) && (linedef.Action == 0) && (sector.Tag == 0) &&
|
|
((Other == null) || (Other.sector.Tag == 0))))
|
|
{
|
|
if(!HighRequired())
|
|
{
|
|
BeforePropsChange(); //mxd
|
|
changed = true;
|
|
this.texnamehigh = "-";
|
|
this.longtexnamehigh = MapSet.EmptyLongName;
|
|
General.Map.IsChanged = true;
|
|
}
|
|
else if(shiftmiddle && this.longtexnamehigh == MapSet.EmptyLongName) //mxd
|
|
{
|
|
SetTextureHigh(this.texnamemid);
|
|
changed = true;
|
|
}
|
|
|
|
if(!LowRequired())
|
|
{
|
|
if(!changed) //mxd
|
|
{
|
|
BeforePropsChange();
|
|
changed = true;
|
|
}
|
|
this.texnamelow = "-";
|
|
this.longtexnamelow = MapSet.EmptyLongName;
|
|
General.Map.IsChanged = true;
|
|
}
|
|
else if(shiftmiddle && this.longtexnamelow == MapSet.EmptyLongName) //mxd
|
|
{
|
|
SetTextureLow(this.texnamemid);
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
// The middle texture can be removed regardless of any sector tag or linedef action
|
|
if(!MiddleRequired() && removemiddle)
|
|
{
|
|
if(!changed) BeforePropsChange(); //mxd
|
|
this.texnamemid = "-";
|
|
this.longtexnamemid = MapSet.EmptyLongName;
|
|
General.Map.IsChanged = true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This checks if a texture is required
|
|
/// </summary>
|
|
public bool HighRequired()
|
|
{
|
|
// Doublesided?
|
|
if(Other != null)
|
|
{
|
|
//mxd. Check sloped ceilings...
|
|
if(General.Map.UDMF && this.sector != Other.Sector)
|
|
{
|
|
float thisstartz = this.sector.CeilHeight;
|
|
float thisendz = this.sector.CeilHeight;
|
|
float otherstartz = Other.sector.CeilHeight;
|
|
float otherendz = Other.sector.CeilHeight;
|
|
|
|
// Check if this side is affected by UDMF slope (it overrides vertex heights, riiiiiight?..) TODO: check this!
|
|
if(this.sector.CeilSlope.GetLengthSq() > 0)
|
|
{
|
|
Plane ceil = new Plane(this.sector.CeilSlope, this.sector.CeilSlopeOffset);
|
|
thisstartz = ceil.GetZ(this.Line.Start.Position);
|
|
thisendz = ceil.GetZ(this.Line.End.Position);
|
|
}
|
|
else if(this.sector.Sidedefs.Count == 3) // Check vertex heights on this side
|
|
{
|
|
if(!float.IsNaN(this.Line.Start.ZCeiling)) thisstartz = this.Line.Start.ZCeiling;
|
|
if(!float.IsNaN(this.Line.End.ZCeiling)) thisendz = this.Line.End.ZCeiling;
|
|
}
|
|
|
|
// Check if other side is affected by UDMF slope (it overrides vertex heights, riiiiiight?..) TODO: check this!
|
|
if(Other.sector.CeilSlope.GetLengthSq() > 0)
|
|
{
|
|
Plane ceil = new Plane(Other.sector.CeilSlope, Other.sector.CeilSlopeOffset);
|
|
otherstartz = ceil.GetZ(this.Line.Start.Position);
|
|
otherendz = ceil.GetZ(this.Line.End.Position);
|
|
}
|
|
else if(Other.sector.Sidedefs.Count == 3) // Check other line's vertex heights
|
|
{
|
|
if(!float.IsNaN(this.Line.Start.ZCeiling)) otherstartz = this.Line.Start.ZCeiling;
|
|
if(!float.IsNaN(this.Line.End.ZCeiling)) otherendz = this.Line.End.ZCeiling;
|
|
}
|
|
|
|
// Texture is required when our start or end vertex is higher than on the other side.
|
|
if(thisstartz > otherstartz || thisendz > otherendz) return true;
|
|
}
|
|
|
|
// Texture is required when ceiling of other side is lower
|
|
return (Other.sector.CeilHeight < this.sector.CeilHeight);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This checks if a texture is required
|
|
/// </summary>
|
|
public bool MiddleRequired()
|
|
{
|
|
// Texture is required when the line is singlesided
|
|
return (Other == null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// This checks if a texture is required
|
|
/// </summary>
|
|
public bool LowRequired()
|
|
{
|
|
// Doublesided?
|
|
if(Other != null)
|
|
{
|
|
//mxd. Check sloped floors...
|
|
if(General.Map.UDMF && this.sector != Other.Sector)
|
|
{
|
|
float thisstartz = this.sector.FloorHeight;
|
|
float thisendz = this.sector.FloorHeight;
|
|
float otherstartz = Other.sector.FloorHeight;
|
|
float otherendz = Other.sector.FloorHeight;
|
|
|
|
// Check if this side is affected by UDMF slope (it overrides vertex heights, riiiiiight?..) TODO: check this!
|
|
if(this.sector.FloorSlope.GetLengthSq() > 0)
|
|
{
|
|
Plane floor = new Plane(this.sector.FloorSlope, this.sector.FloorSlopeOffset);
|
|
thisstartz = floor.GetZ(this.Line.Start.Position);
|
|
thisendz = floor.GetZ(this.Line.End.Position);
|
|
}
|
|
else if(this.sector.Sidedefs.Count == 3) // Check vertex heights on this side
|
|
{
|
|
if(!float.IsNaN(this.Line.Start.ZFloor)) thisstartz = this.Line.Start.ZFloor;
|
|
if(!float.IsNaN(this.Line.End.ZFloor)) thisendz = this.Line.End.ZFloor;
|
|
}
|
|
|
|
// Check if other side is affected by UDMF slope (it overrides vertex heights, riiiiiight?..) TODO: check this!
|
|
if(Other.sector.FloorSlope.GetLengthSq() > 0)
|
|
{
|
|
Plane floor = new Plane(Other.sector.FloorSlope, Other.sector.FloorSlopeOffset);
|
|
otherstartz = floor.GetZ(this.Line.Start.Position);
|
|
otherendz = floor.GetZ(this.Line.End.Position);
|
|
}
|
|
else if(Other.sector.Sidedefs.Count == 3) // Check other line's vertex heights
|
|
{
|
|
if(!float.IsNaN(this.Line.Start.ZFloor)) otherstartz = this.Line.Start.ZFloor;
|
|
if(!float.IsNaN(this.Line.End.ZFloor)) otherendz = this.Line.End.ZFloor;
|
|
}
|
|
|
|
// Texture is required when our start or end vertex is lower than on the other side.
|
|
if(thisstartz < otherstartz || thisendz < otherendz) return true;
|
|
}
|
|
|
|
// Texture is required when floor of other side is higher
|
|
return (Other.sector.FloorHeight > this.sector.FloorHeight);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This returns the height of the upper wall part. Returns 0 when no upper part exists.
|
|
/// </summary>
|
|
public int GetHighHeight()
|
|
{
|
|
Sidedef other = this.Other;
|
|
if(other != null)
|
|
{
|
|
int top = this.sector.CeilHeight;
|
|
int bottom = other.sector.CeilHeight;
|
|
int height = top - bottom;
|
|
return (height > 0) ? height : 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This returns the height of the middle wall part.
|
|
/// </summary>
|
|
public int GetMiddleHeight()
|
|
{
|
|
Sidedef other = this.Other;
|
|
if(other != null)
|
|
{
|
|
int top = Math.Min(this.Sector.CeilHeight, other.Sector.CeilHeight);
|
|
int bottom = Math.Max(this.Sector.FloorHeight, other.Sector.FloorHeight);
|
|
int height = top - bottom;
|
|
return (height > 0) ? height : 0;
|
|
}
|
|
else
|
|
{
|
|
int top = this.Sector.CeilHeight;
|
|
int bottom = this.Sector.FloorHeight;
|
|
int height = top - bottom;
|
|
return (height > 0) ? height : 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This returns the height of the lower wall part. Returns 0 when no lower part exists.
|
|
/// </summary>
|
|
public int GetLowHeight()
|
|
{
|
|
Sidedef other = this.Other;
|
|
if(other != null)
|
|
{
|
|
int top = other.sector.FloorHeight;
|
|
int bottom = this.sector.FloorHeight;
|
|
int height = top - bottom;
|
|
return (height > 0) ? height : 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// This creates a checksum from the sidedef properties
|
|
// Used for faster sidedefs compression
|
|
public uint GetChecksum()
|
|
{
|
|
CRC crc = new CRC();
|
|
crc.Add(sector.FixedIndex);
|
|
crc.Add(offsetx);
|
|
crc.Add(offsety);
|
|
crc.Add(longtexnamehigh);
|
|
crc.Add(longtexnamelow);
|
|
crc.Add(longtexnamemid);
|
|
return (uint)(crc.Value & 0x00000000FFFFFFFF);
|
|
}
|
|
|
|
// This copies textures to another sidedef
|
|
// And possibly also the offsets
|
|
public void AddTexturesTo(Sidedef s)
|
|
{
|
|
int copyoffsets = 0;
|
|
|
|
// s cannot be null
|
|
if(s == null) return;
|
|
|
|
s.BeforePropsChange();
|
|
|
|
// Upper texture set?
|
|
if((texnamehigh.Length > 0) && (texnamehigh != "-"))
|
|
{
|
|
// Copy upper texture
|
|
s.texnamehigh = texnamehigh;
|
|
s.longtexnamehigh = longtexnamehigh;
|
|
|
|
// Counts as a half coice for copying offsets
|
|
copyoffsets += 1;
|
|
|
|
//mxd. Also copy UDMF offsets and scale
|
|
if(General.Map.UDMF)
|
|
{
|
|
UniFields.SetFloat(s.Fields, "offsetx_top", Fields.GetValue("offsetx_top", 0f), 0f);
|
|
UniFields.SetFloat(s.Fields, "offsety_top", Fields.GetValue("offsety_top", 0f), 0f);
|
|
UniFields.SetFloat(s.Fields, "scalex_top", Fields.GetValue("scalex_top", 1.0f), 1.0f);
|
|
UniFields.SetFloat(s.Fields, "scaley_top", Fields.GetValue("scaley_top", 1.0f), 1.0f);
|
|
}
|
|
}
|
|
|
|
// Middle texture set?
|
|
if((texnamemid.Length > 0) && (texnamemid != "-"))
|
|
{
|
|
// Copy middle texture
|
|
s.texnamemid = texnamemid;
|
|
s.longtexnamemid = longtexnamemid;
|
|
|
|
// Counts for copying offsets
|
|
copyoffsets += 2;
|
|
|
|
//mxd. Also copy UDMF offsets and scale
|
|
if(General.Map.UDMF)
|
|
{
|
|
UniFields.SetFloat(s.Fields, "offsetx_mid", Fields.GetValue("offsetx_mid", 0f), 0f);
|
|
UniFields.SetFloat(s.Fields, "offsety_mid", Fields.GetValue("offsety_mid", 0f), 0f);
|
|
UniFields.SetFloat(s.Fields, "scalex_mid", Fields.GetValue("scalex_mid", 1.0f), 1.0f);
|
|
UniFields.SetFloat(s.Fields, "scaley_mid", Fields.GetValue("scaley_mid", 1.0f), 1.0f);
|
|
}
|
|
}
|
|
|
|
// Lower texture set?
|
|
if((texnamelow.Length > 0) && (texnamelow != "-"))
|
|
{
|
|
// Copy middle texture
|
|
s.texnamelow = texnamelow;
|
|
s.longtexnamelow = longtexnamelow;
|
|
|
|
// Counts as a half coice for copying offsets
|
|
copyoffsets += 1;
|
|
|
|
//mxd. Also copy UDMF offsets and scale
|
|
if(General.Map.UDMF)
|
|
{
|
|
UniFields.SetFloat(s.Fields, "offsetx_bottom", Fields.GetValue("offsetx_bottom", 0f), 0f);
|
|
UniFields.SetFloat(s.Fields, "offsety_bottom", Fields.GetValue("offsety_bottom", 0f), 0f);
|
|
UniFields.SetFloat(s.Fields, "scalex_bottom", Fields.GetValue("scalex_bottom", 1.0f), 1.0f);
|
|
UniFields.SetFloat(s.Fields, "scaley_bottom", Fields.GetValue("scaley_bottom", 1.0f), 1.0f);
|
|
}
|
|
}
|
|
|
|
// Copy offsets also?
|
|
if(copyoffsets >= 2)
|
|
{
|
|
// Copy offsets
|
|
s.offsetx = offsetx;
|
|
s.offsety = offsety;
|
|
}
|
|
|
|
General.Map.IsChanged = true;
|
|
}
|
|
|
|
//mxd. String representation
|
|
public override string ToString()
|
|
{
|
|
#if DEBUG
|
|
return "Sidedef " + listindex + (marked ? " (marked)" : "") + " (Line " + linedef.Index + (linedef.Marked ? " (marked)" : "") + ", Sector " + sector.Index + (sector.Marked ? " (marked)" : "") + ")";
|
|
#else
|
|
return "Sidedef " + listindex;
|
|
#endif
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region ================== Changes
|
|
|
|
// This updates all properties
|
|
public void Update(int offsetx, int offsety, string thigh, string tmid, string tlow)
|
|
{
|
|
Update(offsetx, offsety, thigh, tmid, tlow, new Dictionary<string, bool>(StringComparer.Ordinal));
|
|
}
|
|
|
|
//mxd. This updates all properties (UDMF version)
|
|
public void Update(int offsetx, int offsety, string thigh, string tmid, string tlow, Dictionary<string, bool> flags)
|
|
{
|
|
BeforePropsChange();
|
|
|
|
// Apply changes
|
|
this.offsetx = offsetx;
|
|
this.offsety = offsety;
|
|
this.flags = new Dictionary<string, bool>(flags); //mxd
|
|
//SetTextureMid(tmid);
|
|
//SetTextureLow(tlow);
|
|
//SetTextureHigh(thigh);
|
|
|
|
//mxd. Set mid texture
|
|
texnamemid = string.IsNullOrEmpty(tmid) ? "-" : tmid;
|
|
longtexnamemid = Lump.MakeLongName(tmid);
|
|
|
|
//mxd. Set low texture
|
|
texnamelow = string.IsNullOrEmpty(tlow) ? "-" : tlow;
|
|
longtexnamelow = Lump.MakeLongName(tlow);
|
|
|
|
//mxd. Set high texture
|
|
texnamehigh = string.IsNullOrEmpty(thigh) ? "-" : thigh;
|
|
longtexnamehigh = Lump.MakeLongName(texnamehigh);
|
|
|
|
//mxd. Map is changed
|
|
General.Map.IsChanged = true;
|
|
}
|
|
|
|
// This sets texture
|
|
public void SetTextureHigh(string name)
|
|
{
|
|
BeforePropsChange();
|
|
|
|
texnamehigh = string.IsNullOrEmpty(name) ? "-" : name; //mxd
|
|
longtexnamehigh = Lump.MakeLongName(name);
|
|
General.Map.IsChanged = true;
|
|
}
|
|
|
|
// This sets texture
|
|
public void SetTextureMid(string name)
|
|
{
|
|
BeforePropsChange();
|
|
|
|
texnamemid = string.IsNullOrEmpty(name) ? "-" : name; //mxd;
|
|
longtexnamemid = Lump.MakeLongName(name);
|
|
General.Map.IsChanged = true;
|
|
}
|
|
|
|
// This sets texture
|
|
public void SetTextureLow(string name)
|
|
{
|
|
BeforePropsChange();
|
|
|
|
texnamelow = string.IsNullOrEmpty(name) ? "-" : name; //mxd;
|
|
longtexnamelow = Lump.MakeLongName(name);
|
|
General.Map.IsChanged = true;
|
|
}
|
|
|
|
// This sets udmf texture offset
|
|
public void SetUdmfTextureOffsetX(int offset)
|
|
{
|
|
this.Fields.BeforeFieldsChange();
|
|
|
|
//top
|
|
if(longtexnamehigh != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(texnamehigh))
|
|
{
|
|
ImageData texture = General.Map.Data.GetTextureImage(texnamehigh);
|
|
float scaleTop = Fields.GetValue("scalex_top", 1.0f);
|
|
|
|
float value = Fields.GetValue("offsetx_top", 0f);
|
|
float result = (float)(Math.Round(value + offset * scaleTop) % texture.Width);
|
|
UniFields.SetFloat(Fields, "offsetx_top", result);
|
|
}
|
|
|
|
//middle
|
|
if(longtexnamemid != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(texnamemid))
|
|
{
|
|
ImageData texture = General.Map.Data.GetTextureImage(texnamemid);
|
|
float scaleMid = Fields.GetValue("scalex_mid", 1.0f);
|
|
|
|
float value = Fields.GetValue("offsetx_mid", 0f);
|
|
float result = (float)(Math.Round(value + offset * scaleMid) % texture.Width);
|
|
UniFields.SetFloat(Fields, "offsetx_mid", result);
|
|
}
|
|
|
|
//bottom
|
|
if(longtexnamelow != MapSet.EmptyLongName && General.Map.Data.GetTextureExists(texnamelow))
|
|
{
|
|
ImageData texture = General.Map.Data.GetTextureImage(texnamelow);
|
|
float scaleLow = Fields.GetValue("scalex_bottom", 1.0f);
|
|
|
|
float value = Fields.GetValue("offsetx_bottom", 0f);
|
|
float result = (float)(Math.Round(value + offset * scaleLow) % texture.Width);
|
|
UniFields.SetFloat(Fields, "offsetx_bottom", result);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|