mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2025-01-18 14:31:50 +00:00
- added texture Flood-Fill action in Visual Mode
- fixed list of used key combinations on Controls preferences when action without key is selected - fixed automatic texture loading when geometry with new textures is pasted in the map
This commit is contained in:
parent
69f608ddbc
commit
599b8ce667
9 changed files with 189 additions and 13 deletions
|
@ -885,6 +885,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
General.Map.Map.SnapAllToAccuracy();
|
||||
|
||||
// Update cached values
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
General.Map.Map.Update();
|
||||
|
||||
// Clear selection
|
||||
|
|
|
@ -554,3 +554,14 @@ placevisualstart
|
|||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
}
|
||||
|
||||
floodfilltextures
|
||||
{
|
||||
title = "Flood Fill Textures";
|
||||
category = "visual";
|
||||
description = "This allows you to select a texture and flood-fill all adjacent textures that are identical to the original with the selected texture.";
|
||||
allowkeys = true;
|
||||
allowmouse = true;
|
||||
allowscroll = true;
|
||||
default = 65540;
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public virtual void OnToggleLowerUnpegged() { }
|
||||
public virtual void OnResetTextureOffset() { }
|
||||
protected virtual void SetTexture(string texturename) { }
|
||||
public virtual void OnTextureFloodfill() { }
|
||||
|
||||
// Processing
|
||||
public virtual void OnProcess(double deltatime)
|
||||
|
|
|
@ -200,6 +200,51 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if(parts.middlesingle != null) parts.middlesingle.Setup();
|
||||
if(parts.upper != null) parts.upper.Setup();
|
||||
}
|
||||
|
||||
// Flood-fill textures
|
||||
public virtual void OnTextureFloodfill()
|
||||
{
|
||||
if(General.Interface.IsActiveWindow)
|
||||
{
|
||||
string oldtexture = GetTextureName();
|
||||
string newtexture = General.Interface.BrowseTexture(General.Interface, oldtexture);
|
||||
if(newtexture != oldtexture)
|
||||
{
|
||||
General.Map.UndoRedo.CreateUndo("Flood-fill textures with " + newtexture);
|
||||
|
||||
mode.Renderer.SetCrosshairBusy(true);
|
||||
General.Interface.RedrawDisplay();
|
||||
|
||||
// Get the texture
|
||||
ImageData newtextureimage = General.Map.Data.GetTextureImage(newtexture);
|
||||
if(newtextureimage != null)
|
||||
{
|
||||
// Do the alignment
|
||||
Tools.FloodfillTextures(this.Sidedef, base.Texture, newtextureimage, true);
|
||||
|
||||
// Get the changed sidedefs
|
||||
List<Sidedef> changes = General.Map.Map.GetMarkedSidedefs(true);
|
||||
foreach(Sidedef sd in changes)
|
||||
{
|
||||
// Update the parts for this sidedef!
|
||||
if(mode.VisualSectorExists(sd.Sector))
|
||||
{
|
||||
BaseVisualSector vs = (mode.GetVisualSector(sd.Sector) as BaseVisualSector);
|
||||
VisualSidedefParts parts = vs.GetSidedefParts(sd);
|
||||
if(parts.lower != null) parts.lower.Setup();
|
||||
if(parts.middledouble != null) parts.middledouble.Setup();
|
||||
if(parts.middlesingle != null) parts.middlesingle.Setup();
|
||||
if(parts.upper != null) parts.upper.Setup();
|
||||
}
|
||||
}
|
||||
|
||||
General.Map.Data.UpdateUsedTextures();
|
||||
mode.Renderer.SetCrosshairBusy(false);
|
||||
mode.ShowTargetInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-align texture X offsets
|
||||
public virtual void OnTextureAlign(bool alignx, bool aligny)
|
||||
|
|
|
@ -76,6 +76,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
|
||||
#region ================== Properties
|
||||
|
||||
public IRenderer3D Renderer { get { return renderer; } }
|
||||
public string CopiedTexture { get { return copiedtexture; } set { copiedtexture = value; } }
|
||||
public string CopiedFlat { get { return copiedflat; } set { copiedflat = value; } }
|
||||
|
||||
|
@ -546,6 +547,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
if(target.picked != null) (target.picked as IVisualEventReceiver).OnResetTextureOffset();
|
||||
ShowTargetInfo();
|
||||
}
|
||||
|
||||
[BeginAction("floodfilltextures")]
|
||||
public void FloodfillTextures()
|
||||
{
|
||||
PickTargetUnlocked();
|
||||
if(target.picked != null) (target.picked as IVisualEventReceiver).OnTextureFloodfill();
|
||||
ShowTargetInfo();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -349,6 +349,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
public virtual void OnToggleLowerUnpegged() { }
|
||||
public virtual void OnResetTextureOffset() { }
|
||||
public virtual void OnProcess(double deltatime) { }
|
||||
public virtual void OnTextureFloodfill() { }
|
||||
|
||||
// Return texture name
|
||||
public virtual string GetTextureName() { return ""; }
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
|
|||
void OnCopyTexture();
|
||||
void OnPasteTexture();
|
||||
void OnTextureAlign(bool alignx, bool aligny);
|
||||
void OnTextureFloodfill();
|
||||
void OnToggleUpperUnpegged();
|
||||
void OnToggleLowerUnpegged();
|
||||
void OnProcess(double deltatime);
|
||||
|
|
|
@ -63,7 +63,15 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
// must be subtracted from the X offset first.
|
||||
public bool forward;
|
||||
}
|
||||
|
||||
|
||||
private struct SidedefFillJob
|
||||
{
|
||||
public Sidedef sidedef;
|
||||
|
||||
// Moving forward along the sidedef?
|
||||
public bool forward;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Constants
|
||||
|
@ -1224,7 +1232,104 @@ namespace CodeImp.DoomBuilder.Geometry
|
|||
}
|
||||
|
||||
#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(Sidedef start, ImageData texture, ImageData filltexture, bool resetsidemarks)
|
||||
{
|
||||
Stack<SidedefFillJob> todo = new Stack<SidedefFillJob>(50);
|
||||
|
||||
// Begin with first sidedef
|
||||
if(SidedefTextureMatch(start, texture.LongName))
|
||||
{
|
||||
SidedefFillJob first = new SidedefFillJob();
|
||||
first.sidedef = start;
|
||||
first.forward = true;
|
||||
todo.Push(first);
|
||||
}
|
||||
|
||||
// Continue until nothing more to align
|
||||
while(todo.Count > 0)
|
||||
{
|
||||
// Get the align job to do
|
||||
SidedefFillJob j = todo.Pop();
|
||||
|
||||
if(j.forward)
|
||||
{
|
||||
Vertex v;
|
||||
|
||||
// Apply texturing
|
||||
if(j.sidedef.LongHighTexture == texture.LongName) j.sidedef.SetTextureHigh(filltexture.Name);
|
||||
if(j.sidedef.LongMiddleTexture == texture.LongName) j.sidedef.SetTextureMid(filltexture.Name);
|
||||
if(j.sidedef.LongLowTexture == texture.LongName) j.sidedef.SetTextureLow(filltexture.Name);
|
||||
j.sidedef.Marked = true;
|
||||
|
||||
// Add sidedefs forward (connected to the right vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
||||
AddSidedefsForFloodfill(todo, v, true, texture.LongName);
|
||||
|
||||
// Add sidedefs backward (connected to the left vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
||||
AddSidedefsForFloodfill(todo, v, false, texture.LongName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vertex v;
|
||||
|
||||
// Apply texturing
|
||||
if(j.sidedef.LongHighTexture == texture.LongName) j.sidedef.SetTextureHigh(filltexture.Name);
|
||||
if(j.sidedef.LongMiddleTexture == texture.LongName) j.sidedef.SetTextureMid(filltexture.Name);
|
||||
if(j.sidedef.LongLowTexture == texture.LongName) j.sidedef.SetTextureLow(filltexture.Name);
|
||||
j.sidedef.Marked = true;
|
||||
|
||||
// Add sidedefs backward (connected to the left vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.Start : j.sidedef.Line.End;
|
||||
AddSidedefsForFloodfill(todo, v, false, texture.LongName);
|
||||
|
||||
// Add sidedefs forward (connected to the right vertex)
|
||||
v = j.sidedef.IsFront ? j.sidedef.Line.End : j.sidedef.Line.Start;
|
||||
AddSidedefsForFloodfill(todo, v, true, texture.LongName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This adds the matching, unmarked sidedefs from a vertex for texture alignment
|
||||
private static void AddSidedefsForFloodfill(Stack<SidedefFillJob> stack, Vertex v, bool forward, long texturelongname)
|
||||
{
|
||||
foreach(Linedef ld in v.Linedefs)
|
||||
{
|
||||
Sidedef side1 = forward ? ld.Front : ld.Back;
|
||||
Sidedef side2 = forward ? ld.Back : ld.Front;
|
||||
if((ld.Start == v) && (side1 != null) && !side1.Marked)
|
||||
{
|
||||
if(SidedefTextureMatch(side1, texturelongname))
|
||||
{
|
||||
SidedefFillJob nj = new SidedefFillJob();
|
||||
nj.forward = forward;
|
||||
nj.sidedef = side1;
|
||||
stack.Push(nj);
|
||||
}
|
||||
}
|
||||
else if((ld.End == v) && (side2 != null) && !side2.Marked)
|
||||
{
|
||||
if(SidedefTextureMatch(side2, texturelongname))
|
||||
{
|
||||
SidedefFillJob nj = new SidedefFillJob();
|
||||
nj.forward = forward;
|
||||
nj.sidedef = side2;
|
||||
stack.Push(nj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ================== Texture Alignment
|
||||
|
||||
// This performs texture alignment along all walls that match with the same texture
|
||||
|
|
|
@ -315,19 +315,21 @@ namespace CodeImp.DoomBuilder.Windows
|
|||
{
|
||||
// Get info
|
||||
int thiskey = (int)listactions.SelectedItems[0].SubItems[1].Tag;
|
||||
|
||||
// Find actions with same key
|
||||
foreach(ListViewItem item in listactions.Items)
|
||||
if(thiskey != 0)
|
||||
{
|
||||
// Don't count the selected action
|
||||
if(item != listactions.SelectedItems[0])
|
||||
// Find actions with same key
|
||||
foreach(ListViewItem item in listactions.Items)
|
||||
{
|
||||
Action a = General.Actions[item.Name];
|
||||
int akey = (int)item.SubItems[1].Tag;
|
||||
|
||||
// Check if the key combination matches
|
||||
if((thiskey & a.ShortcutMask) == (akey & a.ShortcutMask))
|
||||
usedactions.Add(General.Actions.Categories[a.Category] + ": " + a.Title);
|
||||
// Don't count the selected action
|
||||
if(item != listactions.SelectedItems[0])
|
||||
{
|
||||
Action a = General.Actions[item.Name];
|
||||
int akey = (int)item.SubItems[1].Tag;
|
||||
|
||||
// Check if the key combination matches
|
||||
if((thiskey & a.ShortcutMask) == (akey & a.ShortcutMask))
|
||||
usedactions.Add(a.Title + " (" + General.Actions.Categories[a.Category] + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue