From 70b88bd47d5691e94fe0bda8bfad739a8f34bc70 Mon Sep 17 00:00:00 2001 From: MaxED <j.maxed@gmail.com> Date: Wed, 29 May 2013 14:18:49 +0000 Subject: [PATCH] Visual mode, UDMF: "Auto-align textures" actions now work for floors and ceilings. Textures are aligned to a linedef of highlighted floor/ceiling, which is closest to 3d-cursor position. --- Source/Core/VisualModes/VisualMode.cs | 4 +- .../VisualModes/BaseVisualGeometrySector.cs | 149 ++++++++++++++++++ .../VisualModes/BaseVisualMode.cs | 7 +- .../BuilderModes/VisualModes/VisualCeiling.cs | 97 +++--------- .../BuilderModes/VisualModes/VisualFloor.cs | 96 +++-------- 5 files changed, 196 insertions(+), 157 deletions(-) diff --git a/Source/Core/VisualModes/VisualMode.cs b/Source/Core/VisualModes/VisualMode.cs index 7df490399..61597f135 100644 --- a/Source/Core/VisualModes/VisualMode.cs +++ b/Source/Core/VisualModes/VisualMode.cs @@ -427,7 +427,7 @@ namespace CodeImp.DoomBuilder.VisualModes //mxd [BeginAction("placethingatcursor", BaseAction = true)] protected void placeThingAtCursor() { - Vector2D hitpos = getHitPosition(); + Vector2D hitpos = GetHitPosition(); if (!hitpos.IsFinite()) { General.Interface.DisplayStatus(StatusType.Warning, "Cannot place Thing here"); return; @@ -437,7 +437,7 @@ namespace CodeImp.DoomBuilder.VisualModes } //mxd. - protected Vector2D getHitPosition() { + public Vector2D GetHitPosition() { Vector3D start = General.Map.VisualCamera.Position; Vector3D delta = General.Map.VisualCamera.Target - General.Map.VisualCamera.Position; delta = delta.GetFixedLength(General.Settings.ViewDistance * 0.98f); diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs index 082d2e45c..648bebcde 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs @@ -26,6 +26,8 @@ using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.Rendering; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.VisualModes; +using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.GZBuilder.Tools; #endregion @@ -179,6 +181,153 @@ namespace CodeImp.DoomBuilder.BuilderModes public virtual bool IsSelected() { return selected; } + + //mxd + protected void alignTextureToClosestLine(bool alignx, bool aligny) { + //find a linedef to align to + Vector2D hitpos = mode.GetHitPosition(); + if(!(mode.HighlightedObject is BaseVisualSector) || !hitpos.IsFinite()) return; + bool isFront = false; + + //align to line of highlighted sector, which is closest to hitpos + Sector highlightedSector = ((BaseVisualSector)mode.HighlightedObject).Sector; + List<Linedef> lines = new List<Linedef>(); + foreach(Sidedef side in highlightedSector.Sidedefs) lines.Add(side.Line); + + Linedef targetLine = MapSet.NearestLinedef(lines, hitpos); + if(targetLine == null) return; + + foreach(Sidedef side in highlightedSector.Sidedefs) { + if(side.Line == targetLine && side.Line.Front != null && side.Line.Front == side) { + isFront = true; + break; + } + } + + Sector.Sector.Fields.BeforeFieldsChange(); + + //find an angle to rotate texture + float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(targetLine.Angle) + 90 : -Angle2D.RadToDeg(targetLine.Angle) - 90), 1); + if(!isFront) sourceAngle = General.ClampAngle(sourceAngle + 180); + string rotationKey = (geoType == VisualGeometryType.FLOOR ? "rotationfloor" : "rotationceiling"); + + //update angle + UDMFTools.SetFloat(Sector.Sector.Fields, rotationKey, sourceAngle, 0f, false); + + //update scale. Target should be either floor or ceiling at this point + float scaleX = 1.0f; + float scaleY = 1.0f; + + if(mode.HighlightedTarget is VisualFloor) { + VisualFloor target = mode.HighlightedTarget as VisualFloor; + scaleX = target.Sector.Sector.Fields.GetValue("xscalefloor", 1.0f); + scaleY = target.Sector.Sector.Fields.GetValue("yscalefloor", 1.0f); + } else { + VisualCeiling target = mode.HighlightedTarget as VisualCeiling; + scaleX = target.Sector.Sector.Fields.GetValue("xscaleceiling", 1.0f); + scaleY = target.Sector.Sector.Fields.GetValue("yscaleceiling", 1.0f); + } + + string xScaleKey = (geoType == VisualGeometryType.FLOOR ? "xscalefloor" : "xscaleceiling"); + string yScaleKey = (geoType == VisualGeometryType.FLOOR ? "yscalefloor" : "yscaleceiling"); + + //set scale + UDMFTools.SetFloat(Sector.Sector.Fields, xScaleKey, scaleX, 1.0f, false); + UDMFTools.SetFloat(Sector.Sector.Fields, yScaleKey, scaleY, 1.0f, false); + + //update offset + float distToStart = Vector2D.Distance(hitpos, targetLine.Start.Position); + float distToEnd = Vector2D.Distance(hitpos, targetLine.End.Position); + Vector2D offset = (distToStart < distToEnd ? targetLine.Start.Position : targetLine.End.Position).GetRotated(Angle2D.DegToRad(sourceAngle)); + + if(alignx) { + if(Texture != null) offset.x %= Texture.Width / scaleX; + UDMFTools.SetFloat(Sector.Sector.Fields, (geoType == VisualGeometryType.FLOOR ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f, false); + } + + if(aligny) { + if(Texture != null) offset.y %= Texture.Height / scaleY; + UDMFTools.SetFloat(Sector.Sector.Fields, (geoType == VisualGeometryType.FLOOR ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f, false); + } + + //update geometry + Sector.UpdateSectorGeometry(false); + } + + //mxd + protected void alignTextureToSlopeLine(Linedef slopeSource, float slopeAngle, bool isFront, bool alignx, bool aligny) { + Vector2D hitpos = mode.GetHitPosition(); + bool isFloor = (geoType == VisualGeometryType.FLOOR); + + Sector.Sector.Fields.BeforeFieldsChange(); + + float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(slopeSource.Angle) + 90 : -Angle2D.RadToDeg(slopeSource.Angle) - 90), 1); + + if(isFloor) { + if((isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight) || + (!isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight)) { + sourceAngle = General.ClampAngle(sourceAngle + 180); + } + } else { + if((isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight) || + (!isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight)) { + sourceAngle = General.ClampAngle(sourceAngle + 180); + } + } + + //update angle + string rotationKey = (isFloor ? "rotationfloor" : "rotationceiling"); + UDMFTools.SetFloat(Sector.Sector.Fields, rotationKey, sourceAngle, 0f, false); + + //update scaleY + string xScaleKey = (isFloor ? "xscalefloor" : "xscaleceiling"); + string yScaleKey = (isFloor ? "yscalefloor" : "yscaleceiling"); + + float scaleX = Sector.Sector.Fields.GetValue(xScaleKey, 1.0f); + float scaleY;// = (float)Math.Round(scaleX * (1 / (float)Math.Cos(slopeAngle)), 2); + + //set scale + if(aligny) { + scaleY = (float)Math.Round(scaleX * (1 / (float)Math.Cos(slopeAngle)), 2); + UDMFTools.SetFloat(Sector.Sector.Fields, yScaleKey, scaleY, 1.0f, false); + } else { + scaleY = Sector.Sector.Fields.GetValue(yScaleKey, 1.0f); + } + + //update texture offsets + Vector2D offset; + + if(isFloor) { + if((isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight) || + (!isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight)) { + offset = slopeSource.End.Position; + } else { + offset = slopeSource.Start.Position; + } + } else { + if((isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight) || + (!isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight)) { + offset = slopeSource.End.Position; + } else { + offset = slopeSource.Start.Position; + } + } + + offset = offset.GetRotated(Angle2D.DegToRad(sourceAngle)); + + if(alignx) { + if(Texture != null) offset.x %= Texture.Width / scaleX; + UDMFTools.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f, false); + } + + if(aligny) { + if(Texture != null) offset.y %= Texture.Height / scaleY; + UDMFTools.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f, false); + } + + //update geometry + Sector.UpdateSectorGeometry(false); + } #endregion diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index b9c94b0ea..833d4f62f 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -144,6 +144,9 @@ namespace CodeImp.DoomBuilder.BuilderModes } } + //mxd + public object HighlightedTarget { get { return target.picked; } } + new public IRenderer3D Renderer { get { return renderer; } } public bool IsSingleSelection { get { return singleselection; } } @@ -2316,7 +2319,7 @@ namespace CodeImp.DoomBuilder.BuilderModes [BeginAction("insertitem", BaseAction = true)] public void InsertThing() { - Vector2D hitpos = getHitPosition(); + Vector2D hitpos = GetHitPosition(); if (!hitpos.IsFinite()) { General.Interface.DisplayStatus(StatusType.Warning, "Cannot insert thing here!"); @@ -2386,7 +2389,7 @@ namespace CodeImp.DoomBuilder.BuilderModes return; } - Vector2D hitpos = getHitPosition(); + Vector2D hitpos = GetHitPosition(); if (!hitpos.IsFinite()) { General.Interface.DisplayStatus(StatusType.Warning, "Cannot paste here!"); diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs index 01f6c0ba6..019486b46 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs @@ -380,90 +380,33 @@ namespace CodeImp.DoomBuilder.BuilderModes public void AlignTexture(bool alignx, bool aligny) { if(!General.Map.UDMF) return; + //is is a surface with line slope? float slopeAngle = level.plane.Normal.GetAngleZ() - Angle2D.PIHALF; - if(slopeAngle == 0) return; //it's a horizontal plane - - //find slope source linedef - Linedef slopeSource = null; - bool isFront = false; - - foreach(Sidedef side in Sector.Sector.Sidedefs) { - if(side.Line.Action == 181) { - if(side.Line.Args[1] == 1 && side.Line.Front != null && side.Line.Front == side) { - slopeSource = side.Line; - isFront = true; - break; - } else if(side.Line.Args[1] == 2 && side.Line.Back != null && side.Line.Back == side) { - slopeSource = side.Line; - break; + if(slopeAngle == 0) {//it's a horizontal plane + alignTextureToClosestLine(alignx, aligny); + } else { //it can be a surface with line slope + Linedef slopeSource = null; + bool isFront = false; + + foreach(Sidedef side in Sector.Sector.Sidedefs) { + if(side.Line.Action == 181) { + if(side.Line.Args[1] == 1 && side.Line.Front != null && side.Line.Front == side) { + slopeSource = side.Line; + isFront = true; + break; + } else if(side.Line.Args[1] == 2 && side.Line.Back != null && side.Line.Back == side) { + slopeSource = side.Line; + break; + } } } - } - - if(slopeSource == null) return; - - Sector.Sector.Fields.BeforeFieldsChange(); - - //match rotation - float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(slopeSource.Angle) + 90 : -Angle2D.RadToDeg(slopeSource.Angle) - 90), 1); - - if((isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight) || - (!isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight)) { - sourceAngle = General.ClampAngle(sourceAngle + 180); - } - if(sourceAngle != 0) { - if(!Sector.Sector.Fields.ContainsKey("rotationceiling")) - Sector.Sector.Fields.Add("rotationceiling", new UniValue(UniversalType.Float, sourceAngle)); + if(slopeSource != null && slopeSource.Front != null && slopeSource.Front.Sector != null && slopeSource.Back != null && slopeSource.Back.Sector != null) + alignTextureToSlopeLine(slopeSource, slopeAngle, isFront, alignx, aligny); else - Sector.Sector.Fields["rotationceiling"].Value = sourceAngle; - } else if(Sector.Sector.Fields.ContainsKey("rotationceiling")) { - Sector.Sector.Fields.Remove("rotationceiling"); + alignTextureToClosestLine(alignx, aligny); } - - //update scaleY - float scaleX = Sector.Sector.Fields.GetValue("xscaleceiling", 1.0f); - float scaleY = (float)Math.Round(scaleX * (1 / (float)Math.Cos(slopeAngle)), 2); - - if(aligny) { - if(Sector.Sector.Fields.ContainsKey("yscaleceiling")) - Sector.Sector.Fields["yscaleceiling"].Value = scaleY; - else - Sector.Sector.Fields.Add("yscaleceiling", new UniValue(UniversalType.Float, scaleY)); - } - - //update texture offsets - Vector2D offset; - if((isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight) || - (!isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight)) { - offset = slopeSource.End.Position; - } else { - offset = slopeSource.Start.Position; - } - - offset = offset.GetRotated(Angle2D.DegToRad(sourceAngle)); - - if(alignx) { - if(Texture != null) offset.x %= Texture.Width / scaleX; - - if(Sector.Sector.Fields.ContainsKey("xpanningceiling")) - Sector.Sector.Fields["xpanningceiling"].Value = (float)Math.Round(-offset.x); - else - Sector.Sector.Fields.Add("xpanningceiling", new UniValue(UniversalType.Float, (float)Math.Round(-offset.x))); - } - - if(aligny) { - if(Texture != null) offset.y %= Texture.Height / scaleY; - - if(Sector.Sector.Fields.ContainsKey("ypanningceiling")) - Sector.Sector.Fields["ypanningceiling"].Value = (float)Math.Round(offset.y); - else - Sector.Sector.Fields.Add("ypanningceiling", new UniValue(UniversalType.Float, (float)Math.Round(offset.y))); - } - - //update geometry - Sector.UpdateSectorGeometry(false); } #endregion diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs index f6f1f9c65..6beb26ed4 100644 --- a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs +++ b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs @@ -337,89 +337,33 @@ namespace CodeImp.DoomBuilder.BuilderModes public void AlignTexture(bool alignx, bool aligny) { if(!General.Map.UDMF) return; + //is is a surface with line slope? float slopeAngle = level.plane.Normal.GetAngleZ() - Angle2D.PIHALF; - if(slopeAngle == 0) return; //it's a horizontal plane - - //find slope source linedef - Linedef slopeSource = null; - bool isFront = false; - - foreach(Sidedef side in Sector.Sector.Sidedefs) { - if(side.Line.Action == 181) { - if(side.Line.Args[0] == 1 && side.Line.Front != null && side.Line.Front == side) { - slopeSource = side.Line; - isFront = true; - break; - } else if(side.Line.Args[0] == 2 && side.Line.Back != null && side.Line.Back == side) { - slopeSource = side.Line; - break; + if(slopeAngle == 0) {//it's a horizontal plane + alignTextureToClosestLine(alignx, aligny); + } else { //it can be a surface with line slope + Linedef slopeSource = null; + bool isFront = false; + + foreach(Sidedef side in Sector.Sector.Sidedefs) { + if(side.Line.Action == 181) { + if(side.Line.Args[0] == 1 && side.Line.Front != null && side.Line.Front == side) { + slopeSource = side.Line; + isFront = true; + break; + } else if(side.Line.Args[0] == 2 && side.Line.Back != null && side.Line.Back == side) { + slopeSource = side.Line; + break; + } } } - } - - if(slopeSource == null) return; - - Sector.Sector.Fields.BeforeFieldsChange(); - - float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(slopeSource.Angle) + 90 : -Angle2D.RadToDeg(slopeSource.Angle) - 90), 1); - - if((isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight) || - (!isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight)) { - sourceAngle = General.ClampAngle(sourceAngle + 180); - } - - if(sourceAngle != 0) { - if(!Sector.Sector.Fields.ContainsKey("rotationfloor")) - Sector.Sector.Fields.Add("rotationfloor", new UniValue(UniversalType.Float, sourceAngle)); - else - Sector.Sector.Fields["rotationfloor"].Value = sourceAngle; - } else if(Sector.Sector.Fields.ContainsKey("rotationfloor")) { - Sector.Sector.Fields.Remove("rotationfloor"); - } - - //update scaleY - float scaleX = Sector.Sector.Fields.GetValue("xscalefloor", 1.0f); - float scaleY = (float)Math.Round(scaleX * (1 / (float)Math.Cos(slopeAngle)), 2); - - if(aligny) { - if(Sector.Sector.Fields.ContainsKey("yscalefloor")) - Sector.Sector.Fields["yscalefloor"].Value = scaleY; - else - Sector.Sector.Fields.Add("yscalefloor", new UniValue(UniversalType.Float, scaleY)); - } - - //update texture offsets - Vector2D offset; - if((isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight) || - (!isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight)) { - offset = slopeSource.End.Position; - } else { - offset = slopeSource.Start.Position; - } - - offset = offset.GetRotated(Angle2D.DegToRad(sourceAngle)); - if(alignx) { - if(Texture != null) offset.x %= Texture.Width / scaleX; - - if(Sector.Sector.Fields.ContainsKey("xpanningfloor")) - Sector.Sector.Fields["xpanningfloor"].Value = (float)Math.Round(-offset.x); - else - Sector.Sector.Fields.Add("xpanningfloor", new UniValue(UniversalType.Float, (float)Math.Round(-offset.x))); - } - - if(aligny) { - if(Texture != null) offset.y %= Texture.Height / scaleY; - - if(Sector.Sector.Fields.ContainsKey("ypanningfloor")) - Sector.Sector.Fields["ypanningfloor"].Value = (float)Math.Round(offset.y); + if(slopeSource != null && slopeSource.Front != null && slopeSource.Front.Sector != null && slopeSource.Back != null && slopeSource.Back.Sector != null) + alignTextureToSlopeLine(slopeSource, slopeAngle, isFront, alignx, aligny); else - Sector.Sector.Fields.Add("ypanningfloor", new UniValue(UniversalType.Float, (float)Math.Round(offset.y))); + alignTextureToClosestLine(alignx, aligny); } - - //update geometry - Sector.UpdateSectorGeometry(false); } #endregion -- GitLab