mirror of
https://git.do.srb2.org/STJr/ZoneBuilder.git
synced 2024-11-10 06:41:49 +00:00
Added: more magic to the autoalign/select neighbours logic; These functions should not anymore wrap around to the opposite side of two-sided linedefs, allowing you to select back and front sides separately using shift+click, and reducing infinite broken autoalign loops.
This commit is contained in:
parent
f8bbe45c7b
commit
c677627c09
4 changed files with 202 additions and 50 deletions
|
@ -48,7 +48,7 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
public string newtexlow;
|
||||
}
|
||||
|
||||
private struct SidedefFillJob
|
||||
public struct SidedefFillJob
|
||||
{
|
||||
public Sidedef sidedef;
|
||||
|
||||
|
@ -1788,6 +1788,12 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
{
|
||||
Sidedef side1 = forward ? ld.Front : ld.Back;
|
||||
Sidedef side2 = forward ? ld.Back : ld.Front;
|
||||
|
||||
// [ZZ] don't iterate the same linedef twice.
|
||||
//
|
||||
if ((side1 != null && side1.Marked) ||
|
||||
(side2 != null && side2.Marked)) continue;
|
||||
|
||||
if((ld.Start == v) && (side1 != null) && !side1.Marked)
|
||||
{
|
||||
if(SidedefTextureMatch(side1, texturelongname))
|
||||
|
|
|
@ -692,5 +692,112 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Texture Floodfill
|
||||
|
||||
// This performs texture floodfill along all walls that match with the same texture
|
||||
// NOTE: This method uses the sidedefs marking to indicate which sides have been filled
|
||||
// When resetsidemarks is set to true, all sidedefs will first be marked false (not aligned).
|
||||
// Setting resetsidemarks to false is usefull to fill only within a specific selection
|
||||
// (set the marked property to true for the sidedefs outside the selection)
|
||||
public static void FloodfillTextures(BaseVisualMode mode, Sidedef start, HashSet<long> originaltextures, string filltexture, bool resetsidemarks)
|
||||
{
|
||||
Stack<Tools.SidedefFillJob> todo = new Stack<Tools.SidedefFillJob>(50);
|
||||
|
||||
// Mark all sidedefs false (they will be marked true when the texture is aligned)
|
||||
if(resetsidemarks) General.Map.Map.ClearMarkedSidedefs(false);
|
||||
|
||||
// Begin with first sidedef
|
||||
if(SidedefTextureMatch(mode, start, originaltextures))
|
||||
todo.Push(new Tools.SidedefFillJob { sidedef = start, forward = true });
|
||||
|
||||
// Continue until nothing more to align
|
||||
while(todo.Count > 0)
|
||||
{
|
||||
// Get the align job to do
|
||||
Tools.SidedefFillJob j = todo.Pop();
|
||||
|
||||
//mxd. Get visual parts
|
||||
if(mode.VisualSectorExists(j.sidedef.Sector))
|
||||
{
|
||||
VisualSidedefParts parts = ((BaseVisualSector)mode.GetVisualSector(j.sidedef.Sector)).GetSidedefParts(j.sidedef);
|
||||
|
||||
// Apply texturing
|
||||
if((parts.upper != null && parts.upper.Triangles > 0) && originaltextures.Contains(j.sidedef.LongHighTexture))
|
||||
j.sidedef.SetTextureHigh(filltexture);
|
||||
if(((parts.middledouble != null && parts.middledouble.Triangles > 0) || (parts.middlesingle != null && parts.middlesingle.Triangles > 0)) && originaltextures.Contains(j.sidedef.LongMiddleTexture))
|
||||
j.sidedef.SetTextureMid(filltexture);
|
||||
if((parts.lower != null && parts.lower.Triangles > 0) && originaltextures.Contains(j.sidedef.LongLowTexture))
|
||||
j.sidedef.SetTextureLow(filltexture);
|
||||
}
|
||||
|
||||
j.sidedef.Marked = true;
|
||||
|
||||
if(j.forward)
|
||||
{
|
||||
// Add sidedefs forward (connected to the right vertex)
|
||||
Vertex v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
||||
AddSidedefsForFloodfill(mode, todo, v, true, originaltextures);
|
||||
|
||||
// Add sidedefs backward (connected to the left vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
||||
AddSidedefsForFloodfill(mode, todo, v, false, originaltextures);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add sidedefs backward (connected to the left vertex)
|
||||
Vertex v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
||||
AddSidedefsForFloodfill(mode, todo, v, false, originaltextures);
|
||||
|
||||
// Add sidedefs forward (connected to the right vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
||||
AddSidedefsForFloodfill(mode, todo, v, true, originaltextures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This adds the matching, unmarked sidedefs from a vertex for texture alignment
|
||||
private static void AddSidedefsForFloodfill(BaseVisualMode mode, Stack<Tools.SidedefFillJob> stack, Vertex v, bool forward, HashSet<long> texturelongnames)
|
||||
{
|
||||
foreach(Linedef ld in v.Linedefs)
|
||||
{
|
||||
Sidedef side1 = (forward ? ld.Front : ld.Back);
|
||||
Sidedef side2 = (forward ? ld.Back : ld.Front);
|
||||
|
||||
// [ZZ] don't iterate the same linedef twice.
|
||||
//
|
||||
if ((side1 != null && side1.Marked) ||
|
||||
(side2 != null && side2.Marked)) continue;
|
||||
|
||||
if ((ld.Start == v) && (side1 != null) && !side1.Marked)
|
||||
{
|
||||
if(SidedefTextureMatch(mode, side1, texturelongnames))
|
||||
stack.Push(new Tools.SidedefFillJob { forward = forward, sidedef = side1 });
|
||||
}
|
||||
else if((ld.End == v) && (side2 != null) && !side2.Marked)
|
||||
{
|
||||
if(SidedefTextureMatch(mode, side2, texturelongnames))
|
||||
stack.Push(new Tools.SidedefFillJob { forward = forward, sidedef = side2 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Texture Alignment
|
||||
|
||||
//mxd. This checks if any of the sidedef texture match the given textures
|
||||
public static bool SidedefTextureMatch(BaseVisualMode mode, Sidedef sd, HashSet<long> texturelongnames)
|
||||
{
|
||||
if(!mode.VisualSectorExists(sd.Sector)) return false;
|
||||
VisualSidedefParts parts = ((BaseVisualSector)mode.GetVisualSector(sd.Sector)).GetSidedefParts(sd);
|
||||
|
||||
return (texturelongnames.Contains(sd.LongHighTexture) && (parts.upper != null && parts.upper.Triangles > 0)) ||
|
||||
(texturelongnames.Contains(sd.LongLowTexture) && (parts.lower != null && parts.lower.Triangles > 0)) ||
|
||||
(texturelongnames.Contains(sd.LongMiddleTexture)
|
||||
&& ((parts.middledouble != null && parts.middledouble.Triangles > 0) || (parts.middlesingle != null && parts.middlesingle.Triangles > 0)));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -561,6 +561,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
//mxd
|
||||
public void SelectNeighbours(bool select, bool matchtexture, bool matchheight)
|
||||
{
|
||||
SelectNeighbours(select, matchtexture, matchheight, true, true);
|
||||
}
|
||||
|
||||
private void SelectNeighbours(bool select, bool matchtexture, bool matchheight, bool clearlinedefs, bool forward)
|
||||
{
|
||||
if(Sidedef.Sector == null || Triangles < 1 || (!matchtexture && !matchheight)) return;
|
||||
|
||||
|
@ -578,57 +583,86 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
mode.RemoveSelectedObject(this);
|
||||
}
|
||||
|
||||
// [ZZ] use the marking system.
|
||||
if (clearlinedefs) General.Map.Map.ClearMarkedLinedefs(false);
|
||||
Sidedef.Line.Marked = true;
|
||||
|
||||
// Select
|
||||
SelectNeighbourLines(Sidedef.Line.Start.Linedefs, rect, select, matchtexture, matchheight);
|
||||
SelectNeighbourLines(Sidedef.Line.End.Linedefs, rect, select, matchtexture, matchheight);
|
||||
Vertex v;
|
||||
|
||||
if (forward)
|
||||
{
|
||||
v = Sidedef.IsFront ? Sidedef.Line.End : Sidedef.Line.Start;
|
||||
SelectNeighbourLines(v.Linedefs, v, rect, select, matchtexture, matchheight, true);
|
||||
v = Sidedef.IsFront ? Sidedef.Line.Start : Sidedef.Line.End;
|
||||
SelectNeighbourLines(v.Linedefs, v, rect, select, matchtexture, matchheight, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = Sidedef.IsFront ? Sidedef.Line.Start : Sidedef.Line.End;
|
||||
SelectNeighbourLines(v.Linedefs, v, rect, select, matchtexture, matchheight, false);
|
||||
v = Sidedef.IsFront ? Sidedef.Line.End : Sidedef.Line.Start;
|
||||
SelectNeighbourLines(v.Linedefs, v, rect, select, matchtexture, matchheight, true);
|
||||
}
|
||||
}
|
||||
|
||||
//mxd
|
||||
private void SelectNeighbourLines(IEnumerable<Linedef> lines, Rectangle sourcerect, bool select, bool matchtexture, bool matchheight)
|
||||
private void SelectNeighbourLines(IEnumerable<Linedef> lines, Vertex v, Rectangle sourcerect, bool select, bool matchtexture, bool matchheight, bool forward)
|
||||
{
|
||||
foreach(Linedef line in lines)
|
||||
{
|
||||
if (line.Index == Sidedef.Line.Index) continue;
|
||||
// [ZZ] decide which side of the next linedef to iterate.
|
||||
// do NOT do both
|
||||
Sidedef next = null;
|
||||
Sidedef side1 = forward ? line.Front : line.Back;
|
||||
Sidedef side2 = forward ? line.Back : line.Front;
|
||||
|
||||
if (line.Front != null && line.Front.Sector != null)
|
||||
SelectNeighbourSideParts(line.Front, sourcerect, select, matchtexture, matchheight);
|
||||
if (line.Start == v)
|
||||
next = side1;
|
||||
else if (line.End == v)
|
||||
next = side2;
|
||||
|
||||
if (line.Back != null && line.Back.Sector != null)
|
||||
SelectNeighbourSideParts(line.Back, sourcerect, select, matchtexture, matchheight);
|
||||
if (next == null || next.Sector == null)
|
||||
continue;
|
||||
|
||||
SelectNeighbourSideParts(next, sourcerect, select, matchtexture, matchheight, forward);
|
||||
}
|
||||
}
|
||||
|
||||
//mxd
|
||||
private void SelectNeighbourSideParts(Sidedef side, Rectangle sourcerect, bool select, bool matchtexture, bool matchheight)
|
||||
private void SelectNeighbourSideParts(Sidedef side, Rectangle sourcerect, bool select, bool matchtexture, bool matchheight, bool forward)
|
||||
{
|
||||
BaseVisualSector s = mode.GetVisualSector(side.Sector) as BaseVisualSector;
|
||||
if (side.Line.Marked)
|
||||
return;
|
||||
|
||||
BaseVisualSector s = (BaseVisualSector)mode.GetVisualSector(side.Sector);
|
||||
if(s != null)
|
||||
{
|
||||
VisualSidedefParts parts = s.GetSidedefParts(side);
|
||||
SelectNeighbourSidePart(parts.lower, sourcerect, select, matchtexture, matchheight);
|
||||
SelectNeighbourSidePart(parts.middlesingle, sourcerect, select, matchtexture, matchheight);
|
||||
SelectNeighbourSidePart(parts.middledouble, sourcerect, select, matchtexture, matchheight);
|
||||
SelectNeighbourSidePart(parts.upper, sourcerect, select, matchtexture, matchheight);
|
||||
SelectNeighbourSidePart(parts.lower, sourcerect, select, matchtexture, matchheight, forward);
|
||||
SelectNeighbourSidePart(parts.middlesingle, sourcerect, select, matchtexture, matchheight, forward);
|
||||
SelectNeighbourSidePart(parts.middledouble, sourcerect, select, matchtexture, matchheight, forward);
|
||||
SelectNeighbourSidePart(parts.upper, sourcerect, select, matchtexture, matchheight, forward);
|
||||
|
||||
if(parts.middle3d != null)
|
||||
{
|
||||
foreach(VisualMiddle3D middle3D in parts.middle3d)
|
||||
SelectNeighbourSidePart(middle3D, sourcerect, select, matchtexture, matchheight);
|
||||
SelectNeighbourSidePart(middle3D, sourcerect, select, matchtexture, matchheight, forward);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//mxd
|
||||
private void SelectNeighbourSidePart(BaseVisualGeometrySidedef visualside, Rectangle sourcerect, bool select, bool matchtexture, bool matchheight)
|
||||
private void SelectNeighbourSidePart(BaseVisualGeometrySidedef visualside, Rectangle sourcerect, bool select, bool matchtexture, bool matchheight, bool forward)
|
||||
{
|
||||
if(visualside != null && visualside.Triangles > 0 && visualside.Selected != select)
|
||||
{
|
||||
Rectangle r = BuilderModesTools.GetSidedefPartSize(visualside);
|
||||
if(r.Width == 0 || r.Height == 0) return;
|
||||
if ((matchtexture && visualside.Texture == Texture && r.IntersectsWith(sourcerect)) ||
|
||||
(matchheight && sourcerect.Height == r.Height && sourcerect.Y == r.Y))
|
||||
if((!matchtexture || (visualside.Texture == Texture && r.IntersectsWith(sourcerect))) &&
|
||||
(!matchheight || (sourcerect.Height == r.Height && sourcerect.Y == r.Y)))
|
||||
{
|
||||
visualside.SelectNeighbours(select, matchtexture, matchheight);
|
||||
visualside.SelectNeighbours(select, matchtexture, matchheight, false, forward);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4640,6 +4640,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
Sidedef side1 = forward ? ld.Front : ld.Back;
|
||||
Sidedef side2 = forward ? ld.Back : ld.Front;
|
||||
|
||||
// [ZZ] I don't know what logic here is.
|
||||
// I'm going to check if any side is marked, and if so, don't add.
|
||||
if ((side1 != null && side1.Marked) ||
|
||||
(side2 != null && side2.Marked)) continue;
|
||||
|
||||
if((ld.Start == v) && (side1 != null) && !side1.Marked)
|
||||
{
|
||||
List<Sidedef> controlSides = GetControlSides(side1, udmf); //mxd
|
||||
|
|
Loading…
Reference in a new issue