From 9908e41197b0c2ef8a5df9d6c88798b4a9fd5ef0 Mon Sep 17 00:00:00 2001 From: MaxED <j.maxed@gmail.com> Date: Mon, 24 Oct 2016 19:19:11 +0000 Subject: [PATCH] Added, Game configurations: added "ignoreddirectories" parameter. It lists directory names to be ignored when loading PK3/PK7/Directory resources. Added, Game configurations: added "ignoredextensions" parameter. It lists file extensions to be ignored when loading PK3/PK7/Directory resources. Updated: sector triangulation logic now works ~20% faster. Changed: a case when a pk3/pk7 archive contains several entries with identical filename is now treated as a warning, not as an error. Fixed, Visual mode: absolute floor/ceiling brightness should not be affected by brightness transfer effects (like 3d floors). Fixed, Draw Lines mode: in some cases unclosed sectors were created when several points were successively drawn at the same location. Updated documentation. --- Build/Configurations/Includes/Common.cfg | 6 ++ Help/gc_basicsettings.html | 18 +++- Source/Core/Config/GameConfiguration.cs | 12 +++ Source/Core/Data/PK3Reader.cs | 2 +- Source/Core/Geometry/Triangulation.cs | 90 +++++++++++-------- Source/Core/IO/DirectoryFilesList.cs | 44 ++++++--- .../ClassicModes/DrawGeometryMode.cs | 8 ++ .../BuilderModes/VisualModes/SectorData.cs | 45 ++++++---- 8 files changed, 158 insertions(+), 67 deletions(-) diff --git a/Build/Configurations/Includes/Common.cfg b/Build/Configurations/Includes/Common.cfg index 57b125880..93880b232 100644 --- a/Build/Configurations/Includes/Common.cfg +++ b/Build/Configurations/Includes/Common.cfg @@ -27,6 +27,12 @@ bottomboundary = -32768; longtexturenames = false; +//mxd. These directory names are ignored when loading PK3/PK7/Directory resources +ignoreddirectories = ".svn .git"; + + +//mxd. Files with these extensions are ignored when loading PK3/PK7/Directory resources +ignoredextensions = "wad pk3 pk7 bak backup1 backup2 backup3 zip rar 7z"; // Things used by the editor thingtypes diff --git a/Help/gc_basicsettings.html b/Help/gc_basicsettings.html index 218d6bd21..9e1f001c4 100644 --- a/Help/gc_basicsettings.html +++ b/Help/gc_basicsettings.html @@ -81,7 +81,6 @@ skills damagetypes = "None BFGSplash Drowning Slime"; </pre> <br /> - <b class="fat">internalsoundnames</b> (string) - <span class="red">GZDB only</span>.<br /> Space-separated list of built-in logical sound names. These names won't trigger an editor warning when they are not bound to actual sounds in SNDINFO.<br /> <br /> @@ -90,7 +89,22 @@ damagetypes = "None BFGSplash Drowning Slime"; internalsoundnames = "*death *xdeath *wimpydeath *crazydeath *burndeath"; </pre> <br /> - + <b class="fat">ignoredextensions</b> (string) - <span class="red">GZDB only</span>.<br /> + Space-separated list of file extensions. Files with these extensions will be ignored when loading PK3/PK7/Directory resources.<br /> + <br /> + <strong>Example:</strong> + <pre> +ignoredextensions = "wad pk3 pk7 bak backup1 backup2 backup3 zip rar 7z"; +</pre> +<br /> +<b class="fat">ignoreddirectories</b> (string) - <span class="red">GZDB only</span>.<br /> + Space-separated list of directory names. These directory names are ignored when loading PK3/PK7/Directory resources. This applies to top level directories only.<br /> + <br /> + <strong>Example:</strong> + <pre> +ignoreddirectories = ".svn .git"; +</pre> +<br /> <b class="fat">linetagindicatesectors</b> (boolean)<br /> When <b>true</b>, Doom Builder will highlight sectors associated with the same tag number when a line is highlighted. This is only really useful for Doom format maps, because Hexen format and UDMF format has no single tag on linedefs (in those formats, the arguments of the linedef's action can be tags, which also works to highlight sectors).<br /> Default value is <b>false</b>.<br /> diff --git a/Source/Core/Config/GameConfiguration.cs b/Source/Core/Config/GameConfiguration.cs index 93f7d7bfa..c1a195628 100644 --- a/Source/Core/Config/GameConfiguration.cs +++ b/Source/Core/Config/GameConfiguration.cs @@ -160,6 +160,10 @@ namespace CodeImp.DoomBuilder.Config //mxd. Internal sounds. These logical sound names won't trigger a warning when they are not bound to actual sounds in SOUNDINFO. private HashSet<string> internalsoundnames; + + //mxd. Stuff to ignore + private HashSet<string> ignoreddirectories; + private HashSet<string> ignoredextensions; // Defaults private readonly List<DefinedTextureSet> texturesets; @@ -291,6 +295,10 @@ namespace CodeImp.DoomBuilder.Config //mxd. Internal sounds internal HashSet<string> InternalSoundNames { get { return internalsoundnames; } } + //mxd. Stuff to ignore + internal HashSet<string> IgnoredFileExtensions { get { return ignoredextensions; } } + internal HashSet<string> IgnoredDirectoryNames { get { return ignoreddirectories; } } + // Defaults internal List<DefinedTextureSet> TextureSets { get { return texturesets; } } public List<ThingsFilter> ThingsFilters { get { return thingfilters; } } @@ -438,6 +446,10 @@ namespace CodeImp.DoomBuilder.Config damagetypes = new HashSet<string>(cfg.ReadSetting("damagetypes", "None").Split(splitter, StringSplitOptions.RemoveEmptyEntries), StringComparer.OrdinalIgnoreCase); internalsoundnames = new HashSet<string>(cfg.ReadSetting("internalsoundnames", string.Empty).Split(splitter, StringSplitOptions.RemoveEmptyEntries), StringComparer.OrdinalIgnoreCase); + //mxd. Load stuff to ignore + ignoreddirectories = new HashSet<string>(cfg.ReadSetting("ignoreddirectories", string.Empty).Split(splitter, StringSplitOptions.RemoveEmptyEntries), StringComparer.OrdinalIgnoreCase); + ignoredextensions = new HashSet<string>(cfg.ReadSetting("ignoredextensions", string.Empty).Split(splitter, StringSplitOptions.RemoveEmptyEntries), StringComparer.OrdinalIgnoreCase); + // Things LoadThingFlags(); LoadDefaultThingFlags(); diff --git a/Source/Core/Data/PK3Reader.cs b/Source/Core/Data/PK3Reader.cs index 0483a52ef..53ab3b2f1 100644 --- a/Source/Core/Data/PK3Reader.cs +++ b/Source/Core/Data/PK3Reader.cs @@ -97,7 +97,7 @@ namespace CodeImp.DoomBuilder.Data archive = null; // Make files list - files = new DirectoryFilesList(fileentries); + files = new DirectoryFilesList(dl.GetDisplayName(), fileentries); // Initialize without path (because we use paths relative to the PK3 file) Initialize(); diff --git a/Source/Core/Geometry/Triangulation.cs b/Source/Core/Geometry/Triangulation.cs index 9f6e554c5..42de01ff6 100644 --- a/Source/Core/Geometry/Triangulation.cs +++ b/Source/Core/Geometry/Triangulation.cs @@ -374,18 +374,18 @@ namespace CodeImp.DoomBuilder.Geometry Vertex found = null; // Go for all sides to find the right-most side - foreach(KeyValuePair<Sidedef, bool> sd in sides) + foreach(Sidedef sd in sides.Keys) { // First found? - if((found == null) && !ignores.ContainsKey(sd.Key.Line.Start)) found = sd.Key.Line.Start; - if((found == null) && !ignores.ContainsKey(sd.Key.Line.End)) found = sd.Key.Line.End; + if((found == null) && !ignores.ContainsKey(sd.Line.Start)) found = sd.Line.Start; + if((found == null) && !ignores.ContainsKey(sd.Line.End)) found = sd.Line.End; // Compare? if(found != null) { // Check if more to the right than the previous found - if((sd.Key.Line.Start.Position.x > found.Position.x) && !ignores.ContainsKey(sd.Key.Line.Start)) found = sd.Key.Line.Start; - if((sd.Key.Line.End.Position.x > found.Position.x) && !ignores.ContainsKey(sd.Key.Line.End)) found = sd.Key.Line.End; + if((sd.Line.Start.Position.x > found.Position.x) && !ignores.ContainsKey(sd.Line.Start)) found = sd.Line.Start; + if((sd.Line.End.Position.x > found.Position.x) && !ignores.ContainsKey(sd.Line.End)) found = sd.Line.End; } } @@ -779,11 +779,16 @@ namespace CodeImp.DoomBuilder.Geometry // This checks if a given ear is a valid (no intersections from reflex vertices) private static bool CheckValidEar(EarClipVertex[] t, LinkedList<EarClipVertex> reflexes) { + //mxd + Vector2D pos0 = t[0].Position; + Vector2D pos1 = t[1].Position; + Vector2D pos2 = t[2].Position; + // Go for all reflex vertices foreach(EarClipVertex rv in reflexes) { // Not one of the triangle corners? - if((rv.Position != t[0].Position) && (rv.Position != t[1].Position) && (rv.Position != t[2].Position)) + if((rv.Position != pos0) && (rv.Position != pos1) && (rv.Position != pos2)) { // Return false on intersection if(PointInsideTriangle(t, rv.MainListNode)) return false; @@ -797,11 +802,12 @@ namespace CodeImp.DoomBuilder.Geometry // This returns the 3-vertex array triangle for an ear private static EarClipVertex[] GetTriangle(EarClipVertex v) { - EarClipVertex[] t = new EarClipVertex[3]; - t[0] = (v.MainListNode.Previous == null) ? v.MainListNode.List.Last.Value : v.MainListNode.Previous.Value; - t[1] = v; - t[2] = (v.MainListNode.Next == null) ? v.MainListNode.List.First.Value : v.MainListNode.Next.Value; - return t; + return new [] + { + (v.MainListNode.Previous == null) ? v.MainListNode.List.Last.Value : v.MainListNode.Previous.Value, + v, + (v.MainListNode.Next == null) ? v.MainListNode.List.First.Value : v.MainListNode.Next.Value + }; } // This checks if a vertex is reflex (corner > 180 deg) or convex (corner < 180 deg) @@ -820,18 +826,23 @@ namespace CodeImp.DoomBuilder.Geometry // If the triangle has no area, there can never be a point inside if(TriangleHasArea(t)) { - float lineside01 = Line2D.GetSideOfLine(t[0].Position, t[1].Position, p.Value.Position); - float lineside12 = Line2D.GetSideOfLine(t[1].Position, t[2].Position, p.Value.Position); - float lineside20 = Line2D.GetSideOfLine(t[2].Position, t[0].Position, p.Value.Position); + //mxd + Vector2D pos0 = t[0].Position; + Vector2D pos1 = t[1].Position; + Vector2D pos2 = t[2].Position; + + float lineside01 = Line2D.GetSideOfLine(pos0, pos1, p.Value.Position); + float lineside12 = Line2D.GetSideOfLine(pos1, pos2, p.Value.Position); + float lineside20 = Line2D.GetSideOfLine(pos2, pos0, p.Value.Position); float u_on_line = 0.5f; // If point p is on the line of an edge, find out where on the edge segment p is. if(lineside01 == 0.0f) - u_on_line = Line2D.GetNearestOnLine(t[0].Position, t[1].Position, p.Value.Position); + u_on_line = Line2D.GetNearestOnLine(pos0, pos1, p.Value.Position); else if(lineside12 == 0.0f) - u_on_line = Line2D.GetNearestOnLine(t[1].Position, t[2].Position, p.Value.Position); + u_on_line = Line2D.GetNearestOnLine(pos1, pos2, p.Value.Position); else if(lineside20 == 0.0f) - u_on_line = Line2D.GetNearestOnLine(t[2].Position, t[0].Position, p.Value.Position); + u_on_line = Line2D.GetNearestOnLine(pos2, pos0, p.Value.Position); // If any of the lineside results are 0 then that means the point p lies on that edge and we // need to test if the lines adjacent to the point p are in the triangle or not. @@ -877,9 +888,10 @@ namespace CodeImp.DoomBuilder.Geometry // Line is inside triangle, because p2 is return true; } + // Test if p2 is on an edge of the triangle and if it is we would // like to know where on the edge segment p2 is - else if(s01 == 0.0f) + if(s01 == 0.0f) { p2_on_edge = Line2D.GetNearestOnLine(t[0].Position, t[1].Position, p2); p1_on_same_edge = Line2D.GetSideOfLine(t[0].Position, t[1].Position, p1); @@ -912,13 +924,10 @@ namespace CodeImp.DoomBuilder.Geometry Line2D t20 = new Line2D(t[2].Position, t[0].Position); float pu, pt; - // Test intersections - t01.GetIntersection(p, out pu, out pt); - if(!float.IsNaN(pu) && (pu >= 0.0f) && (pu <= 1.0f) && (pt >= 0.0f) && (pt <= 1.0f)) return true; - t12.GetIntersection(p, out pu, out pt); - if(!float.IsNaN(pu) && (pu >= 0.0f) && (pu <= 1.0f) && (pt >= 0.0f) && (pt <= 1.0f)) return true; - t20.GetIntersection(p, out pu, out pt); - if(!float.IsNaN(pu) && (pu >= 0.0f) && (pu <= 1.0f) && (pt >= 0.0f) && (pt <= 1.0f)) return true; + //mxd. Test intersections + if(t01.GetIntersection(p, out pu, out pt)) return true; + if(t12.GetIntersection(p, out pu, out pt)) return true; + if(t20.GetIntersection(p, out pu, out pt)) return true; return false; } @@ -926,24 +935,33 @@ namespace CodeImp.DoomBuilder.Geometry // This checks if the triangle has an area greater than 0 private static bool TriangleHasArea(EarClipVertex[] t) { - return ((t[0].Position.x * (t[1].Position.y - t[2].Position.y) + - t[1].Position.x * (t[2].Position.y - t[0].Position.y) + - t[2].Position.x * (t[0].Position.y - t[1].Position.y)) != 0.0f); + Vector2D tp0 = t[0].Position; + Vector2D tp1 = t[1].Position; + Vector2D tp2 = t[2].Position; + + return ((tp0.x * (tp1.y - tp2.y) + + tp1.x * (tp2.y - tp0.y) + + tp2.x * (tp0.y - tp1.y)) != 0.0f); } // This adds an array of vertices private static void AddTriangleToList(EarClipVertex[] triangle, List<Vector2D> verticeslist, List<Sidedef> sidedefslist, bool last) { - // Create triangle - verticeslist.Add(triangle[0].Position); - sidedefslist.Add(triangle[0].Sidedef); - verticeslist.Add(triangle[1].Position); - sidedefslist.Add(triangle[1].Sidedef); - verticeslist.Add(triangle[2].Position); - if(!last) sidedefslist.Add(null); else sidedefslist.Add(triangle[2].Sidedef); + //mxd + EarClipVertex v0 = triangle[0]; + EarClipVertex v1 = triangle[1]; + EarClipVertex v2 = triangle[2]; + // Create triangle + verticeslist.Add(v0.Position); + sidedefslist.Add(v0.Sidedef); + verticeslist.Add(v1.Position); + sidedefslist.Add(v1.Sidedef); + verticeslist.Add(v2.Position); + sidedefslist.Add(!last ? null : v2.Sidedef); + // Modify the first earclipvertex of this triangle, it no longer lies along a sidedef - triangle[0].Sidedef = null; + v0.Sidedef = null; } #endregion diff --git a/Source/Core/IO/DirectoryFilesList.cs b/Source/Core/IO/DirectoryFilesList.cs index f373d99ac..8e390c05c 100644 --- a/Source/Core/IO/DirectoryFilesList.cs +++ b/Source/Core/IO/DirectoryFilesList.cs @@ -29,11 +29,6 @@ namespace CodeImp.DoomBuilder.IO { #region ================== Constants (mxd) - private static HashSet<string> EXLUDE_EXTENSIONS = new HashSet<string>(StringComparer.OrdinalIgnoreCase) - { - "wad", "pk3", "pk7", "bak", "backup1", "backup2", "backup3", "zip", "rar", "7z" - }; - #endregion #region ================== Variables @@ -68,17 +63,26 @@ namespace CodeImp.DoomBuilder.IO wadentries.Add(file); continue; } - if(EXLUDE_EXTENSIONS.Contains(e.extension)) continue; - - if(entries.ContainsKey(e.filepathname)) - throw new IOException("Multiple files with the same filename in the same directory are not allowed. See: \"" + e.filepathname + "\""); + + if(General.Map.Config.IgnoredFileExtensions.Contains(e.extension)) continue; + + bool skipfolder = false; + foreach(string ef in General.Map.Config.IgnoredDirectoryNames) + { + if(e.path.StartsWith(ef + Path.DirectorySeparatorChar)) + { + skipfolder = true; + break; + } + } + if(skipfolder) continue; entries.Add(e.filepathname, e); } } // Constructor for custom list - public DirectoryFilesList(ICollection<DirectoryFileEntry> sourceentries) + public DirectoryFilesList(string resourcename, ICollection<DirectoryFileEntry> sourceentries) { entries = new Dictionary<string, DirectoryFileEntry>(sourceentries.Count, StringComparer.OrdinalIgnoreCase); wadentries = new List<string>(); @@ -89,10 +93,26 @@ namespace CodeImp.DoomBuilder.IO wadentries.Add(e.filepathname); continue; } - if(EXLUDE_EXTENSIONS.Contains(e.extension)) continue; + + if(General.Map.Config.IgnoredFileExtensions.Contains(e.extension)) continue; + + bool skipfolder = false; + foreach(string ef in General.Map.Config.IgnoredDirectoryNames) + { + if(e.path.StartsWith(ef + Path.DirectorySeparatorChar)) + { + skipfolder = true; + break; + } + } + if(skipfolder) continue; if(entries.ContainsKey(e.filepathname)) - throw new IOException("Multiple files with the same filename in the same directory are not allowed. See: \"" + e.filepathname + "\""); + { + General.ErrorLogger.Add(ErrorType.Warning, "Resource \"" + resourcename + "\" contains multiple files with the same filename. See: \"" + e.filepathname + "\""); + continue; + } + entries.Add(e.filepathname, e); } } diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs index a792ac32e..14f0d03b9 100644 --- a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs +++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs @@ -545,6 +545,14 @@ namespace CodeImp.DoomBuilder.BuilderModes pos.y > General.Map.Config.TopBoundary || pos.y < General.Map.Config.BottomBoundary) return false; + //mxd. Avoid zero-length lines... + if(points.Count > 0) + { + Vector2D delta = points[points.Count - 1].pos - pos; + if((Math.Abs(delta.x) <= 0.001f) && (Math.Abs(delta.y) <= 0.001f)) + return true; + } + DrawnVertex newpoint = new DrawnVertex(); newpoint.pos = pos; newpoint.stitch = stitch; diff --git a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs index b156b2d45..50926a0af 100644 --- a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs +++ b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs @@ -56,6 +56,12 @@ namespace CodeImp.DoomBuilder.BuilderModes private bool floorchanged; private bool ceilingchanged; + //mxd. Absolute lights are not affected by brightness transfers... + private bool lightfloorabsolute; + private bool lightceilingabsolute; + private int lightfloor; + private int lightceiling; + #endregion #region ================== Properties @@ -288,17 +294,17 @@ namespace CodeImp.DoomBuilder.BuilderModes // Fetch ZDoom fields int color = sector.Fields.GetValue("lightcolor", -1); - int flight = sector.Fields.GetValue("lightfloor", 0); - bool fabs = sector.Fields.GetValue("lightfloorabsolute", false); - int clight = sector.Fields.GetValue("lightceiling", 0); - bool cabs = sector.Fields.GetValue("lightceilingabsolute", false); + lightfloor = sector.Fields.GetValue("lightfloor", 0); + lightfloorabsolute = sector.Fields.GetValue("lightfloorabsolute", false); + lightceiling = sector.Fields.GetValue("lightceiling", 0); + lightceilingabsolute = sector.Fields.GetValue("lightceilingabsolute", false); // Determine colors & light levels PixelColor lightcolor = PixelColor.FromInt(color); - if(!fabs) flight = sector.Brightness + flight; - if(!cabs) clight = sector.Brightness + clight; - PixelColor floorbrightness = PixelColor.FromInt(mode.CalculateBrightness(flight)); - PixelColor ceilingbrightness = PixelColor.FromInt(mode.CalculateBrightness(clight)); + if(!lightfloorabsolute) lightfloor = sector.Brightness + lightfloor; + if(!lightceilingabsolute) lightceiling = sector.Brightness + lightceiling; + PixelColor floorbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightfloor)); + PixelColor ceilingbrightness = PixelColor.FromInt(mode.CalculateBrightness(lightceiling)); PixelColor floorcolor = PixelColor.Modulate(lightcolor, floorbrightness); PixelColor ceilingcolor = PixelColor.Modulate(lightcolor, ceilingbrightness); floor.color = floorcolor.WithAlpha(255).ToInt(); @@ -357,7 +363,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { lightlevels[lightlevels.Count - 1].colorbelow = stored.colorbelow; lightlevels[lightlevels.Count - 1].brightnessbelow = stored.brightnessbelow; - lightlevels[lightlevels.Count - 1].color = GetLevelColor(stored); + lightlevels[lightlevels.Count - 1].color = GetLevelColor(stored, lightlevels[lightlevels.Count - 1]); } //mxd. Cast light properties from top to bottom @@ -378,12 +384,12 @@ namespace CodeImp.DoomBuilder.BuilderModes { l.colorbelow = stored.colorbelow; l.brightnessbelow = stored.brightnessbelow; - l.color = GetLevelColor(stored); + l.color = GetLevelColor(stored, l); } else if(l.restrictlighting) { if(!pl.restrictlighting && pl != ceiling) stored = pl; - l.color = GetLevelColor(stored); + l.color = GetLevelColor(stored, l); // This is the bottom side of extrafloor with "restrict lighting" flag. Make it cast stored light props. if(l.type == SectorLevelType.Ceiling) @@ -394,10 +400,10 @@ namespace CodeImp.DoomBuilder.BuilderModes // Use light and color settings from previous layer l.colorbelow = pl.colorbelow; l.brightnessbelow = pl.brightnessbelow; - l.color = GetLevelColor(pl); + l.color = GetLevelColor(pl, l); // Also colorize previous layer using next higher level color - if(i + 2 < lightlevels.Count) pl.color = GetLevelColor(lightlevels[i + 2]); + if(i + 2 < lightlevels.Count) pl.color = GetLevelColor(lightlevels[i + 2], pl); } else { @@ -439,7 +445,7 @@ namespace CodeImp.DoomBuilder.BuilderModes if(src.colorbelow.a > 0 && src.brightnessbelow != -1) { // Only surface brightness is retained when a glowing flat is used as extrafloor texture - if(!l.affectedbyglow) l.color = GetLevelColor(src); + if(!l.affectedbyglow) l.color = GetLevelColor(src, l); // Transfer brightnessbelow and colorbelow if current level is not extrafloor top if(!(l.extrafloor && l.type == SectorLevelType.Floor)) @@ -594,9 +600,16 @@ namespace CodeImp.DoomBuilder.BuilderModes } //mxd - private int GetLevelColor(SectorLevel src) + private int GetLevelColor(SectorLevel src, SectorLevel target) { - PixelColor brightness = PixelColor.FromInt(mode.CalculateBrightness(src.brightnessbelow)); + PixelColor brightness; + if(lightfloorabsolute && target == floor) + brightness = PixelColor.FromInt(mode.CalculateBrightness(lightfloor)); + else if(lightceilingabsolute && target == ceiling) + brightness = PixelColor.FromInt(mode.CalculateBrightness(lightceiling)); + else + brightness = PixelColor.FromInt(mode.CalculateBrightness(src.brightnessbelow)); + PixelColor color = PixelColor.Modulate(src.colorbelow, brightness); return color.WithAlpha(255).ToInt(); } -- GitLab