From 1084cae38b5e4c56d86c79cb270bfd83b7894c42 Mon Sep 17 00:00:00 2001 From: codeimp Date: Sun, 21 Oct 2007 22:41:46 +0000 Subject: [PATCH] things! colored, scaled, and in their own mode! --- Build/Builder.cfg | 20 +++ Resources/Icons/ThingsMode.png | Bin 0 -> 660 bytes Resources/ThingTexture2.png | Bin 11495 -> 11522 bytes Source/Builder.csproj | 2 + Source/Config/GameConfiguration.cs | 53 +++++++- Source/Config/ThingCategory.cs | 105 ++++++++++++++- Source/Config/ThingTypeInfo.cs | 101 +++++++++++++- Source/Controls/Action.cs | 1 + Source/Editing/LinedefsMode.cs | 4 + Source/Editing/SectorsMode.cs | 6 +- Source/Editing/ThingsMode.cs | 166 ++++++++++++++++++++++++ Source/Editing/VerticesMode.cs | 9 +- Source/General/MapManager.cs | 13 +- Source/IO/DoomMapSetIO.cs | 1 + Source/Interface/MainForm.Designer.cs | 28 +++- Source/Interface/MainForm.cs | 12 ++ Source/Map/Linedef.cs | 28 ++++ Source/Map/MapSet.cs | 14 +- Source/Map/Thing.cs | 29 ++++- Source/Properties/Resources.Designer.cs | 7 + Source/Properties/Resources.resx | 31 +++-- Source/Rendering/ColorCollection.cs | 48 ++++++- Source/Rendering/Renderer2D.cs | 156 +++++++++++++--------- Source/Resources/Actions.cfg | 9 ++ Source/Resources/Thing2D.png | Bin 11495 -> 11522 bytes Source/Resources/ThingsMode.png | Bin 0 -> 660 bytes Source/Resources/things2d.fx | 2 +- 27 files changed, 749 insertions(+), 96 deletions(-) create mode 100644 Resources/Icons/ThingsMode.png create mode 100644 Source/Editing/ThingsMode.cs create mode 100644 Source/Resources/ThingsMode.png diff --git a/Build/Builder.cfg b/Build/Builder.cfg index aed3fe4c..aa43c92a 100644 --- a/Build/Builder.cfg +++ b/Build/Builder.cfg @@ -36,6 +36,26 @@ colors color17 = -16776961; color18 = -16744448; color19 = -8388608; + color20 = -9868951; + color21 = -12490271; + color22 = -14513374; + color23 = -14634326; + color24 = -5103070; + color25 = -7077677; + color26 = -2448096; + color27 = -4144960; + color28 = -8355712; + color29 = -16728065; + color30 = -13447886; + color31 = -5247250; + color32 = -40121; + color33 = -1146130; + color34 = -256; + color35 = -657931; + color36 = -18751; + color37 = -29696; + color38 = -4343957; + color39 = -4684277; } diff --git a/Resources/Icons/ThingsMode.png b/Resources/Icons/ThingsMode.png new file mode 100644 index 0000000000000000000000000000000000000000..2e35b74aa8dc54ca71db193e0ddd81f8b794747d GIT binary patch literal 660 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 + @@ -217,6 +218,7 @@ + diff --git a/Source/Config/GameConfiguration.cs b/Source/Config/GameConfiguration.cs index 9bb4796c..c1a6df77 100644 --- a/Source/Config/GameConfiguration.cs +++ b/Source/Config/GameConfiguration.cs @@ -46,9 +46,15 @@ namespace CodeImp.DoomBuilder.Config private float defaulttexturescale; private float defaultflatscale; private string formatinterface; - private IDictionary maplumpnames; private int soundlinedefflags; + // Map lumps + private IDictionary maplumpnames; + + // Things + private List thingcategories; + private Dictionary things; + #endregion #region ================== Properties @@ -57,9 +63,14 @@ namespace CodeImp.DoomBuilder.Config public float DefaultTextureScale { get { return defaulttexturescale; } } public float DefaultFlatScale { get { return defaultflatscale; } } public string FormatInterface { get { return formatinterface; } } - public IDictionary MapLumpNames { get { return maplumpnames; } } public int SoundLinedefFlags { get { return soundlinedefflags; } } + // Map lumps + public IDictionary MapLumpNames { get { return maplumpnames; } } + + // Things + public List ThingCategories { get { return thingcategories; } } + #endregion #region ================== Constructor / Disposer @@ -67,16 +78,34 @@ namespace CodeImp.DoomBuilder.Config // Constructor public GameConfiguration(Configuration cfg) { - // Keep reference + IDictionary dic; + ThingCategory thingcat; + + // Initialize this.cfg = cfg; + this.thingcategories = new List(); + this.things = new Dictionary(); // Read general settings defaulttexturescale = cfg.ReadSetting("defaulttexturescale", 1f); defaultflatscale = cfg.ReadSetting("defaultflatscale", 1f); formatinterface = cfg.ReadSetting("formatinterface", ""); - maplumpnames = cfg.ReadSetting("maplumpnames", new Hashtable()); soundlinedefflags = cfg.ReadSetting("soundlinedefflags", 0); + // Get map lumps + maplumpnames = cfg.ReadSetting("maplumpnames", new Hashtable()); + + // Get thing categories + dic = cfg.ReadSetting("thingtypes", new Hashtable()); + foreach(DictionaryEntry de in dic) + { + // Make a category + thingcat = new ThingCategory(cfg, de.Key.ToString()); + + // Add all thing in category to the big list + foreach(ThingTypeInfo t in thingcat.Things) things.Add(t.Index, t); + } + // We have no destructor GC.SuppressFinalize(this); } @@ -95,6 +124,22 @@ namespace CodeImp.DoomBuilder.Config public byte ReadSetting(string setting, byte defaultsetting) { return cfg.ReadSetting(setting, defaultsetting); } public IDictionary ReadSetting(string setting, IDictionary defaultsetting) { return cfg.ReadSetting(setting, defaultsetting); } + // This gets thing information by index + public ThingTypeInfo GetThingInfo(int index) + { + // Index in config? + if(things.ContainsKey(index)) + { + // Return from config + return things[index]; + } + else + { + // Create unknown thing info + return new ThingTypeInfo(index); + } + } + #endregion } } diff --git a/Source/Config/ThingCategory.cs b/Source/Config/ThingCategory.cs index d38866a2..4d106f3c 100644 --- a/Source/Config/ThingCategory.cs +++ b/Source/Config/ThingCategory.cs @@ -26,12 +26,13 @@ using CodeImp.DoomBuilder.Data; using System.IO; using System.Diagnostics; using System.Windows.Forms; +using CodeImp.DoomBuilder.Rendering; #endregion namespace CodeImp.DoomBuilder.Config { - internal class ThingCategory + internal class ThingCategory : IDisposable { #region ================== Constants @@ -39,27 +40,127 @@ namespace CodeImp.DoomBuilder.Config #region ================== Variables + // Things + private List things; + + // Category properties + private string name; + private string title; + private bool sorted; + + // Thing properties for inheritance + private string sprite; + private int color; + private int arrow; + private float width; + private float height; + private int hangs; + private int blocking; + private int errorcheck; + + // Disposing + private bool isdisposed = false; + #endregion #region ================== Properties + public string Name { get { return name; } } + public string Title { get { return title; } } + public string Sprite { get { return sprite; } } + public bool Sorted { get { return sorted; } } + public int Color { get { return color; } } + public int Arrow { get { return arrow; } } + public float Width { get { return width; } } + public float Height { get { return height; } } + public int Hangs { get { return hangs; } } + public int Blocking { get { return blocking; } } + public int ErrorCheck { get { return errorcheck; } } + public bool IsDisposed { get { return isdisposed; } } + public List Things { get { return things; } } + #endregion #region ================== Constructor / Disposer // Constructor - public ThingCategory() + public ThingCategory(Configuration cfg, string name) { + IDictionary dic; + int index; + // Initialize + this.name = name; + this.things = new List(); + + // Read properties + this.title = cfg.ReadSetting("thingtypes." + name + ".title", ""); + this.sprite = cfg.ReadSetting("thingtypes." + name + ".sprite", ""); + this.sorted = (cfg.ReadSetting("thingtypes." + name + ".sort", 0) != 0); + this.color = cfg.ReadSetting("thingtypes." + name + ".color", 0); + this.arrow = cfg.ReadSetting("thingtypes." + name + ".arrow", 0); + this.width = cfg.ReadSetting("thingtypes." + name + ".width", 16); + this.height = cfg.ReadSetting("thingtypes." + name + ".height", 16); + this.hangs = cfg.ReadSetting("thingtypes." + name + ".hangs", 0); + this.blocking = cfg.ReadSetting("thingtypes." + name + ".blocking", 0); + this.errorcheck = cfg.ReadSetting("thingtypes." + name + ".errorcheck", 0); + + // Safety + if(this.width < 2f) this.width = 2f; + if(this.height < 2f) this.height = 2f; + + // Go for all items in category + dic = cfg.ReadSetting("thingtypes." + name, new Hashtable()); + foreach(DictionaryEntry de in dic) + { + // Check if the item key is numeric + if(int.TryParse(de.Key.ToString(), NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.InvariantCulture, out index)) + { + // Check if the item value is a structure + if(de.Value is IDictionary) + { + // Create this thing + things.Add(new ThingTypeInfo(this, index, cfg)); + } + // Check if the item value is a string + else if(de.Value is string) + { + // Interpret this as the title + things.Add(new ThingTypeInfo(this, index, de.Value.ToString())); + } + } + } // We have no destructor GC.SuppressFinalize(this); } + // Disposer + public void Dispose() + { + // Not already disposed? + if(!isdisposed) + { + // Clean up + things = null; + + // Done + isdisposed = true; + } + } + #endregion #region ================== Methods + // This adds a thing to the category + public void AddThing(ThingTypeInfo t) + { + // Add + things.Add(t); + } + #endregion } } + diff --git a/Source/Config/ThingTypeInfo.cs b/Source/Config/ThingTypeInfo.cs index 71050b84..27d0d9f6 100644 --- a/Source/Config/ThingTypeInfo.cs +++ b/Source/Config/ThingTypeInfo.cs @@ -39,18 +39,117 @@ namespace CodeImp.DoomBuilder.Config #region ================== Variables + // Properties + private int index; + private string title; + private string sprite; + private long spritelongname; + private int color; + private bool arrow; + private float width; + private float height; + private bool hangs; + private int blocking; + private int errorcheck; + private ThingCategory category; + #endregion #region ================== Properties + public int Index { get { return index; } } + public string Title { get { return title; } } + public string Sprite { get { return sprite; } } + public long SpriteLongName { get { return spritelongname; } } + public int Color { get { return color; } } + public bool Arrow { get { return arrow; } } + public float Width { get { return width; } } + public float Height { get { return height; } } + public bool Hangs { get { return hangs; } } + public int Blocking { get { return blocking; } } + public int ErrorCheck { get { return errorcheck; } } + public ThingCategory Category { get { return category; } } + #endregion #region ================== Constructor / Disposer // Constructor - public ThingTypeInfo() + public ThingTypeInfo(int index) { // Initialize + this.index = index; + this.category = null; + this.title = "<" + index.ToString(CultureInfo.InvariantCulture) + ">"; + this.sprite = ""; + this.color = 0; + this.arrow = true; + this.width = 16f; + this.height = 16f; + this.hangs = false; + this.blocking = 0; + this.errorcheck = 0; + + // Make long name for sprite lookup + this.spritelongname = Lump.MakeLongName(this.sprite); + + // We have no destructor + GC.SuppressFinalize(this); + } + + // Constructor + public ThingTypeInfo(ThingCategory cat, int index, Configuration cfg) + { + string key = index.ToString(CultureInfo.InvariantCulture); + + // Initialize + this.index = index; + this.category = cat; + + // Read properties + this.title = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".title", "<" + key + ">"); + this.sprite = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".sprite", cat.Sprite); + this.color = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".color", cat.Color); + this.arrow = (cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".arrow", cat.Arrow) != 0); + this.width = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".width", cat.Width); + this.height = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".height", cat.Height); + this.hangs = (cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".hangs", cat.Hangs) != 0); + this.blocking = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".blocking", cat.Blocking); + this.errorcheck = cfg.ReadSetting("thingtypes." + cat.Name + "." + key + ".errorcheck", cat.ErrorCheck); + + // Safety + if(this.width < 2f) this.width = 2f; + if(this.height < 2f) this.height = 2f; + + // Make long name for sprite lookup + this.spritelongname = Lump.MakeLongName(this.sprite); + + // We have no destructor + GC.SuppressFinalize(this); + } + + // Constructor + public ThingTypeInfo(ThingCategory cat, int index, string title) + { + string key = index.ToString(CultureInfo.InvariantCulture); + + // Initialize + this.index = index; + this.category = cat; + this.title = title; + + // Read properties + this.sprite = cat.Sprite; + this.color = cat.Color; + this.arrow = (cat.Arrow != 0); + this.width = cat.Width; + this.height = cat.Height; + this.hangs = (cat.Hangs != 0); + this.blocking = cat.Blocking; + this.errorcheck = cat.ErrorCheck; + + // Make long name for sprite lookup + this.spritelongname = Lump.MakeLongName(this.sprite); // We have no destructor GC.SuppressFinalize(this); diff --git a/Source/Controls/Action.cs b/Source/Controls/Action.cs index 29605b14..5d2fd25a 100644 --- a/Source/Controls/Action.cs +++ b/Source/Controls/Action.cs @@ -50,6 +50,7 @@ namespace CodeImp.DoomBuilder.Controls public const string VERTICESMODE = "verticesmode"; public const string LINEDEFSMODE = "linedefsmode"; public const string SECTORSMODE = "sectorsmode"; + public const string THINGSMODE = "thingsmode"; #endregion diff --git a/Source/Editing/LinedefsMode.cs b/Source/Editing/LinedefsMode.cs index 3e34ca84..d647b63c 100644 --- a/Source/Editing/LinedefsMode.cs +++ b/Source/Editing/LinedefsMode.cs @@ -101,6 +101,10 @@ namespace CodeImp.DoomBuilder.Editing // Start with a clear display if(renderer.StartRendering(true)) { + // Render things + renderer.SetThingsRenderOrder(false); + renderer.RenderThingSet(General.Map.Map.Things); + // Render lines renderer.RenderLinedefSet(General.Map.Map.Linedefs); diff --git a/Source/Editing/SectorsMode.cs b/Source/Editing/SectorsMode.cs index 0ec622bb..f5910015 100644 --- a/Source/Editing/SectorsMode.cs +++ b/Source/Editing/SectorsMode.cs @@ -99,7 +99,11 @@ namespace CodeImp.DoomBuilder.Editing // Start with a clear display if(renderer.StartRendering(true)) { - // Render stuff + // Render things + renderer.SetThingsRenderOrder(false); + renderer.RenderThingSet(General.Map.Map.Things); + + // Render lines and vertices renderer.RenderLinedefSet(General.Map.Map.Linedefs); renderer.RenderVerticesSet(General.Map.Map.Vertices); diff --git a/Source/Editing/ThingsMode.cs b/Source/Editing/ThingsMode.cs new file mode 100644 index 00000000..3d38ba32 --- /dev/null +++ b/Source/Editing/ThingsMode.cs @@ -0,0 +1,166 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Reflection; +using CodeImp.DoomBuilder.Interface; +using CodeImp.DoomBuilder.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Geometry; + +#endregion + +namespace CodeImp.DoomBuilder.Editing +{ + internal class ThingsMode : ClassicMode + { + #region ================== Constants + + protected const float THING_HIGHLIGHT_RANGE = 10f; + + #endregion + + #region ================== Variables + + // Highlighted item + private Thing highlighted; + + #endregion + + #region ================== Properties + + #endregion + + #region ================== Constructor / Disposer + + // Constructor + public ThingsMode() + { + } + + // Diposer + public override void Dispose() + { + // Not already disposed? + if(!isdisposed) + { + // Clean up + + // Dispose base + base.Dispose(); + } + } + + #endregion + + #region ================== Methods + + // Mode engages + public override void Engage() + { + base.Engage(); + + // Check things button on main window + General.MainWindow.SetThingsChecked(true); + } + + // Mode disengages + public override void Disengage() + { + base.Disengage(); + + // Check things button on main window + General.MainWindow.SetThingsChecked(false); + } + + // This redraws the display + public unsafe override void RedrawDisplay() + { + // Start with a clear display + if(renderer.StartRendering(true)) + { + // Render lines and vertices + renderer.RenderLinedefSet(General.Map.Map.Linedefs); + renderer.RenderVerticesSet(General.Map.Map.Vertices); + + // Render things + renderer.SetThingsRenderOrder(true); + renderer.RenderThingSet(General.Map.Map.Things); + + // Render highlighted item + if(highlighted != null) + renderer.RenderThing(highlighted, General.Colors.Highlight); + + // Done + renderer.FinishRendering(); + } + } + + // This highlights a new item + protected void Highlight(Thing t) + { + // Update display + if(renderer.StartRendering(false)) + { + // Undraw previous highlight + if(highlighted != null) + renderer.RenderThing(highlighted, renderer.DetermineThingColor(highlighted)); + + // Set new highlight + highlighted = t; + + // Render highlighted item + if(highlighted != null) + renderer.RenderThing(highlighted, General.Colors.Highlight); + + // Done + renderer.FinishRendering(); + } + } + + // Mouse moves + public override void MouseMove(MouseEventArgs e) + { + base.MouseMove(e); + + // Find the nearest vertex within highlight range + //Thing t = General.Map.Map.Nearestt(mousemappos, VERTEX_HIGHLIGHT_RANGE / renderer.Scale); + + // Highlight if not the same + //if(t != highlighted) Highlight(v); + } + + // Mouse leaves + public override void MouseLeave(EventArgs e) + { + base.MouseLeave(e); + + // Highlight nothing + Highlight(null); + } + + #endregion + } +} diff --git a/Source/Editing/VerticesMode.cs b/Source/Editing/VerticesMode.cs index 620edff2..c8cb6119 100644 --- a/Source/Editing/VerticesMode.cs +++ b/Source/Editing/VerticesMode.cs @@ -101,7 +101,11 @@ namespace CodeImp.DoomBuilder.Editing // Start with a clear display if(renderer.StartRendering(true)) { - // Render stuff + // Render things + renderer.SetThingsRenderOrder(false); + renderer.RenderThingSet(General.Map.Map.Things); + + // Render lines and vertices renderer.RenderLinedefSet(General.Map.Map.Linedefs); renderer.RenderVerticesSet(General.Map.Map.Vertices); @@ -109,9 +113,6 @@ namespace CodeImp.DoomBuilder.Editing if(highlighted != null) renderer.RenderVertex(highlighted, ColorCollection.HIGHLIGHT); - // Render things - renderer.RenderThingSet(General.Map.Map.Things); - // Done renderer.FinishRendering(); } diff --git a/Source/General/MapManager.cs b/Source/General/MapManager.cs index df9e7aaa..3760d3d0 100644 --- a/Source/General/MapManager.cs +++ b/Source/General/MapManager.cs @@ -850,6 +850,14 @@ namespace CodeImp.DoomBuilder // Change to sectors mode ChangeMode(new SectorsMode()); } + + // This switches to things mode + [Action(Action.THINGSMODE)] + public void SwitchThingsMode() + { + // Change to things mode + ChangeMode(new ThingsMode()); + } #endregion @@ -882,7 +890,10 @@ namespace CodeImp.DoomBuilder data = new DataManager(); maplocation = new DataLocation(DataLocation.RESOURCE_WAD, filepathname, false, false); data.Load(configinfo.Resources, options.Resources, maplocation); - + + // Apply new settings to map elements + map.UpdateConfiguration(); + // Reset status General.MainWindow.DisplayStatus(oldstatus); Cursor.Current = oldcursor; diff --git a/Source/IO/DoomMapSetIO.cs b/Source/IO/DoomMapSetIO.cs index c723be78..3cd60827 100644 --- a/Source/IO/DoomMapSetIO.cs +++ b/Source/IO/DoomMapSetIO.cs @@ -113,6 +113,7 @@ namespace CodeImp.DoomBuilder.IO t = map.CreateThing(); t.Update(type, new Vector3D(x, y, 0f), angle, flags, 0, 0, Thing.EMPTY_ARGS); t.DetermineSector(); + t.UpdateConfiguration(); } // Done diff --git a/Source/Interface/MainForm.Designer.cs b/Source/Interface/MainForm.Designer.cs index 7d21679a..5ba74c62 100644 --- a/Source/Interface/MainForm.Designer.cs +++ b/Source/Interface/MainForm.Designer.cs @@ -50,6 +50,7 @@ namespace CodeImp.DoomBuilder.Interface this.itemverticesmode = new System.Windows.Forms.ToolStripMenuItem(); this.itemlinedefsmode = new System.Windows.Forms.ToolStripMenuItem(); this.itemsectorsmode = new System.Windows.Forms.ToolStripMenuItem(); + this.itemthingsmode = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); this.itemmapoptions = new System.Windows.Forms.ToolStripMenuItem(); this.menutools = new System.Windows.Forms.ToolStripMenuItem(); @@ -68,6 +69,7 @@ namespace CodeImp.DoomBuilder.Interface this.buttonverticesmode = new System.Windows.Forms.ToolStripButton(); this.buttonlinedefsmode = new System.Windows.Forms.ToolStripButton(); this.buttonsectorsmode = new System.Windows.Forms.ToolStripButton(); + this.buttonthingsmode = new System.Windows.Forms.ToolStripButton(); this.statusbar = new System.Windows.Forms.StatusStrip(); this.statuslabel = new System.Windows.Forms.ToolStripStatusLabel(); this.zoomlabel = new System.Windows.Forms.ToolStripStatusLabel(); @@ -231,6 +233,7 @@ namespace CodeImp.DoomBuilder.Interface this.itemverticesmode, this.itemlinedefsmode, this.itemsectorsmode, + this.itemthingsmode, this.toolStripSeparator6, this.itemmapoptions}); this.menuedit.Name = "menuedit"; @@ -264,6 +267,15 @@ namespace CodeImp.DoomBuilder.Interface this.itemsectorsmode.Text = "Sectors Mode"; this.itemsectorsmode.Click += new System.EventHandler(this.InvokeTaggedAction); // + // itemthingsmode + // + this.itemthingsmode.Image = global::CodeImp.DoomBuilder.Properties.Resources.ThingsMode; + this.itemthingsmode.Name = "itemthingsmode"; + this.itemthingsmode.Size = new System.Drawing.Size(161, 22); + this.itemthingsmode.Tag = "thingsmode"; + this.itemthingsmode.Text = "Things Mode"; + this.itemthingsmode.Click += new System.EventHandler(this.InvokeTaggedAction); + // // toolStripSeparator6 // this.toolStripSeparator6.Name = "toolStripSeparator6"; @@ -340,7 +352,8 @@ namespace CodeImp.DoomBuilder.Interface this.toolStripSeparator5, this.buttonverticesmode, this.buttonlinedefsmode, - this.buttonsectorsmode}); + this.buttonsectorsmode, + this.buttonthingsmode}); this.toolbar.Location = new System.Drawing.Point(0, 24); this.toolbar.Name = "toolbar"; this.toolbar.Size = new System.Drawing.Size(731, 25); @@ -436,6 +449,17 @@ namespace CodeImp.DoomBuilder.Interface this.buttonsectorsmode.Text = "Sectors Mode"; this.buttonsectorsmode.Click += new System.EventHandler(this.InvokeTaggedAction); // + // buttonthingsmode + // + this.buttonthingsmode.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.buttonthingsmode.Image = global::CodeImp.DoomBuilder.Properties.Resources.ThingsMode; + this.buttonthingsmode.ImageTransparentColor = System.Drawing.Color.Magenta; + this.buttonthingsmode.Name = "buttonthingsmode"; + this.buttonthingsmode.Size = new System.Drawing.Size(23, 22); + this.buttonthingsmode.Tag = "thingsmode"; + this.buttonthingsmode.Text = "Things Mode"; + this.buttonthingsmode.Click += new System.EventHandler(this.InvokeTaggedAction); + // // statusbar // this.statusbar.Font = new System.Drawing.Font("Verdana", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); @@ -687,5 +711,7 @@ namespace CodeImp.DoomBuilder.Interface private System.Windows.Forms.ToolStripMenuItem itemlinedefsmode; private System.Windows.Forms.ToolStripMenuItem itemsectorsmode; private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; + private System.Windows.Forms.ToolStripButton buttonthingsmode; + private System.Windows.Forms.ToolStripMenuItem itemthingsmode; } } \ No newline at end of file diff --git a/Source/Interface/MainForm.cs b/Source/Interface/MainForm.cs index 6eeb4e12..e3d6a1f0 100644 --- a/Source/Interface/MainForm.cs +++ b/Source/Interface/MainForm.cs @@ -691,6 +691,13 @@ namespace CodeImp.DoomBuilder.Interface buttonsectorsmode.Checked = value; } + // This sets the status of the things button + public void SetThingsChecked(bool value) + { + itemthingsmode.Checked = value; + buttonthingsmode.Checked = value; + } + // This sets up the edit menu private void UpdateEditMenu() { @@ -702,12 +709,14 @@ namespace CodeImp.DoomBuilder.Interface itemverticesmode.Enabled = (General.Map != null); itemlinedefsmode.Enabled = (General.Map != null); itemsectorsmode.Enabled = (General.Map != null); + itemthingsmode.Enabled = (General.Map != null); // Toolbar icons buttonmapoptions.Enabled = (General.Map != null); buttonverticesmode.Enabled = (General.Map != null); buttonlinedefsmode.Enabled = (General.Map != null); buttonsectorsmode.Enabled = (General.Map != null); + buttonthingsmode.Enabled = (General.Map != null); } #endregion @@ -769,6 +778,9 @@ namespace CodeImp.DoomBuilder.Interface { // Update shortcut keys in menus ApplyShortcutKeys(); + + // Apply new settings if a map is open + if(General.Map != null) General.Map.Map.UpdateConfiguration(); // Redraw display RedrawDisplay(); diff --git a/Source/Map/Linedef.cs b/Source/Map/Linedef.cs index 570b1e58..21cc2cfd 100644 --- a/Source/Map/Linedef.cs +++ b/Source/Map/Linedef.cs @@ -243,6 +243,34 @@ namespace CodeImp.DoomBuilder.Map #region ================== Methods + // This returns the shortest distance from given coordinates to line + public float SafeDistanceToSq(Vector2D p, bool bounded) + { + Vector2D v1 = start.Position; + Vector2D v2 = end.Position; + + // Calculate intersection offset + float u = ((p.x - v1.x) * (v2.x - v1.x) + (p.y - v1.y) * (v2.y - v1.y)) / lengthsq; + + // Limit intersection offset to the line + if(bounded) if(u < lengthinv) u = lengthinv; else if(u > (1f - lengthinv)) u = 1f - lengthinv; + + // Calculate intersection point + Vector2D i = v1 + u * (v2 - v1); + + // Return distance between intersection and point + // which is the shortest distance to the line + float ldx = p.x - i.x; + float ldy = p.y - i.y; + return ldx * ldx + ldy * ldy; + } + + // This returns the shortest distance from given coordinates to line + public float SafeDistanceTo(Vector2D p, bool bounded) + { + return (float)Math.Sqrt(SafeDistanceToSq(p, bounded)); + } + // This returns the shortest distance from given coordinates to line public float DistanceToSq(Vector2D p, bool bounded) { diff --git a/Source/Map/MapSet.cs b/Source/Map/MapSet.cs index 1fe93f9d..cc1ae093 100644 --- a/Source/Map/MapSet.cs +++ b/Source/Map/MapSet.cs @@ -301,6 +301,14 @@ namespace CodeImp.DoomBuilder.Map // Update all linedefs foreach(Linedef l in linedefs) l.Update(); } + + // This updates all structures after a + // configuration or settings change + public void UpdateConfiguration() + { + // Update all things + foreach(Thing t in things) t.UpdateConfiguration(); + } #endregion @@ -317,7 +325,7 @@ namespace CodeImp.DoomBuilder.Map foreach(Linedef l in selection) { // Calculate distance and check if closer than previous find - d = l.DistanceToSq(pos, true); + d = l.SafeDistanceToSq(pos, true); if(d < distance) { // This one is closer @@ -342,7 +350,7 @@ namespace CodeImp.DoomBuilder.Map foreach(Linedef l in selection) { // Calculate distance and check if closer than previous find - d = l.DistanceToSq(pos, true); + d = l.SafeDistanceToSq(pos, true); if((d <= maxrangesq) && (d < distance)) { // This one is closer @@ -430,7 +438,7 @@ namespace CodeImp.DoomBuilder.Map // This performs sidedefs compression public void CompressSidedefs() { - // TODO: Make this + // TODO: Make this happen } // This removes unused vertices diff --git a/Source/Map/Thing.cs b/Source/Map/Thing.cs index 8828459a..ed0a9c9c 100644 --- a/Source/Map/Thing.cs +++ b/Source/Map/Thing.cs @@ -23,6 +23,8 @@ using System.Globalization; using System.Text; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Rendering; +using CodeImp.DoomBuilder.Config; +using System.Drawing; #endregion @@ -60,6 +62,7 @@ namespace CodeImp.DoomBuilder.Map // Configuration private float size; private PixelColor color; + private float iconoffset; // Selections private int selected; @@ -78,7 +81,10 @@ namespace CodeImp.DoomBuilder.Map public float Angle { get { return angle; } } public int Flags { get { return flags; } } public int Selected { get { return selected; } set { selected = value; } } - + public float Size { get { return size; } } + public float IconOffset { get { return iconoffset; } } + public PixelColor Color { get { return color; } } + #endregion #region ================== Constructor / Disposer @@ -219,7 +225,28 @@ namespace CodeImp.DoomBuilder.Map // This updates the settings from configuration public void UpdateConfiguration() { + ThingTypeInfo ti; + // Lookup settings + ti = General.Map.Configuration.GetThingInfo(type); + + // Apply size + size = ti.Width; + + // Color valid? + if((ti.Color >= 0) && (ti.Color < ColorCollection.NUM_THING_COLORS)) + { + // Apply color + color = General.Colors.Colors[ti.Color + ColorCollection.THING_COLORS_OFFSET]; + } + else + { + // Unknown thing color + color = General.Colors.Colors[ColorCollection.THING_COLORS_OFFSET]; + } + + // Apply icon offset (arrow or dot) + if(ti.Arrow) iconoffset = 0f; else iconoffset = 0.25f; } #endregion diff --git a/Source/Properties/Resources.Designer.cs b/Source/Properties/Resources.Designer.cs index 96ac5ca7..7b86c82d 100644 --- a/Source/Properties/Resources.Designer.cs +++ b/Source/Properties/Resources.Designer.cs @@ -130,6 +130,13 @@ namespace CodeImp.DoomBuilder.Properties { } } + internal static System.Drawing.Bitmap ThingsMode { + get { + object obj = ResourceManager.GetObject("ThingsMode", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + internal static System.Drawing.Bitmap VerticesMode { get { object obj = ResourceManager.GetObject("VerticesMode", resourceCulture); diff --git a/Source/Properties/Resources.resx b/Source/Properties/Resources.resx index 84e47dc3..d6604cf8 100644 --- a/Source/Properties/Resources.resx +++ b/Source/Properties/Resources.resx @@ -121,14 +121,14 @@ ..\Resources\ColorPick.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\NewMap2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Splash2small.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\Properties.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\NewMap.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\OpenMap.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\VerticesMode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -136,22 +136,25 @@ ..\Resources\Splash2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\SectorsMode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\NewMap.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\NewMap2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\Zoom.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\OpenMap.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\LinesMode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\SaveMap.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\Splash2small.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\LinesMode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\SectorsMode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\ThingsMode.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a \ No newline at end of file diff --git a/Source/Rendering/ColorCollection.cs b/Source/Rendering/ColorCollection.cs index 0a8b5661..92a05e8e 100644 --- a/Source/Rendering/ColorCollection.cs +++ b/Source/Rendering/ColorCollection.cs @@ -41,7 +41,9 @@ namespace CodeImp.DoomBuilder.Rendering private const float DARK_ADDITION = -0.2f; // Palette size - private const int NUM_COLORS = 20; + private const int NUM_COLORS = 40; + public const int NUM_THING_COLORS = 20; + public const int THING_COLORS_OFFSET = 20; // Colors! public const int BACKGROUND = 0; @@ -64,6 +66,26 @@ namespace CodeImp.DoomBuilder.Rendering public const int KEYWORDS = 17; public const int LITERALS = 18; public const int CONSTANTS = 19; + public const int THINGCOLOR00 = 20; + public const int THINGCOLOR01 = 21; + public const int THINGCOLOR02 = 22; + public const int THINGCOLOR03 = 23; + public const int THINGCOLOR04 = 24; + public const int THINGCOLOR05 = 25; + public const int THINGCOLOR06 = 26; + public const int THINGCOLOR07 = 27; + public const int THINGCOLOR08 = 28; + public const int THINGCOLOR09 = 29; + public const int THINGCOLOR10 = 30; + public const int THINGCOLOR11 = 31; + public const int THINGCOLOR12 = 32; + public const int THINGCOLOR13 = 33; + public const int THINGCOLOR14 = 34; + public const int THINGCOLOR15 = 35; + public const int THINGCOLOR16 = 36; + public const int THINGCOLOR17 = 37; + public const int THINGCOLOR18 = 38; + public const int THINGCOLOR19 = 39; #endregion @@ -121,8 +143,30 @@ namespace CodeImp.DoomBuilder.Rendering for(int i = 0; i < NUM_COLORS; i++) { // Read color - colors[i] = PixelColor.FromInt(cfg.ReadSetting("colors.color" + i.ToString(CultureInfo.InvariantCulture), -1)); + colors[i] = PixelColor.FromInt(cfg.ReadSetting("colors.color" + i.ToString(CultureInfo.InvariantCulture), 0)); } + + // Set new colors + if(colors[THINGCOLOR00].ToInt() == 0) colors[THINGCOLOR00] = PixelColor.FromColor(Color.DimGray); + if(colors[THINGCOLOR01].ToInt() == 0) colors[THINGCOLOR01] = PixelColor.FromColor(Color.RoyalBlue); + if(colors[THINGCOLOR02].ToInt() == 0) colors[THINGCOLOR02] = PixelColor.FromColor(Color.ForestGreen); + if(colors[THINGCOLOR03].ToInt() == 0) colors[THINGCOLOR03] = PixelColor.FromColor(Color.LightSeaGreen); + if(colors[THINGCOLOR04].ToInt() == 0) colors[THINGCOLOR04] = PixelColor.FromColor(Color.Firebrick); + if(colors[THINGCOLOR05].ToInt() == 0) colors[THINGCOLOR05] = PixelColor.FromColor(Color.DarkViolet); + if(colors[THINGCOLOR06].ToInt() == 0) colors[THINGCOLOR06] = PixelColor.FromColor(Color.Goldenrod); + if(colors[THINGCOLOR07].ToInt() == 0) colors[THINGCOLOR07] = PixelColor.FromColor(Color.Silver); + if(colors[THINGCOLOR08].ToInt() == 0) colors[THINGCOLOR08] = PixelColor.FromColor(Color.Gray); + if(colors[THINGCOLOR09].ToInt() == 0) colors[THINGCOLOR09] = PixelColor.FromColor(Color.DeepSkyBlue); + if(colors[THINGCOLOR10].ToInt() == 0) colors[THINGCOLOR10] = PixelColor.FromColor(Color.LimeGreen); + if(colors[THINGCOLOR11].ToInt() == 0) colors[THINGCOLOR11] = PixelColor.FromColor(Color.PaleTurquoise); + if(colors[THINGCOLOR12].ToInt() == 0) colors[THINGCOLOR12] = PixelColor.FromColor(Color.Tomato); + if(colors[THINGCOLOR13].ToInt() == 0) colors[THINGCOLOR13] = PixelColor.FromColor(Color.Violet); + if(colors[THINGCOLOR14].ToInt() == 0) colors[THINGCOLOR14] = PixelColor.FromColor(Color.Yellow); + if(colors[THINGCOLOR15].ToInt() == 0) colors[THINGCOLOR15] = PixelColor.FromColor(Color.WhiteSmoke); + if(colors[THINGCOLOR16].ToInt() == 0) colors[THINGCOLOR16] = PixelColor.FromColor(Color.LightPink); + if(colors[THINGCOLOR17].ToInt() == 0) colors[THINGCOLOR17] = PixelColor.FromColor(Color.DarkOrange); + if(colors[THINGCOLOR18].ToInt() == 0) colors[THINGCOLOR18] = PixelColor.FromColor(Color.DarkKhaki); + if(colors[THINGCOLOR19].ToInt() == 0) colors[THINGCOLOR19] = PixelColor.FromColor(Color.DarkGoldenrod); // Create assist colors CreateAssistColors(); diff --git a/Source/Rendering/Renderer2D.cs b/Source/Rendering/Renderer2D.cs index 084e49bd..fd913ad1 100644 --- a/Source/Rendering/Renderer2D.cs +++ b/Source/Rendering/Renderer2D.cs @@ -44,9 +44,12 @@ namespace CodeImp.DoomBuilder.Rendering private const byte DOUBLESIDED_LINE_ALPHA = 130; private const float FSAA_BLEND_FACTOR = 0.6f; - private const float THING_ARROW_SIZE = 15f; - private const float THING_CIRCLE_SIZE = 10f; + private const float THING_ARROW_SIZE = 1.5f; + private const float THING_ARROW_SHRINK = 2f; + private const float THING_CIRCLE_SIZE = 1f; + private const float THING_CIRCLE_SHRINK = 2f; private const int THING_BUFFER_STEP = 100; + private const byte THINGS_BACK_ALPHA = 80; #endregion @@ -66,6 +69,9 @@ namespace CodeImp.DoomBuilder.Rendering private int numthings; private int maxthings; + // Render settings + private bool thingsfront; + // Images private ResourceImage thingtexture; @@ -133,6 +139,9 @@ namespace CodeImp.DoomBuilder.Rendering // Start drawing if(graphics.StartRendering(General.Colors.Background.ToInt())) { + // Render things in back? + if(!thingsfront) PresentThings(THINGS_BACK_ALPHA); + // Set renderstates graphics.Device.SetTexture(0, tex); graphics.Device.SetRenderState(RenderState.CullMode, Cull.None); @@ -149,47 +158,56 @@ namespace CodeImp.DoomBuilder.Rendering try { graphics.Device.DrawUserPrimitives(PrimitiveType.TriangleStrip, 0, 2, screenverts); } catch(Exception) { } graphics.Shaders.Base2D.EndPass(); graphics.Shaders.Base2D.End(); - - // Do we have things to render? - if((numthings > 0) && (thingsvertices != null)) - { - // Set renderstates - graphics.Device.SetRenderState(RenderState.CullMode, Cull.None); - graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, true); - graphics.Device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha); - graphics.Device.SetRenderState(RenderState.DestBlend, Blend.InvSourceAlpha); - graphics.Device.SetTexture(0, thingtexture.Texture); - graphics.Shaders.Things2D.Texture1 = thingtexture.Texture; - - // Set the vertex buffer - graphics.Device.SetStreamSource(0, thingsvertices, 0, FlatVertex.Stride); - - // Go for all things - for(int i = 0; i < numthings; i++) - { - // Set renderstates - graphics.Device.SetRenderState(RenderState.TextureFactor, thingcolors[i].ToInt()); - graphics.Shaders.Things2D.SetColors(thingcolors[i]); - - // Draw the thing circle - graphics.Shaders.Things2D.Begin(); - graphics.Shaders.Things2D.BeginPass(0); - try { graphics.Device.DrawPrimitives(PrimitiveType.TriangleStrip, i * 8, 2); } catch(Exception) { } - graphics.Shaders.Things2D.EndPass(); - - // Draw the thing icon - graphics.Shaders.Things2D.BeginPass(1); - try { graphics.Device.DrawPrimitives(PrimitiveType.TriangleStrip, i * 8 + 4, 2); } catch(Exception) { } - graphics.Shaders.Things2D.EndPass(); - graphics.Shaders.Things2D.End(); - } - } + + // Render things in front with full alpha? + if(thingsfront) PresentThings(255); // Done graphics.FinishRendering(); } } + // This presents the things + private void PresentThings(byte a) + { + // Do we have things to render? + if((numthings > 0) && (thingsvertices != null)) + { + // Set renderstates + graphics.Device.SetRenderState(RenderState.CullMode, Cull.None); + graphics.Device.SetRenderState(RenderState.AlphaBlendEnable, true); + graphics.Device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha); + graphics.Device.SetRenderState(RenderState.DestBlend, Blend.InvSourceAlpha); + graphics.Device.SetTexture(0, thingtexture.Texture); + graphics.Shaders.Things2D.Texture1 = thingtexture.Texture; + + // Set the vertex buffer + graphics.Device.SetStreamSource(0, thingsvertices, 0, FlatVertex.Stride); + + // Go for all things + for(int i = 0; i < numthings; i++) + { + // Set renderstates + graphics.Device.SetRenderState(RenderState.TextureFactor, thingcolors[i].ToInt()); + graphics.Shaders.Things2D.SetColors(thingcolors[i].WithAlpha(a)); + + // Draw the thing circle + graphics.Shaders.Things2D.Begin(); + graphics.Shaders.Things2D.BeginPass(0); + try { graphics.Device.DrawPrimitives(PrimitiveType.TriangleStrip, i * 8, 2); } + catch(Exception) { } + graphics.Shaders.Things2D.EndPass(); + + // Draw the thing icon + graphics.Shaders.Things2D.BeginPass(1); + try { graphics.Device.DrawPrimitives(PrimitiveType.TriangleStrip, i * 8 + 4, 2); } + catch(Exception) { } + graphics.Shaders.Things2D.EndPass(); + graphics.Shaders.Things2D.End(); + } + } + } + // This is called before a device is reset // (when resized or display adapter was changed) public override void UnloadResource() @@ -411,58 +429,65 @@ namespace CodeImp.DoomBuilder.Rendering // This makes vertices for a thing private void CreateThingVerts(Thing t, ref FlatVertex[] verts, int offset) { + float circlesize; + float arrowsize; + // Transform to screen coordinates Vector2D screenpos = ((Vector2D)t.Position).GetTransformed(translatex, translatey, scale, -scale); + // Determine sizes + circlesize = (t.Size - THING_CIRCLE_SHRINK) * scale * THING_CIRCLE_SIZE; + arrowsize = (t.Size - THING_ARROW_SHRINK) * scale * THING_ARROW_SIZE; + // Setup fixed rect for circle - verts[offset].x = screenpos.x - THING_CIRCLE_SIZE; - verts[offset].y = screenpos.y - THING_CIRCLE_SIZE; + verts[offset].x = screenpos.x - circlesize; + verts[offset].y = screenpos.y - circlesize; verts[offset].w = 1f; verts[offset].u = 1f / 512f; verts[offset].v = 1f / 128f; offset++; - verts[offset].x = screenpos.x + THING_CIRCLE_SIZE; - verts[offset].y = screenpos.y - THING_CIRCLE_SIZE; + verts[offset].x = screenpos.x + circlesize; + verts[offset].y = screenpos.y - circlesize; verts[offset].w = 1f; verts[offset].u = 0.25f - 1f / 512f; verts[offset].v = 1f / 128f; offset++; - verts[offset].x = screenpos.x - THING_CIRCLE_SIZE; - verts[offset].y = screenpos.y + THING_CIRCLE_SIZE; + verts[offset].x = screenpos.x - circlesize; + verts[offset].y = screenpos.y + circlesize; verts[offset].w = 1f; verts[offset].u = 1f / 512f; verts[offset].v = 1f - 1f / 128f; offset++; - verts[offset].x = screenpos.x + THING_CIRCLE_SIZE; - verts[offset].y = screenpos.y + THING_CIRCLE_SIZE; + verts[offset].x = screenpos.x + circlesize; + verts[offset].y = screenpos.y + circlesize; verts[offset].w = 1f; verts[offset].u = 0.25f - 1f / 512f; verts[offset].v = 1f - 1f / 128f; offset++; // Setup rotated rect for arrow - verts[offset].x = screenpos.x + (float)Math.Sin(t.Angle - Angle2D.PI * 0.25f) * THING_ARROW_SIZE; - verts[offset].y = screenpos.y + (float)Math.Cos(t.Angle - Angle2D.PI * 0.25f) * THING_ARROW_SIZE; + verts[offset].x = screenpos.x + (float)Math.Sin(t.Angle - Angle2D.PI * 0.25f) * arrowsize; + verts[offset].y = screenpos.y + (float)Math.Cos(t.Angle - Angle2D.PI * 0.25f) * arrowsize; verts[offset].w = 1f; - verts[offset].u = 0.50f; + verts[offset].u = 0.50f + t.IconOffset; verts[offset].v = 0f; offset++; - verts[offset].x = screenpos.x + (float)Math.Sin(t.Angle + Angle2D.PI * 0.25f) * THING_ARROW_SIZE; - verts[offset].y = screenpos.y + (float)Math.Cos(t.Angle + Angle2D.PI * 0.25f) * THING_ARROW_SIZE; + verts[offset].x = screenpos.x + (float)Math.Sin(t.Angle + Angle2D.PI * 0.25f) * arrowsize; + verts[offset].y = screenpos.y + (float)Math.Cos(t.Angle + Angle2D.PI * 0.25f) * arrowsize; verts[offset].w = 1f; - verts[offset].u = 0.75f; + verts[offset].u = 0.75f + t.IconOffset; verts[offset].v = 0f; offset++; - verts[offset].x = screenpos.x + (float)Math.Sin(t.Angle - Angle2D.PI * 0.75f) * THING_ARROW_SIZE; - verts[offset].y = screenpos.y + (float)Math.Cos(t.Angle - Angle2D.PI * 0.75f) * THING_ARROW_SIZE; + verts[offset].x = screenpos.x + (float)Math.Sin(t.Angle - Angle2D.PI * 0.75f) * arrowsize; + verts[offset].y = screenpos.y + (float)Math.Cos(t.Angle - Angle2D.PI * 0.75f) * arrowsize; verts[offset].w = 1f; - verts[offset].u = 0.50f; + verts[offset].u = 0.50f + t.IconOffset; verts[offset].v = 1f; offset++; - verts[offset].x = screenpos.x + (float)Math.Sin(t.Angle + Angle2D.PI * 0.75f) * THING_ARROW_SIZE; - verts[offset].y = screenpos.y + (float)Math.Cos(t.Angle + Angle2D.PI * 0.75f) * THING_ARROW_SIZE; + verts[offset].x = screenpos.x + (float)Math.Sin(t.Angle + Angle2D.PI * 0.75f) * arrowsize; + verts[offset].y = screenpos.y + (float)Math.Cos(t.Angle + Angle2D.PI * 0.75f) * arrowsize; verts[offset].w = 1f; - verts[offset].u = 0.75f; + verts[offset].u = 0.75f + t.IconOffset; verts[offset].v = 1f; } @@ -475,9 +500,7 @@ namespace CodeImp.DoomBuilder.Rendering { // Determine color if(t.Selected > 0) return General.Colors.Selection; - else return PixelColor.FromColor(Color.Tomato); - - // TODO: Check against game configuration or embed color into thing + else return t.Color; } // This returns the color for a vertex @@ -512,7 +535,18 @@ namespace CodeImp.DoomBuilder.Rendering #endregion - #region ================== Map Rendering + #region ================== Settings + + // This sets the things in front or back + public void SetThingsRenderOrder(bool front) + { + // Set things render order + this.thingsfront = front; + } + + #endregion + + #region ================== Rendering // This adds a thing in the things buffer for rendering public void RenderThing(Thing t, PixelColor c) diff --git a/Source/Resources/Actions.cfg b/Source/Resources/Actions.cfg index 550c15a8..df8a0707 100644 --- a/Source/Resources/Actions.cfg +++ b/Source/Resources/Actions.cfg @@ -175,3 +175,12 @@ sectorsmode allowmouse = true; allowscroll = true; } + +thingsmode +{ + title = "Tools: Things Mode"; + description = "Switches to things editing mode."; + allowkeys = true; + allowmouse = true; + allowscroll = true; +} diff --git a/Source/Resources/Thing2D.png b/Source/Resources/Thing2D.png index 474975f97c99aefc6d1d57485ac1bf95e8d1ab31..bc15905297e05613e234d16652687da6468636ab 100644 GIT binary patch literal 11522 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