From e4b8a6ba2b53c5e9c47e76035aac6f48be83e706 Mon Sep 17 00:00:00 2001 From: spherallic Date: Thu, 27 Apr 2023 03:37:36 +0200 Subject: [PATCH] Improved associations --- .../Core/Windows/PreferencesForm.Designer.cs | 46 ++ .../BuilderModes/ClassicModes/LinedefsMode.cs | 72 +- .../BuilderModes/ClassicModes/SectorsMode.cs | 17 +- .../BuilderModes/ClassicModes/ThingsMode.cs | 58 +- .../BuilderModes/General/Association.cs | 756 ++++++++++++++++-- .../BuilderModes/General/BuilderPlug.cs | 179 +---- .../BuilderModes/Interface/PreferencesForm.cs | 4 + 7 files changed, 795 insertions(+), 337 deletions(-) diff --git a/Source/Core/Windows/PreferencesForm.Designer.cs b/Source/Core/Windows/PreferencesForm.Designer.cs index ba94fc8..13c9aee 100644 --- a/Source/Core/Windows/PreferencesForm.Designer.cs +++ b/Source/Core/Windows/PreferencesForm.Designer.cs @@ -232,6 +232,9 @@ namespace CodeImp.DoomBuilder.Windows this.pasteoptions = new CodeImp.DoomBuilder.Controls.PasteOptionsControl(); this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); this.browseScreenshotsFolderDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.eventlinelabelvisibility = new System.Windows.Forms.ComboBox(); + this.eventlinelabelstyle = new System.Windows.Forms.ComboBox(); label7 = new System.Windows.Forms.Label(); label5 = new System.Windows.Forms.Label(); groupBox1 = new System.Windows.Forms.GroupBox(); @@ -257,6 +260,7 @@ namespace CodeImp.DoomBuilder.Windows this.groupBox5.SuspendLayout(); this.groupBox4.SuspendLayout(); this.groupBox2.SuspendLayout(); + this.groupBox1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.vertexScale3D)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.viewdistance)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.movespeed)).BeginInit(); @@ -2651,6 +2655,44 @@ namespace CodeImp.DoomBuilder.Windows // browseScreenshotsFolderDialog // this.browseScreenshotsFolderDialog.Description = "Select a Folder to Save Screenshots Into"; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.eventlinelabelstyle); + this.groupBox1.Controls.Add(this.eventlinelabelvisibility); + this.groupBox1.Location = new System.Drawing.Point(6, 445); + this.groupBox1.Name = "groupBox5"; + this.groupBox1.Size = new System.Drawing.Size(272, 54); + this.groupBox1.TabIndex = 4; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Event line labels"; + // + // eventlinelabelvisibility + // + this.eventlinelabelvisibility.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.eventlinelabelvisibility.FormattingEnabled = true; + this.eventlinelabelvisibility.Items.AddRange(new object[] { + "Never show", + "Forward only", + "Reverse only", + "Forward + Reverse"}); + this.eventlinelabelvisibility.Location = new System.Drawing.Point(6, 19); + this.eventlinelabelvisibility.Name = "eventlinelabelvisibility"; + this.eventlinelabelvisibility.Size = new System.Drawing.Size(121, 21); + this.eventlinelabelvisibility.TabIndex = 0; + // + // eventlinelabelstyle + // + this.eventlinelabelstyle.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.eventlinelabelstyle.FormattingEnabled = true; + this.eventlinelabelstyle.Items.AddRange(new object[] { + "Action only", + "Action + short arguments", + "Action + full arguments"}); + this.eventlinelabelstyle.Location = new System.Drawing.Point(133, 19); + this.eventlinelabelstyle.Name = "eventlinelabelstyle"; + this.eventlinelabelstyle.Size = new System.Drawing.Size(133, 21); + this.eventlinelabelstyle.TabIndex = 1; // // PreferencesForm // @@ -2726,6 +2768,7 @@ namespace CodeImp.DoomBuilder.Windows this.groupBox6.ResumeLayout(false); this.groupBox6.PerformLayout(); this.tabpasting.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); this.ResumeLayout(false); } @@ -2923,5 +2966,8 @@ namespace CodeImp.DoomBuilder.Windows private System.Windows.Forms.ComboBox textlabelfontsize; private CodeImp.DoomBuilder.Controls.ColorControl colorguidelines; private System.Windows.Forms.CheckBox autolaunchontest; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.ComboBox eventlinelabelvisibility; + private System.Windows.Forms.ComboBox eventlinelabelstyle; } } \ No newline at end of file diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs index 8748706..a95cae9 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs @@ -57,8 +57,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Highlighted item private Linedef highlighted; - private readonly Association[] association = new Association[Linedef.NUM_ARGS]; - private readonly Association highlightasso = new Association(); + private readonly Association highlightasso; private Vector2D insertpreview = new Vector2D(float.NaN, float.NaN); //mxd //mxd. Text labels @@ -86,8 +85,7 @@ namespace CodeImp.DoomBuilder.BuilderModes public LinedefsMode() { //mxd. Associations now requre initializing... - for(int i = 0; i < association.Length; i++) association[i] = new Association(); - + highlightasso = new Association(renderer); textlabelsizecache = new Dictionary(); } @@ -152,9 +150,9 @@ namespace CodeImp.DoomBuilder.BuilderModes labels[highlighted].Color = General.Colors.Highlight; completeredraw = true; } - + // Previous association highlights something? - if(highlighted.Tag != 0) completeredraw = true; + if (!highlightasso.IsEmpty) completeredraw = true; } // Set highlight association @@ -168,57 +166,18 @@ namespace CodeImp.DoomBuilder.BuilderModes } // New association highlights something? - if(l.Tag != 0) - { - highlightasso.Set(new Vector2D((l.Start.Position + l.End.Position) / 2), l.Tags, UniversalType.LinedefTag); - completeredraw = true; - } + highlightasso.Set(l); + + // Only need a complete redraw if the association contains elements + if (!highlightasso.IsEmpty) completeredraw = true; } else { - highlightasso.Set(new Vector2D(), 0, 0); + // Only need a complete redraw if the old association wasn't empty + if (!highlightasso.IsEmpty) completeredraw = true; + highlightasso.Clear(); } - // Use the line tag to highlight sectors (Doom style) - if(General.Map.Config.LineTagIndicatesSectors) - { - if(l != null) - association[0].Set(new Vector2D((l.Start.Position + l.End.Position)/2), l.Tags, UniversalType.SectorTag); - else - association[0].Set(new Vector2D(), 0, 0); - } - else - { - LinedefActionInfo action = null; - - if(l != null) - { - // Check if we can find the linedefs action - if((l.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(l.Action)) - action = General.Map.Config.LinedefActions[l.Action]; - } - - // Determine linedef associations - for(int i = 0; i < Linedef.NUM_ARGS; i++) - { - // Previous association highlights something? - if((association[i].Type == UniversalType.SectorTag) || - (association[i].Type == UniversalType.LinedefTag) || - (association[i].Type == UniversalType.ThingTag)) completeredraw = true; - - // Make new association - if(action != null) - association[i].Set(new Vector2D((l.Start.Position + l.End.Position)/2), l.Args[i], action.Args[i].Type); - else - association[i].Set(new Vector2D(), 0, 0); - - // New association highlights something? - if((association[i].Type == UniversalType.SectorTag) || - (association[i].Type == UniversalType.LinedefTag) || - (association[i].Type == UniversalType.ThingTag)) completeredraw = true; - } - } - // If we're changing associations, then we // need to redraw the entire display if(completeredraw) @@ -702,11 +661,11 @@ namespace CodeImp.DoomBuilder.BuilderModes if(renderer.StartPlotter(true)) { renderer.PlotLinedefSet(General.Map.Map.Linedefs); - for(int i = 0; i < Linedef.NUM_ARGS; i++) BuilderPlug.PlotAssociations(renderer, association[i], eventlines); if((highlighted != null) && !highlighted.IsDisposed) { - BuilderPlug.PlotReverseAssociations(renderer, highlightasso, eventlines); + //BuilderPlug.PlotReverseAssociations(renderer, highlightasso, eventlines); + highlightasso.Plot(); renderer.PlotLinedef(highlighted, General.Colors.Highlight); } renderer.PlotVerticesSet(General.Map.Map.Vertices); @@ -727,8 +686,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(!selecting) //mxd { - for(int i = 0; i < Linedef.NUM_ARGS; i++) BuilderPlug.RenderAssociations(renderer, association[i], eventlines); - if((highlighted != null) && !highlighted.IsDisposed) BuilderPlug.RenderReverseAssociations(renderer, highlightasso, eventlines); //mxd + if ((highlighted != null) && !highlighted.IsDisposed) highlightasso.Render(); //mxd } else { @@ -744,8 +702,6 @@ namespace CodeImp.DoomBuilder.BuilderModes renderer.RenderRectangleFilled(new RectangleF(insertpreview.x - vsize, insertpreview.y - vsize, vsize * 2.0f, vsize * 2.0f), General.Colors.InfoLine.WithAlpha(alpha), true); } - renderer.RenderArrows(eventlines); //mxd - //mxd. Render sector tag labels if(BuilderPlug.Me.ViewSelectionEffects) { diff --git a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs index 0f42763..4e3cfc7 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs @@ -56,7 +56,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Highlighted item private Sector highlighted; - private readonly Association highlightasso = new Association(); + private readonly Association highlightasso; // Interface private bool editpressed; @@ -93,6 +93,8 @@ namespace CodeImp.DoomBuilder.BuilderModes // Constructor public SectorsMode() { + highlightasso = new Association(renderer); + textlabelsizecache = new Dictionary(); //mxd @@ -444,12 +446,11 @@ namespace CodeImp.DoomBuilder.BuilderModes // Set highlight association if(s != null && s.Tag != 0) { - Vector2D center = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); - highlightasso.Set(center, s.Tags, UniversalType.SectorTag); + highlightasso.Set(s); } else { - highlightasso.Set(new Vector2D(), 0, 0); + highlightasso.Clear(); } // New association highlights something? @@ -920,7 +921,7 @@ namespace CodeImp.DoomBuilder.BuilderModes if((highlighted != null) && !highlighted.IsDisposed) { renderer.PlotSector(highlighted, General.Colors.Highlight); - BuilderPlug.PlotReverseAssociations(renderer, highlightasso, eventlines); + highlightasso.Plot(); } renderer.Finish(); } @@ -940,9 +941,9 @@ namespace CodeImp.DoomBuilder.BuilderModes // Render selection if(renderer.StartOverlay(false)) { - if(highlighted != null && !highlighted.IsDisposed) BuilderPlug.RenderReverseAssociations(renderer, highlightasso, eventlines); //mxd - if(selecting) RenderMultiSelection(); - renderer.RenderArrows(eventlines); //mxd + if (highlighted != null && !highlighted.IsDisposed) highlightasso.Render(); + if (selecting) RenderMultiSelection(); + renderer.Finish(); } diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs index 2bb0b1d..4131382 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs @@ -56,9 +56,7 @@ namespace CodeImp.DoomBuilder.BuilderModes // Highlighted item private Thing highlighted; - private readonly Association[] association = new Association[Thing.NUM_ARGS]; - private readonly Association directasso = new Association(); - private readonly Association highlightasso = new Association(); + private readonly Association highlightasso; // Interface private bool editpressed; @@ -90,8 +88,7 @@ namespace CodeImp.DoomBuilder.BuilderModes public ThingsMode() { //mxd. Associations now requre initializing... - for(int i = 0; i < association.Length; i++) association[i] = new Association(); - directasso = new Association(); + highlightasso = new Association(renderer); } //mxd @@ -241,8 +238,7 @@ namespace CodeImp.DoomBuilder.BuilderModes renderer.PlotLinedefSet(General.Map.Map.Linedefs); renderer.PlotVerticesSet(General.Map.Map.Vertices); - for(int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.PlotAssociations(renderer, association[i], eventlines); - if((highlighted != null) && !highlighted.IsDisposed) BuilderPlug.PlotReverseAssociations(renderer, highlightasso, eventlines); + if (highlighted != null && !highlighted.IsDisposed) highlightasso.Plot(); renderer.Finish(); } @@ -254,13 +250,11 @@ namespace CodeImp.DoomBuilder.BuilderModes renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, General.Settings.HiddenThingsAlpha); renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, alpha); renderer.RenderNiGHTSPath(); - for (int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.RenderAssociations(renderer, association[i], eventlines); - BuilderPlug.RenderAssociations(renderer, directasso, eventlines); if((highlighted != null) && !highlighted.IsDisposed) { renderer.RenderThing(highlighted, General.Colors.Highlight, alpha); - BuilderPlug.RenderReverseAssociations(renderer, highlightasso, eventlines); //mxd + highlightasso.Render(); } //mxd. Event lines @@ -363,11 +357,11 @@ namespace CodeImp.DoomBuilder.BuilderModes linktype = ti.ThingLink; // New association highlights something? - if(t.Tag != 0) highlightasso.Set(t.Position, t.Tag, UniversalType.ThingTag, linktype); + highlightasso.Set(t); } else { - highlightasso.Set(new Vector2D(), 0, 0); + highlightasso.Clear(); } if(highlighted != null) //mxd @@ -378,46 +372,6 @@ namespace CodeImp.DoomBuilder.BuilderModes highlighted.Highlighted = false; } - //mxd. Determine thing associations - bool clearassociations = true; //mxd - if(t != null) - { - t.Highlighted = true; //mxd - - // Check if we can find the linedefs action - if((t.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(t.Action)) - { - clearassociations = false; - LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action]; - for(int i = 0; i < Thing.NUM_ARGS; i++) - association[i].Set(t.Position, t.Args[i], action.Args[i].Type); - - //Some things, such as Patrol and Interpolation specials, are associated via a shared tag rather than an argument - ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); - if (ti != null && ti.ThingLink < 0) - directasso.Set(t.Position, t.Tag, (int)UniversalType.ThingTag); - } - //mxd. Check if we can use thing arguments - else if(t.Action == 0) - { - ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); - if(ti != null) - { - clearassociations = false; - for(int i = 0; i < Thing.NUM_ARGS; i++) - association[i].Set(t.Position, t.Args[i], ti.Args[i].Type); - } - } - } - - // mxd. Clear associations? - if(clearassociations) - { - for (int i = 0; i < Thing.NUM_ARGS; i++) - association[i].Set(new Vector2D(), 0, 0); - directasso.Set(new Vector2D(), 0, 0); - } - // Set new highlight and redraw display highlighted = t; General.Interface.RedrawDisplay(); diff --git a/Source/Plugins/BuilderModes/General/Association.cs b/Source/Plugins/BuilderModes/General/Association.cs index 70a2423..5af4844 100644 --- a/Source/Plugins/BuilderModes/General/Association.cs +++ b/Source/Plugins/BuilderModes/General/Association.cs @@ -16,9 +16,16 @@ #region ================== Namespaces +using System; using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; using CodeImp.DoomBuilder.Types; +using CodeImp.DoomBuilder.Windows; #endregion @@ -30,97 +37,748 @@ namespace CodeImp.DoomBuilder.BuilderModes private Vector2D center; private UniversalType type; private int directlinktype; + private int directlinktype; + private Dictionary> eventlines; + private IRenderer2D renderer; + private SelectableElement element; + private List distinctcolors; + private Font font; + private Dictionary textwidths; + private Dictionary> textlabels; + + // Map elements that are associated + private List things; + private List sectors; + private List linedefs; public HashSet Tags { get { return tags; } } public Vector2D Center { get { return center; } } public UniversalType Type { get { return type; } } public int DirectLinkType { get { return directlinktype; } } + public List Things { get { return things; } } + public List Sectors { get { return sectors; } } + public List Linedefs { get { return linedefs; } } + public bool IsEmpty { get { return things.Count == 0 && sectors.Count == 0 && linedefs.Count == 0; } } //mxd. This sets up the association - public Association() + public Association(IRenderer2D renderer) { this.tags = new HashSet { 0 }; + this.renderer = renderer; + + things = new List(); + sectors = new List(); + linedefs = new List(); + eventlines = new Dictionary>(); + + font = new Font(new FontFamily(General.Settings.TextLabelFontName), General.Settings.TextLabelFontSize, (General.Settings.TextLabelFontBold ? FontStyle.Bold : FontStyle.Regular)); + + distinctcolors = new List + { + General.Colors.InfoLine, + PixelColor.FromInt(0x84d5a4).WithAlpha(255), + PixelColor.FromInt(0xc059cb).WithAlpha(255), + PixelColor.FromInt(0xd0533d).WithAlpha(255), + // PixelColor.FromInt(0x415354).WithAlpha(255), // too dark + PixelColor.FromInt(0xcea953).WithAlpha(255), + PixelColor.FromInt(0x91d44b).WithAlpha(255), + PixelColor.FromInt(0xcd5b89).WithAlpha(255), + PixelColor.FromInt(0xa8b6c0).WithAlpha(255), + PixelColor.FromInt(0x797ecb).WithAlpha(255), + // PixelColor.FromInt(0x567539).WithAlpha(255), // too dark + // PixelColor.FromInt(0x72422f).WithAlpha(255), // too dark + // PixelColor.FromInt(0x5d3762).WithAlpha(255), // too dark + PixelColor.FromInt(0xffed6f).WithAlpha(255), + PixelColor.FromInt(0xccebc5).WithAlpha(255), + PixelColor.FromInt(0xbc80bd).WithAlpha(255), + // PixelColor.FromInt(0xd9d9d9).WithAlpha(255), // too gray + PixelColor.FromInt(0xfccde5).WithAlpha(255), + PixelColor.FromInt(0x80b1d3).WithAlpha(255), + PixelColor.FromInt(0xfdb462).WithAlpha(255), + PixelColor.FromInt(0xb3de69).WithAlpha(255), + PixelColor.FromInt(0xfb8072).WithAlpha(255), + PixelColor.FromInt(0xbebada).WithAlpha(255), // too blue/gray? + PixelColor.FromInt(0xffffb3).WithAlpha(255), + PixelColor.FromInt(0x8dd3c7).WithAlpha(255), + }; } - // This sets up the association - public Association(Vector2D center, int tag, int type) + /// + /// Sets the association to a map element. Only works with an instance of Thing, Sector, or Linedef. + /// Also gets the forward and reverse associations + /// + /// An instance of Thing, Sector, or Linedef + public void Set(SelectableElement element) { - this.tags = new HashSet { tag }; //mxd - this.type = (UniversalType)type; - this.center = center; + this.element = element; + things = new List(); + sectors = new List(); + linedefs = new List(); + eventlines = new Dictionary>(); + + if (element is Sector) + { + Sector s = element as Sector; + center = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); + + type = UniversalType.SectorTag; + tags = new HashSet(s.Tags); + } + else if(element is Linedef) + { + Linedef ld = element as Linedef; + center = ld.GetCenterPoint(); + + type = UniversalType.LinedefTag; + tags = new HashSet(ld.Tags); + } + else if(element is Thing) + { + Thing t = element as Thing; + center = t.Position; + + ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); + directlinktype = ti.ThingLink; + + type = UniversalType.ThingTag; + tags = new HashSet(new int[] { t.Tag }); + } + + // Remove the tag 0, because nothing sensible will come from it + tags.Remove(0); + + // Get forward and reverse associations + GetAssociations(); + + // Cache width of label text and generate the labels + textwidths = new Dictionary(eventlines.Count); + textlabels = new Dictionary>(eventlines.Count); + + foreach(KeyValuePair> kvp in eventlines) + { + SizeF size = General.Interface.MeasureString(kvp.Key, font); + textwidths[kvp.Key] = new Vector2D(size.Width, size.Height); + + // Create one label for each line. We might not need them all, but better + // to have them all at the beginning than to generate them later + textlabels[kvp.Key] = new List(kvp.Value.Count); + + for (int i = 0; i < kvp.Value.Count; i++) + { + // We don't need to set the position here, since it'll be done on the fly later + TextLabel l = new TextLabel(); + l.AlignX = TextAlignmentX.Center; + l.AlignY = TextAlignmentY.Middle; + l.TransformCoords = true; + l.Text = kvp.Key; + + textlabels[kvp.Key].Add(l); + } + + textwidths[kvp.Key] = new Vector2D(textlabels[kvp.Key][0].TextSize.Width, textlabels[kvp.Key][0].TextSize.Height); + } + + SetEventLineColors(); } - // This sets up the association - public Association(Vector2D center, int tag, UniversalType type) + /// + /// Clears out all lists so that the association appears empty + /// + public void Clear() { - this.tags = new HashSet { tag }; //mxd - this.type = type; - this.center = center; + tags = new HashSet(); + things = new List(); + sectors = new List(); + linedefs = new List(); + eventlines = new Dictionary>(); } - //mxd. This also sets up the association - public Association(Vector2D center, IEnumerable tags, int type) + /// + /// Get the forward and reverse associations between the element and other map elements + /// + private void GetAssociations() { - this.tags = new HashSet(tags); //mxd - this.type = (UniversalType)type; - this.center = center; + Dictionary> actiontags = new Dictionary>(); + bool showforwardlabel = BuilderPlug.Me.EventLineLabelVisibility == 1 || BuilderPlug.Me.EventLineLabelVisibility == 3; + bool showreverselabel = BuilderPlug.Me.EventLineLabelVisibility == 2 || BuilderPlug.Me.EventLineLabelVisibility == 3; + + // Special handling for Doom format maps where there the linedef's tag references sectors + if (General.Map.Config.LineTagIndicatesSectors) + { + if (tags.Count == 0) + return; + + // Forward association from linedef to sector + if (element is Linedef) + { + foreach (Sector s in General.Map.Map.Sectors) + { + if (tags.Contains(s.Tag)) + { + Vector2D sectorcenter = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); + + sectors.Add(s); + + AddLineToAction(showforwardlabel ? GetActionDescription(element) : string.Empty, center, sectorcenter); + } + } + } + else if(element is Sector) + { + foreach(Linedef ld in General.Map.Map.Linedefs) + { + if(tags.Contains(ld.Tag)) + { + linedefs.Add(ld); + + AddLineToAction(showreverselabel ? GetActionDescription(ld) : string.Empty, ld.GetCenterPoint(), center); + } + } + } + + return; + } + + // Get tags of map elements the element is referencing. This is used for the forward associations + if (element is Linedef || element is Thing) + actiontags = GetTagsByType(); + + // Store presence of different types once, so that we don't have to do a lookup for each map element + bool hassectortags = actiontags.ContainsKey((int)UniversalType.SectorTag); + bool haslinedeftags = actiontags.ContainsKey((int)UniversalType.LinedefTag); + bool hasthingtag = actiontags.ContainsKey((int)UniversalType.ThingTag); + + // Process all sectors in the map + foreach (Sector s in General.Map.Map.Sectors) + { + bool addforward = false; + bool addreverse = false; + + // Check for forward association (from the element to the sector) + if (hassectortags && actiontags[(int)UniversalType.SectorTag].Overlaps(s.Tags)) + addforward = true; + + // Check the reverse association (from the sector to the element) + // Nothing here yet + + if (addforward || addreverse) + { + Vector2D sectorcenter = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); + + sectors.Add(s); + + if (addforward) + AddLineToAction(showforwardlabel ? GetActionDescription(element) : string.Empty, center, sectorcenter); + + if (addreverse) + AddLineToAction(showreverselabel ? GetActionDescription(element) : string.Empty, sectorcenter, center); + } + } + + // Process all linedefs in the map + foreach(Linedef ld in General.Map.Map.Linedefs) + { + bool addforward = false; + bool addreverse = false; + + // Check the forward association (from the element to the linedef) + if (haslinedeftags && actiontags[(int)UniversalType.LinedefTag].Overlaps(ld.Tags)) + addforward = true; + + // Check the reverse association (from the linedef to the element) + if (IsAssociatedToLinedef(ld)) + addreverse = true; + + if (addforward || addreverse) + { + linedefs.Add(ld); + + if (addforward) + AddLineToAction(showforwardlabel ? GetActionDescription(element) : string.Empty, center, ld.GetCenterPoint()); + + if (addreverse) + AddLineToAction(showreverselabel ? GetActionDescription(ld) : string.Empty, ld.GetCenterPoint(), center); + } + } + + // Doom format only knows associations between linedefs and sectors, but not thing, so stop here + if (General.Map.DOOM) + return; + + // Process all things in the map + foreach(Thing t in General.Map.Map.Things) + { + bool addforward = false; + bool addreverse = false; + + // Check the forward association (from the element to the thing) + if (hasthingtag && actiontags[(int)UniversalType.ThingTag].Contains(t.Tag)) + addforward = true; + + // Check the reverse association (from the thing to the element). Only works for Hexen and UDMF, + // as Doom format doesn't have any way to reference other map elements + if (IsAssociatedToThing(t)) + addreverse = true; + + if (addforward || addreverse) + { + things.Add(t); + + if (addforward) + AddLineToAction(showforwardlabel ? GetActionDescription(element) : string.Empty, center, t.Position); + + if (addreverse) + AddLineToAction(showreverselabel ? GetActionDescription(t) : string.Empty, t.Position, center); + } + } } - //mxd. This also sets up the association - public Association(Vector2D center, IEnumerable tags, UniversalType type) + /// + /// Gets a dictionary of sector tags, linedef tags, and thing tags, grouped by their type, that the map element is referencing + /// + /// Dictionary of sector tags, linedef tags, and thing tags that the map element is referencing + private Dictionary> GetTagsByType() { - this.tags = new HashSet(tags); //mxd - this.type = type; - this.center = center; + LinedefActionInfo action = null; + int[] actionargs = new int[5]; + Dictionary> actiontags = new Dictionary>(); + + // Get the action and its arguments from a linedef or a thing, if they have them + if (element is Linedef) + { + Linedef ld = element as Linedef; + + if (ld.Action > 0 && General.Map.Config.LinedefActions.ContainsKey(ld.Action)) + action = General.Map.Config.LinedefActions[ld.Action]; + + actionargs = ld.Args; + } + else if (element is Thing) + { + Thing t = element as Thing; + + if (t.Action > 0 && General.Map.Config.LinedefActions.ContainsKey(t.Action)) + action = General.Map.Config.LinedefActions[t.Action]; + + actionargs = t.Args; + } + else // element is a Sector + { + return actiontags; + } + + if (action != null) + { + // Collect what map element the action arguments are referencing. Ignore the argument if it's 0, so that they + // are not associated to everything untagged + for (int i = 0; i < Linedef.NUM_ARGS; i++) + { + if ((action.Args[i].Type == (int)UniversalType.SectorTag || + action.Args[i].Type == (int)UniversalType.LinedefTag || + action.Args[i].Type == (int)UniversalType.ThingTag) && + actionargs[i] > 0) + { + if (!actiontags.ContainsKey(action.Args[i].Type)) + actiontags[action.Args[i].Type] = new HashSet(); + + actiontags[action.Args[i].Type].Add(actionargs[i]); + } + } + } + else if (element is Thing && directlinktype >= 0 && Math.Abs(directlinktype) != ((Thing)element).Type) + { + // The direct link shenanigans if the thing doesn't have an action, but still reference something through + // the action parameters + Thing t = element as Thing; + ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); + + if (ti != null && directlinktype >= 0 && Math.Abs(directlinktype) != t.Type) + { + for (int i = 0; i < Linedef.NUM_ARGS; i++) + { + if ((ti.Args[i].Type == (int)UniversalType.SectorTag || + ti.Args[i].Type == (int)UniversalType.LinedefTag || + ti.Args[i].Type == (int)UniversalType.ThingTag)) + { + if (!actiontags.ContainsKey(ti.Args[i].Type)) + actiontags[ti.Args[i].Type] = new HashSet(); + + actiontags[ti.Args[i].Type].Add(actionargs[i]); + } + + } + } + } + + return actiontags; } - // This sets up the association - public void Set(Vector2D center, int tag, int type) + /// + /// Checks if there's an association between the element and a Linedef + /// + /// Linedef to check the association against + /// true if the Linedef and the element are associated, false if not + private bool IsAssociatedToLinedef(Linedef linedef) { - this.Set(center, tag, type, 0); + // Doom style reference from linedef to sector? + if (General.Map.Config.LineTagIndicatesSectors && element is Sector) + { + if (linedef.Action > 0 && tags.Overlaps(linedef.Tags)) + return true; + } + + // Known action on this line? + if ((linedef.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(linedef.Action)) + { + LinedefActionInfo action = General.Map.Config.LinedefActions[linedef.Action]; + if (((action.Args[0].Type == (int)type) && (linedef.Args[0] != 0) && (tags.Contains(linedef.Args[0]))) || + ((action.Args[1].Type == (int)type) && (linedef.Args[1] != 0) && (tags.Contains(linedef.Args[1]))) || + ((action.Args[2].Type == (int)type) && (linedef.Args[2] != 0) && (tags.Contains(linedef.Args[2]))) || + ((action.Args[3].Type == (int)type) && (linedef.Args[3] != 0) && (tags.Contains(linedef.Args[3]))) || + ((action.Args[4].Type == (int)type) && (linedef.Args[4] != 0) && (tags.Contains(linedef.Args[4])))) + { + return true; + } + } + + return false; } - public void Set(Vector2D center, int tag, int type, int directlinktype) + /// + /// Checks if there's an association between the element and a Thing + /// + /// Thing to check the association against + /// true if the Thing and the element are associated, false if not + private bool IsAssociatedToThing(Thing thing) { - this.tags = new HashSet { tag }; //mxd - this.type = (UniversalType)type; - this.center = center; - this.directlinktype = directlinktype; + // Get the thing type info + ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(thing.Type); + + // Known action on this thing? + if ((thing.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(thing.Action)) + { + //Do not draw the association if this is a child link. + // This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead. + if (ti != null && directlinktype < 0 && directlinktype != -thing.Type) + return false; + + LinedefActionInfo action = General.Map.Config.LinedefActions[thing.Action]; + if (((action.Args[0].Type == (int)type) && (tags.Contains(thing.Args[0]))) || + ((action.Args[1].Type == (int)type) && (tags.Contains(thing.Args[1]))) || + ((action.Args[2].Type == (int)type) && (tags.Contains(thing.Args[2]))) || + ((action.Args[3].Type == (int)type) && (tags.Contains(thing.Args[3]))) || + ((action.Args[4].Type == (int)type) && (tags.Contains(thing.Args[4])))) + { + return true; + } + + //If there is a link setup on this thing, and it matches the association, then draw a direct link to any matching tag + if (ti != null && directlinktype == thing.Type && tags.Contains(thing.Tag)) + { + return true; + } + } + //mxd. Thing action on this thing? + else if (thing.Action == 0) + { + // Gets the association, unless it is a child link. + // This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead. + if (ti != null && directlinktype >= 0 && Math.Abs(directlinktype) != thing.Type) + { + if (((ti.Args[0].Type == (int)type) && (tags.Contains(thing.Args[0]))) || + ((ti.Args[1].Type == (int)type) && (tags.Contains(thing.Args[1]))) || + ((ti.Args[2].Type == (int)type) && (tags.Contains(thing.Args[2]))) || + ((ti.Args[3].Type == (int)type) && (tags.Contains(thing.Args[3]))) || + ((ti.Args[4].Type == (int)type) && (tags.Contains(thing.Args[4])))) + { + return true; + } + } + } + + return false; } - // This sets up the association - public void Set(Vector2D center, int tag, UniversalType type) + /// + /// Returns a string that contains the description of the action and its arguments, based on the given Linedef or Thing + /// + /// An instance of Thing or Linedef + /// String that contains the description of the action and its arguments for a given Linedef or Thing + private string GetActionDescription(SelectableElement se) { - this.Set(center, tag, type, 0); + int action = 0; + int[] actionargs = new int[5]; + + if (se is Thing) + { + action = ((Thing)se).Action; + actionargs = ((Thing)se).Args; + } + else if(se is Linedef) + { + action = ((Linedef)se).Action; + actionargs = ((Linedef)se).Args; + } + + if (action > 0) + { + LinedefActionInfo lai = General.Map.Config.GetLinedefActionInfo(action); + List argdescription = new List(); + + string description = lai.Index + ": " + lai.Title; + + // Label style: only action, or if the element can't have any parameters + if (BuilderPlug.Me.EventLineLabelStyle == 0 || General.Map.Config.LineTagIndicatesSectors) + return description; + + for (int i=0; i < 5; i++) + { + if(lai.Args[i].Used) + { + string argstring = ""; + + if(BuilderPlug.Me.EventLineLabelStyle == 2) // Label style: full arguments + argstring = lai.Args[i].Title + ": "; + + EnumItem ei = lai.Args[i].Enum.GetByEnumIndex(actionargs[i].ToString()); + + if (ei != null && BuilderPlug.Me.EventLineLabelStyle == 2) // Label style: full arguments + argstring += ei.ToString(); + else // Argument has no EnumItem or label style: short arguments + argstring += actionargs[i].ToString(); + + argdescription.Add(argstring); + } + } + + description += " (" + string.Join(", ", argdescription) + ")"; + + return description; + } + + return null; } - public void Set(Vector2D center, int tag, UniversalType type, int directlinktype) + /// + /// Sets a different color for each event + /// + private void SetEventLineColors() { - this.tags = new HashSet { tag }; //mxd - this.type = type; - this.center = center; - this.directlinktype = directlinktype; + int colorindex = 0; + + foreach(KeyValuePair> kvp in textlabels) + { + foreach (Line3D l in eventlines[kvp.Key]) + l.Color = distinctcolors[colorindex]; + + foreach (TextLabel l in kvp.Value) + l.Color = distinctcolors[colorindex]; + + if(BuilderPlug.Me.EventLineDistinctColors) + if (++colorindex >= distinctcolors.Count) + colorindex = 0; + } } - //mxd. This also sets up the association - public void Set(Vector2D center, IEnumerable tags, int type) + /// + /// Adds a line to an action + /// + /// Name of the action + /// Start of the line + /// End of the line + private void AddLineToAction(string action, Vector2D start, Vector2D end) { - this.Set(center, tags, (UniversalType)type, 0); + if (action == null) + return; + + if (!eventlines.ContainsKey(action)) + eventlines[action] = new List(); + + eventlines[action].Add(new Line3D(start, end, true)); } - //mxd. This also sets up the association - public void Set(Vector2D center, IEnumerable tags, UniversalType type) + /// + /// Generates a label position given a start and end point of a line. Taken (with modifications) from LineLengthLabel.Move() + /// + /// Start of the line + /// End of the line + /// + private Vector2D GetLabelPosition(Vector2D start, Vector2D end) { - this.Set(center, tags, type, 0); + // Check if start/end point is on screen... + Vector2D lt = General.Map.Renderer2D.DisplayToMap(new Vector2D(0.0, General.Interface.Display.Size.Height)); + Vector2D rb = General.Map.Renderer2D.DisplayToMap(new Vector2D(General.Interface.Display.Size.Width, 0.0)); + RectangleF viewport = new RectangleF((float)lt.x, (float)lt.y, (float)(rb.x - lt.x), (float)(rb.y - lt.y)); + bool startvisible = viewport.Contains((float)start.x, (float)start.y); + bool endvisible = viewport.Contains((float)end.x, (float)end.y); + + // Do this only when one point is visible, an the other isn't + if ((!startvisible && endvisible) || (startvisible && !endvisible)) + { + Line2D drawnline = new Line2D(start, end); + Line2D[] viewportsides = new[] { + new Line2D(lt, rb.x, lt.y), // top + new Line2D(lt.x, rb.y, rb.x, rb.y), // bottom + new Line2D(lt, lt.x, rb.y), // left + new Line2D(rb.x, lt.y, rb.x, rb.y), // right + }; + + foreach (Line2D side in viewportsides) + { + // Modify the start point so it stays on screen + double u; + if (!startvisible && side.GetIntersection(drawnline, out u)) + { + start = drawnline.GetCoordinatesAt(u); + break; + } + + // Modify the end point so it stays on screen + if (!endvisible && side.GetIntersection(drawnline, out u)) + { + end = drawnline.GetCoordinatesAt(u); + break; + } + } + } + + // Create position + Vector2D delta = end - start; + return new Vector2D(start.x + delta.x * 0.5, start.y + delta.y * 0.5); } - //mxd. This also sets up the association - public void Set(Vector2D center, IEnumerable tags, UniversalType type, int directlinktype) + /// + /// Merges label positions based on a merge distance + /// + /// Positions to merge + /// Distance to merge positions at + /// List of new positions + List MergePositions(List positions, Vector2D distance) { - this.tags = new HashSet(tags); //mxd - this.type = type; - this.center = center; - this.directlinktype = directlinktype; + List allpositions = positions.OrderBy(o => o.x).ToList(); + List newpositions = new List(positions.Count); + Vector2D mergedistance = distance / renderer.Scale * 1.5; + + // Keep going while we have positions me might want to merge + while (allpositions.Count > 0) + { + Vector2D curposition = allpositions[0]; + allpositions.RemoveAt(0); + + bool hasclosepositions = true; + + // Keep merging as long as there are close positions nearby + while(hasclosepositions) + { + // Get all positions that are close to the current position + List closepositions = allpositions.Where(o => Math.Abs(curposition.x - o.x) < mergedistance.x && Math.Abs(curposition.y - o.y) < mergedistance.y).ToList(); + + if (closepositions.Count > 0) + { + Vector2D tl = curposition; + Vector2D br = curposition; + + // Get the max dimensions of the positions... + foreach (Vector2D v in closepositions) + { + if (v.x < tl.x) tl.x = v.x; + if (v.x > br.x) br.x = v.x; + if (v.y > tl.y) tl.y = v.y; + if (v.y < br.y) br.y = v.y; + + // Remove the position from the list so that it doesn't get checked again + allpositions.Remove(v); + } + + // ... and set the current position to the center of that + curposition.x = tl.x + (br.x - tl.x) / 2.0; + curposition.y = tl.y + (br.y - tl.y) / 2.0; + } + else + { + // The current position is a new final position + newpositions.Add(curposition); + hasclosepositions = false; + allpositions.Reverse(); + } + } + } + + return newpositions; + } + + + /// + /// Renders associated things and sectors in the indication color. + /// Also renders event lines, if that option is enabled + /// + public void Render() + { + bool showlabels = BuilderPlug.Me.EventLineLabelVisibility > 0; // Show labels at all? + + foreach (Thing t in things) + renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); + + // There must be a better way to do this + foreach(Sector s in sectors) + { + int highlightedColor = General.Colors.Highlight.WithAlpha(128).ToInt(); + FlatVertex[] verts = new FlatVertex[s.FlatVertices.Length]; + s.FlatVertices.CopyTo(verts, 0); + for (int i = 0; i < verts.Length; i++) verts[i].c = highlightedColor; + renderer.RenderGeometry(verts, null, true); + } + + if (General.Settings.GZShowEventLines) + { + List lines = new List(eventlines.Count); + List labels = new List(eventlines.Count); + + foreach(KeyValuePair> kvp in eventlines) + { + bool emptylabel = string.IsNullOrEmpty(kvp.Key); // Can be true if only either forward or reverse labels are shown + List allpositions = new List(kvp.Value.Count); + + foreach (Line3D line in kvp.Value) + { + if (showlabels && !emptylabel) + allpositions.Add(GetLabelPosition(line.Start, line.End)); + + lines.Add(line); + } + + if (showlabels && !emptylabel) + { + List positions = MergePositions(allpositions, textwidths[kvp.Key]); + int labelcounter = 0; + + // Set the position of the pre-generated labels. Only add the labels that are needed + foreach (Vector2D pos in positions) + { + textlabels[kvp.Key][labelcounter].Location = pos; + labels.Add(textlabels[kvp.Key][labelcounter]); + labelcounter++; + } + } + } + + renderer.RenderArrows(lines); + + if (showlabels) + renderer.RenderText(labels); + } + } + + /// + /// Plots associated linedefs and sectors + /// + public void Plot() + { + foreach(Linedef ld in linedefs) + renderer.PlotLinedef(ld, General.Colors.Indication); + + foreach (Sector s in sectors) + renderer.PlotSector(s, General.Colors.Indication); } // This compares an association diff --git a/Source/Plugins/BuilderModes/General/BuilderPlug.cs b/Source/Plugins/BuilderModes/General/BuilderPlug.cs index 2c15d96..77a4d2c 100644 --- a/Source/Plugins/BuilderModes/General/BuilderPlug.cs +++ b/Source/Plugins/BuilderModes/General/BuilderPlug.cs @@ -135,6 +135,9 @@ namespace CodeImp.DoomBuilder.BuilderModes private bool lockSectorTextureOffsetsWhileDragging; //mxd private bool syncthingedit; //mxd private bool alphabasedtexturehighlighting; //mxd + private int eventlinelabelvisibility; // 0 = never show, 1 = forward only, 2 = reverse only, 3 = forward + reverse + private int eventlinelabelstyle; // 0 = Action only, 1 = Action + short arguments, 2 = action + full arguments + private bool eventlinedistinctcolors; private bool selectchangedafterundoredo; #endregion @@ -192,6 +195,9 @@ namespace CodeImp.DoomBuilder.BuilderModes public bool LockSectorTextureOffsetsWhileDragging { get { return lockSectorTextureOffsetsWhileDragging; } internal set { lockSectorTextureOffsetsWhileDragging = value; } } //mxd public bool SyncronizeThingEdit { get { return syncthingedit; } internal set { syncthingedit = value; } } //mxd public bool AlphaBasedTextureHighlighting { get { return alphabasedtexturehighlighting; } internal set { alphabasedtexturehighlighting = value; } } //mxd + public int EventLineLabelVisibility { get { return eventlinelabelvisibility; } internal set { eventlinelabelvisibility = value; } } + public int EventLineLabelStyle { get { return eventlinelabelstyle; } internal set { eventlinelabelstyle = value; } } + public bool EventLineDistinctColors { get { return eventlinedistinctcolors; } internal set { eventlinedistinctcolors = value; } } public bool SelectChangedafterUndoRedo { get { return selectchangedafterundoredo; } internal set { selectchangedafterundoredo = value; } } //mxd. "Make Door" action persistent settings @@ -317,6 +323,9 @@ namespace CodeImp.DoomBuilder.BuilderModes autoAlignTextureOffsetsOnCreate = General.Settings.ReadPluginSetting("autoaligntextureoffsetsoncreate", false); //mxd dontMoveGeometryOutsideMapBoundary = General.Settings.ReadPluginSetting("dontmovegeometryoutsidemapboundary", false); //mxd syncSelection = General.Settings.ReadPluginSetting("syncselection", false); //mxd + eventlinelabelvisibility = General.Settings.ReadPluginSetting("eventlinelabelvisibility", 3); + eventlinelabelstyle = General.Settings.ReadPluginSetting("eventlinelabelstyle", 2); + eventlinedistinctcolors = General.Settings.ReadPluginSetting("eventlinedistinctcolors", true); selectchangedafterundoredo = General.Settings.ReadPluginSetting("selectchangedafterundoredo", false); } @@ -698,176 +707,6 @@ namespace CodeImp.DoomBuilder.BuilderModes // Return list return found.ToArray(); } - - // This renders the associated sectors/linedefs with the indication color - public static void PlotAssociations(IRenderer2D renderer, Association asso, List eventlines) - { - // Tag must be above zero - if(General.GetByIndex(asso.Tags, 0) < 1) return; - - // Sectors? - switch(asso.Type) - { - case UniversalType.SectorTag: { - foreach(Sector s in General.Map.Map.Sectors) - { - if(!asso.Tags.Overlaps(s.Tags))continue; - renderer.PlotSector(s, General.Colors.Indication); - - if(!General.Settings.GZShowEventLines) continue; - Vector2D end = (s.Labels.Count > 0 ? s.Labels[0].position : new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2)); - eventlines.Add(new Line3D(asso.Center, end)); //mxd - } - break; - } - - case UniversalType.LinedefTag: { - foreach(Linedef l in General.Map.Map.Linedefs) - { - if(!asso.Tags.Overlaps(l.Tags)) continue; - renderer.PlotLinedef(l, General.Colors.Indication); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(asso.Center, l.GetCenterPoint())); //mxd - } - break; - } - } - } - - // This renders the associated things with the indication color - public static void RenderAssociations(IRenderer2D renderer, Association asso, List eventlines) - { - // Tag must be above zero - if(General.GetByIndex(asso.Tags, 0) < 1) return; - - // Things? - switch(asso.Type) - { - case UniversalType.ThingTag: - foreach(Thing t in General.Map.Map.Things) - { - if(!asso.Tags.Contains(t.Tag)) continue; - - //Do not draw the association if the user is hovering over a child link - ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); - if (ti != null && ti.ThingLink < 0) - continue; - - renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(asso.Center, t.Position)); //mxd - } - break; - - case UniversalType.SectorTag: - foreach(Sector s in General.Map.Map.Sectors) - { - if(!asso.Tags.Overlaps(s.Tags)) continue; - int highlightedColor = General.Colors.Highlight.WithAlpha(128).ToInt(); - FlatVertex[] verts = new FlatVertex[s.FlatVertices.Length]; - s.FlatVertices.CopyTo(verts, 0); - for(int i = 0; i < verts.Length; i++) verts[i].c = highlightedColor; - renderer.RenderGeometry(verts, null, true); - } - break; - } - } - - // This renders the associated sectors/linedefs with the indication color - public static void PlotReverseAssociations(IRenderer2D renderer, Association asso, List eventlines) - { - // Tag must be above zero - if(General.GetByIndex(asso.Tags, 0) < 1) return; - - // Doom style referencing to sectors? - if(General.Map.Config.LineTagIndicatesSectors && (asso.Type == UniversalType.SectorTag)) - { - // Linedefs - foreach(Linedef l in General.Map.Map.Linedefs) - { - // Any action on this line? - if(l.Action <= 0 || !asso.Tags.Overlaps(l.Tags)) continue; - renderer.PlotLinedef(l, General.Colors.Indication); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(l.GetCenterPoint(), asso.Center)); //mxd - } - } - - // Linedefs - foreach(Linedef l in General.Map.Map.Linedefs) - { - // Known action on this line? - if((l.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(l.Action)) - { - LinedefActionInfo action = General.Map.Config.LinedefActions[l.Action]; - if( ((action.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[0]))) || - ((action.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[1]))) || - ((action.Args[2].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[2]))) || - ((action.Args[3].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[3]))) || - ((action.Args[4].Type == (int)asso.Type) && (asso.Tags.Contains(l.Args[4])))) - { - renderer.PlotLinedef(l, General.Colors.Indication); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(l.GetCenterPoint(), asso.Center)); //mxd - } - } - } - } - - // This renders the associated things with the indication color - public static void RenderReverseAssociations(IRenderer2D renderer, Association asso, List eventlines) - { - // Tag must be above zero - if(General.GetByIndex(asso.Tags, 0) < 1) return; - - // Things - foreach(Thing t in General.Map.Map.Things) - { - // Get the thing type info - ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type); - - // Known action on this thing? - if((t.Action > 0) && General.Map.Config.LinedefActions.ContainsKey(t.Action)) - { - //Do not draw the association if this is a child link. - // This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead. - if(ti != null && asso.DirectLinkType < 0 && asso.DirectLinkType != -t.Type) - continue; - - LinedefActionInfo action = General.Map.Config.LinedefActions[t.Action]; - if( ((action.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[0]))) || - ((action.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[1]))) || - ((action.Args[2].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[2]))) || - ((action.Args[3].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[3]))) || - ((action.Args[4].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[4])))) - { - renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center)); //mxd - } - - //If there is a link setup on this thing, and it matches the association, then draw a direct link to any matching tag - if(ti != null && asso.DirectLinkType == t.Type && asso.Tags.Contains(t.Tag)) - { - renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); - if (General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center)); - } - } - //mxd. Thing action on this thing? - else if(t.Action == 0) - { - //Draw the association, unless it is a child link. - // This prevents a reverse link to a thing via an argument, when it should be a direct tag-to-tag link instead. - if(ti != null && asso.DirectLinkType >= 0 && Math.Abs(asso.DirectLinkType) != t.Type) - { - if( ((ti.Args[0].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[0]))) || - ((ti.Args[1].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[1]))) || - ((ti.Args[2].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[2]))) || - ((ti.Args[3].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[3]))) || - ((ti.Args[4].Type == (int)asso.Type) && (asso.Tags.Contains(t.Args[4])))) - { - renderer.RenderThing(t, General.Colors.Indication, General.Settings.ActiveThingsAlpha); - if(General.Settings.GZShowEventLines) eventlines.Add(new Line3D(t.Position, asso.Center)); - } - } - } - } - } #endregion diff --git a/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs b/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs index a16cb2b..58b623d 100644 --- a/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs +++ b/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs @@ -64,6 +64,8 @@ namespace CodeImp.DoomBuilder.BuilderModes defaultbrightness.Text = General.Settings.DefaultBrightness.ToString(); //mxd defaultceilheight.Text = General.Settings.DefaultCeilingHeight.ToString();//mxd defaultfloorheight.Text = General.Settings.DefaultFloorHeight.ToString(); //mxd + eventlinelabelvisibility.SelectedIndex = General.Settings.ReadPluginSetting("eventlinelabelvisibility", 3); + eventlinelabelstyle.SelectedIndex = General.Settings.ReadPluginSetting("eventlinelabelstyle", 2); selectafterundoredo.Checked = General.Settings.ReadPluginSetting("selectchangedafterundoredo", false); } @@ -92,6 +94,8 @@ namespace CodeImp.DoomBuilder.BuilderModes General.Settings.WritePluginSetting("autoaligntextureoffsetsoncreate", autoaligntexturesoncreate.Checked);//mxd General.Settings.WritePluginSetting("dontmovegeometryoutsidemapboundary", dontMoveGeometryOutsideBounds.Checked);//mxd General.Settings.WritePluginSetting("syncselection", syncSelection.Checked);//mxd + General.Settings.WritePluginSetting("eventlinelabelvisibility", eventlinelabelvisibility.SelectedIndex); + General.Settings.WritePluginSetting("eventlinelabelstyle", eventlinelabelstyle.SelectedIndex); General.Settings.WritePluginSetting("selectchangedafterundoredo", selectafterundoredo.Checked); General.Settings.SwitchViewModes = switchviewmodes.Checked; //mxd General.Settings.SplitLineBehavior = (SplitLineBehavior)splitbehavior.SelectedIndex;//mxd