mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-26 22:01:45 +00:00
Added: Map Analysis: added "Check texture alignment" check. Currently it works only in Doom/Hexen map formats.
This commit is contained in:
parent
cc1c407756
commit
88ae568836
9 changed files with 440 additions and 61 deletions
|
@ -1760,6 +1760,57 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
((sd.LongMiddleTexture == texturelongname) && (sd.MiddleRequired() || sd.LongMiddleTexture != MapSet.EmptyLongName)) ;
|
||||
}
|
||||
|
||||
//mxd. This converts offsetY from/to "normalized" offset for given upper wall
|
||||
public static float GetSidedefTopOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized)
|
||||
{
|
||||
if(side.Line.IsFlagSet(General.Map.Config.UpperUnpeggedFlag) || side.Other == null || side.Other.Sector == null)
|
||||
return offset;
|
||||
|
||||
//if we don't have UpperUnpegged flag, normalize offset
|
||||
float surfaceHeight = (side.Sector.CeilHeight - side.Other.Sector.CeilHeight) * scaleY;
|
||||
|
||||
if(fromNormalized) return (float)Math.Round(offset + surfaceHeight);
|
||||
return (float)Math.Round(offset - surfaceHeight);
|
||||
}
|
||||
|
||||
//mxd. This converts offsetY from/to "normalized" offset for given middle wall
|
||||
public static float GetSidedefMiddleOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized)
|
||||
{
|
||||
if(!side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag) || side.Sector == null)
|
||||
return offset;
|
||||
|
||||
// If we have LowerUnpegged flag, normalize offset
|
||||
// Absolute value is used because ceiling height of vavoom-type 3d floors
|
||||
// is lower than floor height
|
||||
float surfaceHeight = (Math.Abs(side.Sector.CeilHeight - side.Sector.FloorHeight)) * scaleY;
|
||||
|
||||
if(fromNormalized) return (float)Math.Round(offset + surfaceHeight);
|
||||
return (float)Math.Round(offset - surfaceHeight);
|
||||
}
|
||||
|
||||
//mxd. This converts offsetY from/to "normalized" offset for given lower wall
|
||||
public static float GetSidedefBottomOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized)
|
||||
{
|
||||
float surfaceHeight;
|
||||
if(side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag))
|
||||
{
|
||||
if(side.Other == null || side.Other.Sector == null || side.Sector.CeilTexture != General.Map.Config.SkyFlatName ||
|
||||
side.Other.Sector.CeilTexture != General.Map.Config.SkyFlatName)
|
||||
return offset;
|
||||
|
||||
//normalize offset the way Doom does it when front and back sector's ceiling is sky
|
||||
surfaceHeight = (side.Sector.CeilHeight - side.Other.Sector.CeilHeight) * scaleY;
|
||||
}
|
||||
else
|
||||
{
|
||||
//normalize offset
|
||||
surfaceHeight = (side.Sector.CeilHeight - side.Other.Sector.FloorHeight) * scaleY;
|
||||
}
|
||||
|
||||
if(fromNormalized) return (float)Math.Round(offset + surfaceHeight);
|
||||
return (float)Math.Round(offset - surfaceHeight);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Tags and Actions
|
||||
|
|
|
@ -232,6 +232,7 @@
|
|||
<Compile Include="ErrorChecks\CheckMissingTextures.cs" />
|
||||
<Compile Include="ErrorChecks\CheckOverlappingVertices.cs" />
|
||||
<Compile Include="ErrorChecks\CheckStrayVertices.cs" />
|
||||
<Compile Include="ErrorChecks\CheckTextureAlignment.cs" />
|
||||
<Compile Include="ErrorChecks\CheckUnknownFlats.cs" />
|
||||
<Compile Include="ErrorChecks\CheckUnknownTextures.cs" />
|
||||
<Compile Include="ErrorChecks\CheckUnknownThings.cs" />
|
||||
|
@ -242,6 +243,7 @@
|
|||
<Compile Include="ErrorChecks\ResultStrayVertex.cs" />
|
||||
<Compile Include="ErrorChecks\ResultStuckThingInThing.cs" />
|
||||
<Compile Include="ErrorChecks\ResultMissingTexture.cs" />
|
||||
<Compile Include="ErrorChecks\ResultTexturesMisaligned.cs" />
|
||||
<Compile Include="ErrorChecks\ResultUnknownFlat.cs" />
|
||||
<Compile Include="ErrorChecks\ResultUnknownTexture.cs" />
|
||||
<Compile Include="ErrorChecks\ResultUnknownThing.cs" />
|
||||
|
|
278
Source/Plugins/BuilderModes/ErrorChecks/CheckTextureAlignment.cs
Normal file
278
Source/Plugins/BuilderModes/ErrorChecks/CheckTextureAlignment.cs
Normal file
|
@ -0,0 +1,278 @@
|
|||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using CodeImp.DoomBuilder.Data;
|
||||
using CodeImp.DoomBuilder.Geometry;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.VisualModes;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.BuilderModes.ErrorChecks
|
||||
{
|
||||
[ErrorChecker("Check texture alignment", true, 1000)]
|
||||
public class CheckTextureAlignment : ErrorChecker
|
||||
{
|
||||
#region ================== Constants
|
||||
|
||||
private const int PROGRESS_STEP = 100;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Destructor
|
||||
|
||||
// Constructor
|
||||
public CheckTextureAlignment()
|
||||
{
|
||||
// Total progress is done when all lines are checked
|
||||
SetTotalProgress(General.Map.Map.Linedefs.Count / PROGRESS_STEP);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This runs the check
|
||||
public override void Run()
|
||||
{
|
||||
Dictionary<int, Dictionary<int, bool>> donesides = new Dictionary<int, Dictionary<int, bool>>();
|
||||
int progress = 0;
|
||||
int stepprogress = 0;
|
||||
bool udmf = General.Map.UDMF;
|
||||
|
||||
// Go for all the liendefs
|
||||
foreach(Linedef l in General.Map.Map.Linedefs)
|
||||
{
|
||||
// Check if not already done
|
||||
if (donesides.ContainsKey(l.Index)) continue;
|
||||
|
||||
// Check if we need to align any part of the front sidedef
|
||||
if (l.Front != null)
|
||||
{
|
||||
CheckTopAlignment(l.Front, donesides, udmf);
|
||||
CheckMiddleAlignment(l.Front, donesides, udmf);
|
||||
CheckBottomAlignment(l.Front, donesides, udmf);
|
||||
}
|
||||
|
||||
// Check if we need to align any part of the back sidedef
|
||||
if (l.Back != null)
|
||||
{
|
||||
CheckTopAlignment(l.Back, donesides, udmf);
|
||||
CheckMiddleAlignment(l.Back, donesides, udmf);
|
||||
CheckBottomAlignment(l.Back, donesides, udmf);
|
||||
}
|
||||
|
||||
// Handle thread interruption
|
||||
try { Thread.Sleep(0); } catch(ThreadInterruptedException) { return; }
|
||||
|
||||
// We are making progress!
|
||||
if ((++progress / PROGRESS_STEP) > stepprogress)
|
||||
{
|
||||
stepprogress = (progress / PROGRESS_STEP);
|
||||
AddProgress(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== UDMF alignment checks
|
||||
|
||||
private void CheckTopAlignment(Sidedef sidedef, Dictionary<int, Dictionary<int, bool>> donesides, bool udmf)
|
||||
{
|
||||
if (!sidedef.HighRequired() || sidedef.LongHighTexture == MapSet.EmptyLongName) return;
|
||||
if (!udmf)
|
||||
{
|
||||
CheckClassicTopAlignment(sidedef, donesides);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void CheckMiddleAlignment(Sidedef sidedef, Dictionary<int, Dictionary<int, bool>> donesides, bool udmf)
|
||||
{
|
||||
if (!sidedef.MiddleRequired() || sidedef.LongMiddleTexture == MapSet.EmptyLongName) return;
|
||||
if (!udmf)
|
||||
{
|
||||
CheckClassicMiddleAlignment(sidedef, donesides);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void CheckBottomAlignment(Sidedef sidedef, Dictionary<int, Dictionary<int, bool>> donesides, bool udmf)
|
||||
{
|
||||
if (!sidedef.LowRequired() || sidedef.LongLowTexture == MapSet.EmptyLongName) return;
|
||||
if (!udmf)
|
||||
{
|
||||
CheckClassicBottomAlignment(sidedef, donesides);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void AddProcessedSides(Sidedef s1, Sidedef s2, Dictionary<int, Dictionary<int, bool>> donesides)
|
||||
{
|
||||
// Add them both ways
|
||||
if (!donesides.ContainsKey(s1.Index)) donesides.Add(s1.Index, new Dictionary<int, bool>());
|
||||
donesides[s1.Index].Add(s2.Index, false);
|
||||
|
||||
if (!donesides.ContainsKey(s2.Index)) donesides.Add(s2.Index, new Dictionary<int, bool>());
|
||||
donesides[s2.Index].Add(s1.Index, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Classic alignment checks
|
||||
|
||||
private void CheckClassicTopAlignment(Sidedef sidedef, Dictionary<int, Dictionary<int, bool>> donesides)
|
||||
{
|
||||
int x = sidedef.OffsetX;
|
||||
int y = (int)Tools.GetSidedefTopOffsetY(sidedef, sidedef.OffsetY, 1.0f, false);
|
||||
CheckClassicAlignment(sidedef, x, y, BuilderModesTools.GetSidedefPartSize(sidedef, VisualGeometryType.WALL_UPPER), sidedef.HighTexture, donesides);
|
||||
}
|
||||
|
||||
private void CheckClassicMiddleAlignment(Sidedef sidedef, Dictionary<int, Dictionary<int, bool>> donesides)
|
||||
{
|
||||
int x = sidedef.OffsetX;
|
||||
int y = (int)Tools.GetSidedefMiddleOffsetY(sidedef, sidedef.OffsetY, 1.0f, false);
|
||||
CheckClassicAlignment(sidedef, x, y, BuilderModesTools.GetSidedefPartSize(sidedef, VisualGeometryType.WALL_MIDDLE), sidedef.MiddleTexture, donesides);
|
||||
}
|
||||
|
||||
private void CheckClassicBottomAlignment(Sidedef sidedef, Dictionary<int, Dictionary<int, bool>> donesides)
|
||||
{
|
||||
int x = sidedef.OffsetX;
|
||||
int y = (int)Tools.GetSidedefBottomOffsetY(sidedef, sidedef.OffsetY, 1.0f, false);
|
||||
CheckClassicAlignment(sidedef, x, y, BuilderModesTools.GetSidedefPartSize(sidedef, VisualGeometryType.WALL_LOWER), sidedef.LowTexture, donesides);
|
||||
}
|
||||
|
||||
private void CheckClassicAlignment(Sidedef sidedef, int offsetx, int offsety, Rectangle partsize, string texturename, Dictionary<int, Dictionary<int, bool>> donesides)
|
||||
{
|
||||
ImageData texture = General.Map.Data.GetTextureImage(texturename);
|
||||
if (!texture.IsImageLoaded) return;
|
||||
|
||||
float scalex = (General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.x : 1.0f;
|
||||
float scaley = (General.Map.Config.ScaledTextureOffsets && !texture.WorldPanning) ? texture.Scale.y : 1.0f;
|
||||
|
||||
// Move offsets to proper range
|
||||
offsetx %= texture.Width;
|
||||
if (offsetx < 0) offsetx += texture.Width;
|
||||
offsety %= texture.Height;
|
||||
if (offsety < 0) offsety += texture.Height;
|
||||
|
||||
// Check if current line is aligned to other sides
|
||||
ICollection<Linedef> lines = (sidedef.IsFront ? sidedef.Line.Start.Linedefs : sidedef.Line.End.Linedefs);
|
||||
Vertex v = sidedef.IsFront ? sidedef.Line.Start : sidedef.Line.End;
|
||||
|
||||
foreach(Linedef line in lines)
|
||||
{
|
||||
if (line.Index == sidedef.Line.Index) continue;
|
||||
|
||||
Sidedef target = null;
|
||||
if (line.Front != null && line.End == v) target = line.Front;
|
||||
else if (line.Back != null && line.Start == v) target = line.Back;
|
||||
|
||||
// No target or laready processed?
|
||||
if (target == null || (donesides.ContainsKey(sidedef.Index) && donesides[sidedef.Index].ContainsKey(target.Index)))
|
||||
continue;
|
||||
|
||||
// Get expected texture offsets
|
||||
int alignedY = GetExpectedOffsetY(sidedef, target, texturename, texture.Height, scaley, partsize);
|
||||
if (alignedY == int.MinValue) continue; // alignedY == int.MinValue means no textures on target and current source part match
|
||||
|
||||
alignedY %= texture.Height;
|
||||
if (alignedY < 0) alignedY += texture.Height;
|
||||
|
||||
int alignedX = (target.OffsetX + (int)Math.Round(target.Line.Length / scalex)) % texture.Width;
|
||||
if (alignedX < 0) alignedX += texture.Width;
|
||||
|
||||
// Submit result if target offsets don't match expected ones
|
||||
if (offsetx != alignedX || offsety != alignedY)
|
||||
{
|
||||
#if DEBUG //TODO: remove this
|
||||
string msg = "Case 1: '"+texturename+"' source " + sidedef.Line.Index + " (" + (sidedef.IsFront ? "front" : "back")
|
||||
+ "), target " + target.Line.Index + " (" + (target.IsFront ? "front" : "back")
|
||||
+ "): expected: " + alignedX + ", " + alignedY
|
||||
+ "; actual [source]: " + offsetx + ", " + offsety;
|
||||
|
||||
SubmitResult(new ResultTexturesMisaligned(sidedef, target, texturename, msg));
|
||||
#else
|
||||
SubmitResult(new ResultTexturesMisaligned(sidedef, target, texturename));
|
||||
#endif
|
||||
AddProcessedSides(sidedef, target, donesides);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if other sides are aligned to current side
|
||||
lines = (sidedef.IsFront ? sidedef.Line.End.Linedefs : sidedef.Line.Start.Linedefs);
|
||||
v = (sidedef.IsFront ? sidedef.Line.End : sidedef.Line.Start);
|
||||
|
||||
foreach(Linedef line in lines)
|
||||
{
|
||||
if (line.Index == sidedef.Line.Index) continue;
|
||||
|
||||
Sidedef target = null;
|
||||
if (line.Front != null && line.Start == v) target = line.Front;
|
||||
else if (line.Back != null && line.End == v) target = line.Back;
|
||||
|
||||
// No target or laready processed?
|
||||
if (target == null || (donesides.ContainsKey(sidedef.Index) && donesides[sidedef.Index].ContainsKey(target.Index)))
|
||||
continue;
|
||||
|
||||
// Get expected texture offsets
|
||||
int alignedY = GetExpectedOffsetY(sidedef, target, texturename, texture.Height, scaley, partsize);
|
||||
if (alignedY == int.MinValue) continue; // alignedY == int.MinValue means no textures on target and current source part match
|
||||
|
||||
alignedY %= texture.Height;
|
||||
if (alignedY < 0) alignedY += texture.Height;
|
||||
|
||||
int alignedX = (target.OffsetX - (int)Math.Round(sidedef.Line.Length / scalex)) % texture.Width;
|
||||
if (alignedX < 0) alignedX += texture.Width;
|
||||
|
||||
// Submit result if target offsets don't match expected ones
|
||||
if (offsetx != alignedX || offsety != alignedY)
|
||||
{
|
||||
#if DEBUG //TODO: remove this
|
||||
string msg = "Case 2: '" + texturename + "' source " + sidedef.Line.Index + " (" + (sidedef.IsFront ? "front" : "back")
|
||||
+ "), target " + target.Line.Index + " (" + (target.IsFront ? "front" : "back")
|
||||
+ "): expected: " + alignedX + ", " + alignedY
|
||||
+ "; actual [source]: " + offsetx + ", " + offsety;
|
||||
|
||||
SubmitResult(new ResultTexturesMisaligned(target, sidedef, texturename, msg));
|
||||
#else
|
||||
SubmitResult(new ResultTexturesMisaligned(target, sidedef, texturename));
|
||||
#endif
|
||||
AddProcessedSides(sidedef, target, donesides);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int GetExpectedOffsetY(Sidedef source, Sidedef target, string texturename, int textureheight, float scaleY, Rectangle partsize)
|
||||
{
|
||||
if (target.MiddleTexture == texturename
|
||||
&& partsize.IntersectsWith(BuilderModesTools.GetSidedefPartSize(target, VisualGeometryType.WALL_MIDDLE)))
|
||||
{
|
||||
return ((int)Tools.GetSidedefMiddleOffsetY(target, target.OffsetY, 1.0f, false) + (int)Math.Round((target.Sector.CeilHeight - source.Sector.CeilHeight) / scaleY)) % textureheight;
|
||||
}
|
||||
|
||||
if (target.HighTexture == texturename
|
||||
&& partsize.IntersectsWith(BuilderModesTools.GetSidedefPartSize(target, VisualGeometryType.WALL_UPPER)))
|
||||
{
|
||||
return ((int)Tools.GetSidedefTopOffsetY(target, target.OffsetY, 1.0f, false) + (int)Math.Round((target.Sector.CeilHeight - source.Sector.CeilHeight) / scaleY)) % textureheight;
|
||||
}
|
||||
|
||||
if (target.LowTexture == texturename
|
||||
&& partsize.IntersectsWith(BuilderModesTools.GetSidedefPartSize(target, VisualGeometryType.WALL_LOWER)))
|
||||
{
|
||||
return ((int)Tools.GetSidedefBottomOffsetY(target, target.OffsetY, 1.0f, false) + (int)Math.Round((target.Sector.CeilHeight - source.Sector.CeilHeight) / scaleY)) % textureheight;
|
||||
}
|
||||
|
||||
return int.MinValue;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
#region ================== Namespaces
|
||||
|
||||
using System;
|
||||
using CodeImp.DoomBuilder.Map;
|
||||
using CodeImp.DoomBuilder.Rendering;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace CodeImp.DoomBuilder.BuilderModes
|
||||
{
|
||||
public class ResultTexturesMisaligned : ErrorResult
|
||||
{
|
||||
|
||||
#region ================== Variables
|
||||
|
||||
private readonly Sidedef side1;
|
||||
private readonly Sidedef side2;
|
||||
private readonly string texturename;
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Properties
|
||||
|
||||
public override int Buttons { get { return 0; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constructor / Destructor
|
||||
|
||||
#if DEBUG //TODO: remove this
|
||||
public ResultTexturesMisaligned(Sidedef side1, Sidedef side2, string texturename, string message)
|
||||
{
|
||||
// Initialize
|
||||
this.side1 = side1;
|
||||
this.side2 = side2;
|
||||
this.texturename = texturename;
|
||||
viewobjects.Add(side1.Line);
|
||||
viewobjects.Add(side2.Line);
|
||||
hidden = (side1.IgnoredErrorChecks.Contains(this.GetType()) && side2.IgnoredErrorChecks.Contains(this.GetType()));
|
||||
description = "Textures are not aligned on given sidedefs. Some players may not like that.\n" + message;
|
||||
}
|
||||
#else
|
||||
public ResultTexturesMisaligned(Sidedef side1, Sidedef side2, string texturename)
|
||||
{
|
||||
// Initialize
|
||||
this.side1 = side1;
|
||||
this.side2 = side2;
|
||||
this.texturename = texturename;
|
||||
viewobjects.Add(side1.Line);
|
||||
viewobjects.Add(side2.Line);
|
||||
hidden = (side1.IgnoredErrorChecks.Contains(this.GetType()) && side2.IgnoredErrorChecks.Contains(this.GetType()));
|
||||
description = "Textures are not aligned on given sidedefs. Some players may not like that.";
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Methods
|
||||
|
||||
// This sets if this result is displayed in ErrorCheckForm (mxd)
|
||||
internal override void Hide(bool hide) {
|
||||
hidden = hide;
|
||||
Type t = this.GetType();
|
||||
if (hide)
|
||||
{
|
||||
side1.IgnoredErrorChecks.Add(t);
|
||||
side2.IgnoredErrorChecks.Add(t);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(side1.IgnoredErrorChecks.Contains(t)) side1.IgnoredErrorChecks.Remove(t);
|
||||
if(side2.IgnoredErrorChecks.Contains(t)) side2.IgnoredErrorChecks.Remove(t);
|
||||
}
|
||||
}
|
||||
|
||||
// This must return the string that is displayed in the listbox
|
||||
public override string ToString()
|
||||
{
|
||||
return "Texture '" + texturename + "' is not aligned on linedefs " + side1.Line.Index + " (" + (side1.IsFront ? "front" : "back")
|
||||
+ ") and " + side2.Line.Index + " (" + (side2.IsFront ? "front" : "back") + ")";
|
||||
}
|
||||
|
||||
// Rendering
|
||||
public override void PlotSelection(IRenderer2D renderer)
|
||||
{
|
||||
renderer.PlotLinedef(side1.Line, General.Colors.Selection);
|
||||
renderer.PlotLinedef(side2.Line, General.Colors.Selection);
|
||||
renderer.PlotVertex(side1.Line.Start, ColorCollection.VERTICES);
|
||||
renderer.PlotVertex(side1.Line.End, ColorCollection.VERTICES);
|
||||
renderer.PlotVertex(side2.Line.Start, ColorCollection.VERTICES);
|
||||
renderer.PlotVertex(side2.Line.End, ColorCollection.VERTICES);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -3262,10 +3262,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
float ystartalign = start.Sidedef.OffsetY;
|
||||
switch(start.GeometryType) {
|
||||
case VisualGeometryType.WALL_UPPER:
|
||||
ystartalign += GetTopOffsetY(start.Sidedef, start.Sidedef.Fields.GetValue("offsety_top", 0.0f), first.scaleY, false);//mxd
|
||||
ystartalign += Tools.GetSidedefTopOffsetY(start.Sidedef, start.Sidedef.Fields.GetValue("offsety_top", 0.0f), first.scaleY, false);//mxd
|
||||
break;
|
||||
case VisualGeometryType.WALL_MIDDLE:
|
||||
ystartalign += GetMiddleOffsetY(start.Sidedef, start.Sidedef.Fields.GetValue("offsety_mid", 0.0f), first.scaleY, false);//mxd
|
||||
ystartalign += Tools.GetSidedefMiddleOffsetY(start.Sidedef, start.Sidedef.Fields.GetValue("offsety_mid", 0.0f), first.scaleY, false);//mxd
|
||||
break;
|
||||
case VisualGeometryType.WALL_MIDDLE_3D: //mxd. 3d-floors are not affected by Lower/Upper unpegged flags
|
||||
ystartalign += first.controlSide.OffsetY - (start.Sidedef.Sector.CeilHeight - first.ceilingHeight);
|
||||
|
@ -3273,7 +3273,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
ystartalign += first.controlSide.Fields.GetValue("offsety_mid", 0.0f);
|
||||
break;
|
||||
case VisualGeometryType.WALL_LOWER:
|
||||
ystartalign += GetBottomOffsetY(start.Sidedef, start.Sidedef.Fields.GetValue("offsety_bottom", 0.0f), first.scaleY, false);//mxd
|
||||
ystartalign += Tools.GetSidedefBottomOffsetY(start.Sidedef, start.Sidedef.Fields.GetValue("offsety_bottom", 0.0f), first.scaleY, false);//mxd
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3362,9 +3362,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
offset = (float)Math.Round(offset); //mxd
|
||||
|
||||
if(matchtop)
|
||||
j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, GetTopOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, Tools.GetSidedefTopOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
if(matchbottom)
|
||||
j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, GetBottomOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, Tools.GetSidedefBottomOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
if(matchmid) {
|
||||
//mxd. Side is part of a 3D floor?
|
||||
if(j.sidedef.Index != j.controlSide.Index) {
|
||||
|
@ -3372,7 +3372,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
offset -= j.controlSide.Fields.GetValue("offsety_mid", 0.0f);
|
||||
j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset % texture.Height);
|
||||
} else {
|
||||
offset = GetMiddleOffsetY(j.sidedef, offset, j.scaleY, true);
|
||||
offset = Tools.GetSidedefMiddleOffsetY(j.sidedef, offset, j.scaleY, true);
|
||||
|
||||
//mxd. Clamp offset if this part is middle single or wrapped middle double
|
||||
if(j.sidedef.Other == null || j.sidedef.IsFlagSet("wrapmidtex") || j.sidedef.Line.IsFlagSet("wrapmidtex")) {
|
||||
|
@ -3423,9 +3423,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
offset = (float)Math.Round(offset); //mxd
|
||||
|
||||
if(matchtop)
|
||||
j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, GetTopOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
j.sidedef.Fields["offsety_top"] = new UniValue(UniversalType.Float, Tools.GetSidedefTopOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
if(matchbottom)
|
||||
j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, GetBottomOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
j.sidedef.Fields["offsety_bottom"] = new UniValue(UniversalType.Float, Tools.GetSidedefBottomOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
if(matchmid) {
|
||||
//mxd. Side is part of a 3D floor?
|
||||
if(j.sidedef.Index != j.controlSide.Index) {
|
||||
|
@ -3433,7 +3433,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
offset -= j.controlSide.Fields.GetValue("offsety_mid", 0.0f);
|
||||
j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, offset % texture.Height); //mxd
|
||||
} else {
|
||||
j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, GetMiddleOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
j.sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, Tools.GetSidedefMiddleOffsetY(j.sidedef, offset, j.scaleY, true) % texture.Height); //mxd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3501,54 +3501,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
return false;
|
||||
}
|
||||
|
||||
//mxd. This converts offsetY from/to "normalized" offset for given upper wall
|
||||
internal float GetTopOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized)
|
||||
{
|
||||
if(side.Line.IsFlagSet(General.Map.Config.UpperUnpeggedFlag) || side.Other == null || side.Other.Sector == null)
|
||||
return offset;
|
||||
|
||||
//if we don't have UpperUnpegged flag, normalize offset
|
||||
float surfaceHeight = (side.Sector.CeilHeight - side.Other.Sector.CeilHeight) * scaleY;
|
||||
|
||||
if(fromNormalized) return (float)Math.Round(offset + surfaceHeight);
|
||||
return (float)Math.Round(offset - surfaceHeight);
|
||||
}
|
||||
|
||||
//mxd. This converts offsetY from/to "normalized" offset for given middle wall
|
||||
internal float GetMiddleOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized)
|
||||
{
|
||||
if(!side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag) || side.Sector == null)
|
||||
return offset;
|
||||
|
||||
// If we have LowerUnpegged flag, normalize offset
|
||||
// Absolute value is used because ceiling height of vavoom-type 3d floors
|
||||
// is lower than floor height
|
||||
float surfaceHeight = (Math.Abs(side.Sector.CeilHeight - side.Sector.FloorHeight)) * scaleY;
|
||||
|
||||
if(fromNormalized) return (float)Math.Round(offset + surfaceHeight);
|
||||
return (float)Math.Round(offset - surfaceHeight);
|
||||
}
|
||||
|
||||
//mxd. This converts offsetY from/to "normalized" offset for given lower wall
|
||||
internal float GetBottomOffsetY(Sidedef side, float offset, float scaleY, bool fromNormalized)
|
||||
{
|
||||
float surfaceHeight;
|
||||
if (side.Line.IsFlagSet(General.Map.Config.LowerUnpeggedFlag)) {
|
||||
if (side.Other == null || side.Other.Sector == null || side.Sector.CeilTexture != General.Map.Config.SkyFlatName ||
|
||||
side.Other.Sector.CeilTexture != General.Map.Config.SkyFlatName)
|
||||
return offset;
|
||||
|
||||
//normalize offset the way Doom does it when front and back sector's ceiling is sky
|
||||
surfaceHeight = (side.Sector.CeilHeight - side.Other.Sector.CeilHeight) * scaleY;
|
||||
} else {
|
||||
//normalize offset
|
||||
surfaceHeight = (side.Sector.CeilHeight - side.Other.Sector.FloorHeight) * scaleY;
|
||||
}
|
||||
|
||||
if(fromNormalized) return (float)Math.Round(offset + surfaceHeight);
|
||||
return (float)Math.Round(offset - surfaceHeight);
|
||||
}
|
||||
|
||||
//mxd
|
||||
private List<Sidedef> getControlSides(Sidedef side, bool udmf) {
|
||||
if(side.Other == null) return new List<Sidedef>() { side };
|
||||
|
|
|
@ -312,7 +312,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
float scaleY = (float)Texture.Height / (Sidedef.Other.Sector.FloorHeight - Sidedef.Sector.FloorHeight);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_bottom", scaleY, 1.0f);
|
||||
|
||||
float offsetY = mode.GetBottomOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
float offsetY = Tools.GetSidedefBottomOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_bottom", offsetY, 0.0f);
|
||||
}
|
||||
|
||||
|
|
|
@ -361,7 +361,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
float scaleY = Texture.ScaledHeight / (Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_mid", scaleY, 1.0f);
|
||||
|
||||
float offsetY = mode.GetMiddleOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
float offsetY = Tools.GetSidedefMiddleOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_mid", offsetY, 0.0f);
|
||||
}
|
||||
|
||||
|
|
|
@ -303,7 +303,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
float scaleY = Texture.ScaledHeight / (Sidedef.Sector.CeilHeight - Sidedef.Sector.FloorHeight);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_mid", scaleY, 1.0f);
|
||||
|
||||
float offsetY = mode.GetMiddleOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
float offsetY = Tools.GetSidedefMiddleOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_mid", offsetY, 0.0f);
|
||||
}
|
||||
|
||||
|
|
|
@ -306,7 +306,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
float scaleY = (float)Texture.Height / (Sidedef.Sector.CeilHeight - Sidedef.Other.Sector.CeilHeight);
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "scaley_top", scaleY, 1.0f);
|
||||
|
||||
float offsetY = mode.GetTopOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
float offsetY = Tools.GetSidedefTopOffsetY(Sidedef, -Sidedef.OffsetY, scaleY, true) % Texture.Height;
|
||||
UDMFTools.SetFloat(Sidedef.Fields, "offsety_top", offsetY, 0.0f);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue