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:
MaxED 2013-05-29 14:18:49 +00:00
parent 4fd2c8d7dc
commit 70b88bd47d
5 changed files with 194 additions and 155 deletions

View file

@ -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);

View file

@ -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

View file

@ -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!");

View file

@ -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

View file

@ -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