mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-18 14:31:50 +00:00
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.
This commit is contained in:
parent
4fd2c8d7dc
commit
70b88bd47d
5 changed files with 194 additions and 155 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -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
|
||||
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;
|
||||
|
||||
//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;
|
||||
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
|
||||
|
|
|
@ -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
|
||||
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;
|
||||
|
||||
//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;
|
||||
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));
|
||||
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["rotationfloor"].Value = sourceAngle;
|
||||
} else if(Sector.Sector.Fields.ContainsKey("rotationfloor")) {
|
||||
Sector.Sector.Fields.Remove("rotationfloor");
|
||||
alignTextureToClosestLine(alignx, aligny);
|
||||
}
|
||||
|
||||
//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);
|
||||
else
|
||||
Sector.Sector.Fields.Add("ypanningfloor", new UniValue(UniversalType.Float, (float)Math.Round(offset.y)));
|
||||
}
|
||||
|
||||
//update geometry
|
||||
Sector.UpdateSectorGeometry(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
Loading…
Reference in a new issue