- 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:
codeimp 2009-01-12 22:00:31 +00:00
parent 69f608ddbc
commit 599b8ce667
9 changed files with 189 additions and 13 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 ""; }

View file

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

View file

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

View file

@ -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] + ")");
}
}
}
}