From 718405b58085a4aa7f173eb1957765431e2f5bee Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 25 Dec 2019 18:57:39 +0100 Subject: [PATCH 1/7] Remove the remaining dictionary lookups when culling --- Source/Core/Map/Sector.cs | 17 +- Source/Core/Map/Sidedef.cs | 3 + Source/Core/Map/Thing.cs | 8 + Source/Core/VisualModes/VisualMode.cs | 181 +++++++++--------- Source/Core/VisualModes/VisualSector.cs | 11 +- .../VisualModes/BaseVisualMode.cs | 125 +++++------- 6 files changed, 169 insertions(+), 176 deletions(-) diff --git a/Source/Core/Map/Sector.cs b/Source/Core/Map/Sector.cs index a6759cca..6ca66481 100755 --- a/Source/Core/Map/Sector.cs +++ b/Source/Core/Map/Sector.cs @@ -23,6 +23,7 @@ using CodeImp.DoomBuilder.Geometry; using System.Drawing; using CodeImp.DoomBuilder.Rendering; using System.Collections.ObjectModel; +using CodeImp.DoomBuilder.VisualModes; #endregion @@ -88,6 +89,7 @@ namespace CodeImp.DoomBuilder.Map private Color4 fogcolor; private SectorFogMode fogmode; private int lastProcessed; + private VisualSector visualsector; //mxd. Slopes private Vector3D floorslope; @@ -144,13 +146,14 @@ namespace CodeImp.DoomBuilder.Map public Vector3D CeilSlope { get { return ceilslope; } set { BeforePropsChange(); ceilslope = value; updateneeded = true; } } public float CeilSlopeOffset { get { return ceiloffset; } set { BeforePropsChange(); ceiloffset = value; updateneeded = true; } } internal int LastProcessed { get { return lastProcessed; } set { lastProcessed = value; } } + public VisualSector VisualSector { get { return visualsector; } set { visualsector = value; } } - #endregion + #endregion - #region ================== Constructor / Disposer + #region ================== Constructor / Disposer - // Constructor - internal Sector(MapSet map, int listindex, int index) + // Constructor + internal Sector(MapSet map, int listindex, int index) { // Initialize this.elementtype = MapElementType.SECTOR; //mxd @@ -208,6 +211,12 @@ namespace CodeImp.DoomBuilder.Map sidedefs = null; map = null; + if (visualsector != null) + { + visualsector.Dispose(); + visualsector = null; + } + //mxd. Restore isdisposed so base classes can do their disposal job isdisposed = false; diff --git a/Source/Core/Map/Sidedef.cs b/Source/Core/Map/Sidedef.cs index 35d1adba..6783b3ba 100755 --- a/Source/Core/Map/Sidedef.cs +++ b/Source/Core/Map/Sidedef.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using CodeImp.DoomBuilder.IO; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.VisualModes; #endregion @@ -60,6 +61,7 @@ namespace CodeImp.DoomBuilder.Map // Rendering private int lastProcessed; + private List visualgeometry; #endregion @@ -82,6 +84,7 @@ namespace CodeImp.DoomBuilder.Map public long LongLowTexture { get { return longtexnamelow; } } internal int SerializedIndex { get { return serializedindex; } set { serializedindex = value; } } internal int LastProcessed { get { return lastProcessed; } set { lastProcessed = value; } } + internal List VisualGeometry { get { return visualgeometry; } set { visualgeometry = value; } } #endregion diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs index 660fa26b..08a08124 100755 --- a/Source/Core/Map/Thing.cs +++ b/Source/Core/Map/Thing.cs @@ -88,6 +88,7 @@ namespace CodeImp.DoomBuilder.Map // Rendering private int lastProcessed; + private VisualThing visualthing; #endregion @@ -120,6 +121,7 @@ namespace CodeImp.DoomBuilder.Map public bool IsDirectional { get { return directional; } } //mxd public bool Highlighted { get { return highlighted; } set { highlighted = value; } } //mxd internal int LastProcessed { get { return lastProcessed; } set { lastProcessed = value; } } + public VisualThing VisualThing { get { return visualthing; } set { visualthing = value; } } #endregion @@ -161,6 +163,12 @@ namespace CodeImp.DoomBuilder.Map map = null; sector = null; + if (visualthing != null) + { + visualthing.Dispose(); + visualthing = null; + } + // Dispose base base.Dispose(); } diff --git a/Source/Core/VisualModes/VisualMode.cs b/Source/Core/VisualModes/VisualMode.cs index 049eb8f9..4dbd9d2f 100755 --- a/Source/Core/VisualModes/VisualMode.cs +++ b/Source/Core/VisualModes/VisualMode.cs @@ -25,6 +25,7 @@ using CodeImp.DoomBuilder.Rendering; using CodeImp.DoomBuilder.Actions; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Editing; +using System.Linq; #endregion @@ -70,8 +71,6 @@ namespace CodeImp.DoomBuilder.VisualModes // Map protected VisualBlockMap blockmap; - protected Dictionary allthings; - protected Dictionary allsectors; protected List visibleblocks; protected List visiblethings; protected List visiblesectors; @@ -101,8 +100,6 @@ namespace CodeImp.DoomBuilder.VisualModes // Initialize this.renderer = General.Map.Renderer3D; this.blockmap = new VisualBlockMap(); - this.allsectors = new Dictionary(General.Map.Map.Sectors.Count); - this.allthings = new Dictionary(General.Map.Map.Things.Count); this.visibleblocks = new List(); this.visiblesectors = new List(50); this.visiblegeometry = new List(200); @@ -129,15 +126,20 @@ namespace CodeImp.DoomBuilder.VisualModes // Not already disposed? if(!isdisposed) { - // Clean up - foreach(KeyValuePair s in allsectors) s.Value.Dispose(); + // Clean up + foreach (Sector sector in General.Map.Map.Sectors) + { + if (sector.VisualSector != null) + { + sector.VisualSector.Dispose(); + sector.VisualSector = null; + } + } blockmap.Dispose(); visiblesectors = null; visiblegeometry = null; visibleblocks = null; visiblethings = null; - allsectors = null; - allthings = null; blockmap = null; //mxd @@ -216,14 +218,26 @@ namespace CodeImp.DoomBuilder.VisualModes public override void OnDisengage() { base.OnDisengage(); - - // Dispose - foreach(KeyValuePair vs in allsectors) - if(vs.Value != null) vs.Value.Dispose(); - // Dispose - foreach(KeyValuePair vt in allthings) - if(vt.Value != null) vt.Value.Dispose(); + // Dispose + foreach (Sector sector in General.Map.Map.Sectors) + { + if (sector.VisualSector != null) + { + sector.VisualSector.Dispose(); + sector.VisualSector = null; + } + } + + // Dispose + foreach (Thing thing in General.Map.Map.Things) + { + if (thing.VisualThing != null) + { + thing.VisualThing.Dispose(); + thing.VisualThing = null; + } + } // Apply camera position to thing General.Map.VisualCamera.ApplyToThing(); @@ -567,22 +581,11 @@ namespace CodeImp.DoomBuilder.VisualModes // Not filtered out? if(!General.Map.ThingsFilter.IsThingVisible(t)) continue; - VisualThing vt; - if(allthings.ContainsKey(t)) - { - vt = allthings[t]; - } - else - { - // Create new visual thing - vt = CreateVisualThing(t); - allthings[t] = vt; - } + if (t.VisualThing == null) + t.VisualThing = CreateVisualThing(t); - if(vt != null) - { - visiblethings.Add(vt); - } + if(t.VisualThing != null) + visiblethings.Add(t.VisualThing); } } } @@ -640,32 +643,20 @@ namespace CodeImp.DoomBuilder.VisualModes sd.LastProcessed = lastProcessed; - VisualSector vs; + if (sd.Sector.VisualSector == null) + sd.Sector.VisualSector = CreateVisualSector(sd.Sector); - // Find the visualsector and make it if needed - if(allsectors.ContainsKey(sd.Sector)) - { - // Take existing visualsector - vs = allsectors[sd.Sector]; - } - else - { - // Make new visualsector - vs = CreateVisualSector(sd.Sector); - //if(vs != null) allsectors.Add(sd.Sector, vs); //mxd - } - - if(vs != null) + if(sd.Sector.VisualSector != null) { if (sd.Sector.LastProcessed != lastProcessed) { sd.Sector.LastProcessed = lastProcessed; - visiblesectors.Add(vs); - visiblegeometry.AddRange(vs.FixedGeometry); + visiblesectors.Add(sd.Sector.VisualSector); + visiblegeometry.AddRange(sd.Sector.VisualSector.FixedGeometry); } // Add sidedef geometry - visiblegeometry.AddRange(vs.GetSidedefGeometry(sd)); + visiblegeometry.AddRange(sd.Sector.VisualSector.GetSidedefGeometry(sd)); } } @@ -705,9 +696,9 @@ namespace CodeImp.DoomBuilder.VisualModes List pickables = new List(blocks.Count * 10); // Add geometry from the camera sector - if((General.Map.VisualCamera.Sector != null) && allsectors.ContainsKey(General.Map.VisualCamera.Sector)) + if(General.Map.VisualCamera.Sector != null && General.Map.VisualCamera.Sector.VisualSector != null) { - VisualSector vs = allsectors[General.Map.VisualCamera.Sector]; + VisualSector vs = General.Map.VisualCamera.Sector.VisualSector; sectors.Add(General.Map.VisualCamera.Sector, vs); foreach(VisualGeometry g in vs.FixedGeometry) pickables.Add(g); } @@ -740,9 +731,9 @@ namespace CodeImp.DoomBuilder.VisualModes if(ld.Front != null) { // Find the visualsector - if(allsectors.ContainsKey(ld.Front.Sector)) + if(ld.Front.Sector.VisualSector != null) { - VisualSector vs = allsectors[ld.Front.Sector]; + VisualSector vs = ld.Front.Sector.VisualSector; // Add sector if not already added if(!sectors.ContainsKey(ld.Front.Sector)) @@ -777,9 +768,9 @@ namespace CodeImp.DoomBuilder.VisualModes if(ld.Back != null) { // Find the visualsector - if(allsectors.ContainsKey(ld.Back.Sector)) + if(ld.Back.Sector.VisualSector != null) { - VisualSector vs = allsectors[ld.Back.Sector]; + VisualSector vs = ld.Back.Sector.VisualSector; // Add sector if not already added if(!sectors.ContainsKey(ld.Back.Sector)) @@ -867,16 +858,26 @@ namespace CodeImp.DoomBuilder.VisualModes /// protected virtual void ResourcesReloaded() { - // Dispose - foreach(KeyValuePair vs in allsectors) - if(vs.Value != null) vs.Value.Dispose(); - - foreach(KeyValuePair vt in allthings) - if(vt.Value != null) vt.Value.Dispose(); + // Dispose + foreach (Sector sector in General.Map.Map.Sectors) + { + if (sector.VisualSector != null) + { + sector.VisualSector.Dispose(); + sector.VisualSector = null; + } + } + + foreach (Thing thing in General.Map.Map.Things) + { + if (thing.VisualThing != null) + { + thing.VisualThing.Dispose(); + thing.VisualThing = null; + } + } // Clear collections - allsectors.Clear(); - allthings.Clear(); visiblesectors.Clear(); visibleblocks.Clear(); visiblegeometry.Clear(); @@ -897,8 +898,6 @@ namespace CodeImp.DoomBuilder.VisualModes /// protected virtual void ResourcesReloadedPartial() { - Dictionary newsectors = new Dictionary(allsectors.Count); - // Neighbour sectors must be updated as well foreach(Sector s in General.Map.Map.Sectors) { @@ -933,27 +932,27 @@ namespace CodeImp.DoomBuilder.VisualModes } } - // Dispose if source was disposed or marked - foreach(KeyValuePair vs in allsectors) + // Dispose if source was marked + foreach(Sector s in General.Map.Map.Sectors) { - if(vs.Value != null) + if(s.Marked && s.VisualSector != null) { - if(vs.Key.IsDisposed || vs.Key.Marked) - vs.Value.Dispose(); - else - newsectors.Add(vs.Key, vs.Value); + s.VisualSector.Dispose(); + s.VisualSector = null; } } // Things depend on the sector they are in and because we can't // easily determine which ones changed, we dispose all things - foreach(KeyValuePair vt in allthings) - if(vt.Value != null) vt.Value.Dispose(); - - // Apply new lists - allsectors = newsectors; - allthings = new Dictionary(allthings.Count); - + foreach (Thing thing in General.Map.Map.Things) + { + if (thing.VisualThing != null) + { + thing.VisualThing.Dispose(); + thing.VisualThing = null; + } + } + // Clear visibility collections visiblesectors.Clear(); visibleblocks.Clear(); @@ -982,14 +981,14 @@ namespace CodeImp.DoomBuilder.VisualModes /// public VisualSector GetVisualSector(Sector s) { - if(!allsectors.ContainsKey(s)) return CreateVisualSector(s); //mxd - return allsectors[s]; + if(s.VisualSector == null) return CreateVisualSector(s); //mxd + return s.VisualSector; } /// /// This returns the VisualThing for the given Thing. /// - public VisualThing GetVisualThing(Thing t) { return allthings[t]; } + public VisualThing GetVisualThing(Thing t) { return t.VisualThing; } //mxd public List GetSelectedVisualThings(bool refreshSelection) @@ -997,10 +996,10 @@ namespace CodeImp.DoomBuilder.VisualModes if(refreshSelection || selectedVisualThings == null) { selectedVisualThings = new List(); - foreach(KeyValuePair group in allthings) + foreach(Thing t in General.Map.Map.Things) { - if(group.Value != null && group.Value.Selected) - selectedVisualThings.Add(group.Value); + if(t.VisualThing != null && t.VisualThing.Selected) + selectedVisualThings.Add(t.VisualThing); } //if nothing is selected - try to get thing from hilighted object @@ -1028,13 +1027,13 @@ namespace CodeImp.DoomBuilder.VisualModes if(refreshSelection || selectedVisualSectors == null) { selectedVisualSectors = new List(); - foreach(KeyValuePair group in allsectors) + foreach(Sector s in General.Map.Map.Sectors.Where(x => x.VisualSector != null)) { - foreach(VisualGeometry vg in group.Value.AllGeometry) + foreach(VisualGeometry vg in s.VisualSector.AllGeometry) { if(vg.Selected) { - selectedVisualSectors.Add(group.Value); + selectedVisualSectors.Add(s.VisualSector); break; } } @@ -1056,9 +1055,9 @@ namespace CodeImp.DoomBuilder.VisualModes public List GetSelectedSurfaces() { List selectedSurfaces = new List(); - foreach(KeyValuePair group in allsectors) + foreach(Sector s in General.Map.Map.Sectors.Where(x => x.VisualSector != null)) { - foreach(VisualGeometry vg in group.Value.AllGeometry) + foreach(VisualGeometry vg in s.VisualSector.AllGeometry) { if(vg.Selected) selectedSurfaces.Add(vg); } @@ -1092,12 +1091,12 @@ namespace CodeImp.DoomBuilder.VisualModes /// /// Returns True when a VisualSector has been created for the specified Sector. /// - public bool VisualSectorExists(Sector s) { return allsectors.ContainsKey(s) && (allsectors[s] != null); } + public bool VisualSectorExists(Sector s) { return s.VisualSector != null; } /// /// Returns True when a VisualThing has been created for the specified Thing. /// - public bool VisualThingExists(Thing t) { return allthings.ContainsKey(t) && (allthings[t] != null); } + public bool VisualThingExists(Thing t) { return t.VisualThing != null; } /// /// This is called when the blockmap needs to be refilled, because it was invalidated. diff --git a/Source/Core/VisualModes/VisualSector.cs b/Source/Core/VisualModes/VisualSector.cs index 8a04708d..fdd3ac9d 100755 --- a/Source/Core/VisualModes/VisualSector.cs +++ b/Source/Core/VisualModes/VisualSector.cs @@ -36,7 +36,6 @@ namespace CodeImp.DoomBuilder.VisualModes // Geometry private readonly List fixedgeometry; private readonly List allgeometry; - private readonly Dictionary> sidedefgeometry; private VertexBuffer geobuffer; private bool updategeo; @@ -69,7 +68,6 @@ namespace CodeImp.DoomBuilder.VisualModes this.sector = s; allgeometry = new List(); fixedgeometry = new List(); - sidedefgeometry = new Dictionary>(); this.sector.UpdateFogColor(); //mxd // Register as resource @@ -168,9 +166,9 @@ namespace CodeImp.DoomBuilder.VisualModes allgeometry.Add(geo); if(geo.Sidedef != null) { - if(!sidedefgeometry.ContainsKey(geo.Sidedef)) - sidedefgeometry[geo.Sidedef] = new List(3); - sidedefgeometry[geo.Sidedef].Add(geo); + if(geo.Sidedef.VisualGeometry == null) + geo.Sidedef.VisualGeometry = new List(3); + geo.Sidedef.VisualGeometry.Add(geo); } else { @@ -185,14 +183,13 @@ namespace CodeImp.DoomBuilder.VisualModes { allgeometry.Clear(); fixedgeometry.Clear(); - sidedefgeometry.Clear(); updategeo = true; } // This gets the geometry list for the specified sidedef public List GetSidedefGeometry(Sidedef sd) { - if(sidedefgeometry.ContainsKey(sd)) return sidedefgeometry[sd]; + if(sd.VisualGeometry != null) return sd.VisualGeometry; return new List(); } diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index 01d1f065..cce60c8b 100755 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -31,6 +31,7 @@ using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.GZBuilder.Data; using CodeImp.DoomBuilder.Types; using CodeImp.DoomBuilder.Data; +using System.Linq; #endregion @@ -289,9 +290,9 @@ namespace CodeImp.DoomBuilder.BuilderModes General.Interface.DisplayStatus(StatusType.Action, actionresult.displaystatus); // Reset changed flags - foreach(KeyValuePair vs in allsectors) + foreach(Sector s in General.Map.Map.Sectors.Where(x => x.VisualSector != null)) { - BaseVisualSector bvs = (BaseVisualSector)vs.Value; + BaseVisualSector bvs = (BaseVisualSector)s.VisualSector; foreach(VisualFloor vf in bvs.ExtraFloors) vf.Changed = false; foreach(VisualCeiling vc in bvs.ExtraCeilings) vc.Changed = false; foreach(VisualFloor vf in bvs.ExtraBackFloors) vf.Changed = false; //mxd @@ -348,31 +349,25 @@ namespace CodeImp.DoomBuilder.BuilderModes { // Make list of selected objects selectedobjects = new List(); - foreach(KeyValuePair vs in allsectors) + foreach(Sector s in General.Map.Map.Sectors.Where(x => x.VisualSector != null)) { - if(vs.Value != null) + BaseVisualSector bvs = (BaseVisualSector)s.VisualSector; + if((bvs.Floor != null) && bvs.Floor.Selected) selectedobjects.Add(bvs.Floor); + if((bvs.Ceiling != null) && bvs.Ceiling.Selected) selectedobjects.Add(bvs.Ceiling); + foreach(Sidedef sd in s.Sidedefs) { - BaseVisualSector bvs = (BaseVisualSector)vs.Value; - if((bvs.Floor != null) && bvs.Floor.Selected) selectedobjects.Add(bvs.Floor); - if((bvs.Ceiling != null) && bvs.Ceiling.Selected) selectedobjects.Add(bvs.Ceiling); - foreach(Sidedef sd in vs.Key.Sidedefs) + List sidedefgeos = bvs.GetSidedefGeometry(sd); + foreach(VisualGeometry sdg in sidedefgeos) { - List sidedefgeos = bvs.GetSidedefGeometry(sd); - foreach(VisualGeometry sdg in sidedefgeos) - { - if(sdg.Selected) selectedobjects.Add((IVisualEventReceiver)sdg); - } + if(sdg.Selected) selectedobjects.Add((IVisualEventReceiver)sdg); } } } - foreach(KeyValuePair vt in allthings) + foreach(Thing t in General.Map.Map.Things.Where(x => x.VisualThing != null)) { - if(vt.Value != null) - { - BaseVisualThing bvt = (BaseVisualThing)vt.Value; - if(bvt.Selected) selectedobjects.Add(bvt); - } + BaseVisualThing bvt = (BaseVisualThing)t.VisualThing; + if(bvt.Selected) selectedobjects.Add(bvt); } //mxd @@ -395,7 +390,7 @@ namespace CodeImp.DoomBuilder.BuilderModes internal BaseVisualSector CreateBaseVisualSector(Sector s) { BaseVisualSector vs = new BaseVisualSector(this, s); - allsectors.Add(s, vs); + s.VisualSector = vs; return vs; } @@ -403,7 +398,7 @@ namespace CodeImp.DoomBuilder.BuilderModes protected override VisualSector CreateVisualSector(Sector s) { BaseVisualSector vs = new BaseVisualSector(this, s); - allsectors.Add(s, vs); //mxd + s.VisualSector = vs; //mxd return vs; } @@ -502,22 +497,16 @@ namespace CodeImp.DoomBuilder.BuilderModes // This updates the VisualSectors and VisualThings that have their Changed property set private void UpdateChangedObjects() { - foreach(KeyValuePair vs in allsectors) + foreach(Sector s in General.Map.Map.Sectors.Where(x => x.VisualSector != null)) { - if(vs.Value != null) - { - BaseVisualSector bvs = (BaseVisualSector)vs.Value; - if(bvs.Changed) bvs.Rebuild(); - } + BaseVisualSector bvs = (BaseVisualSector)s.VisualSector; + if(bvs.Changed) bvs.Rebuild(); } - foreach(KeyValuePair vt in allthings) + foreach(Thing t in General.Map.Map.Things.Where(x => x.VisualThing != null)) { - if(vt.Value != null) - { - BaseVisualThing bvt = (BaseVisualThing)vt.Value; - if(bvt.Changed) bvt.Rebuild(); - } + BaseVisualThing bvt = (BaseVisualThing)t.VisualThing; + if(bvt.Changed) bvt.Rebuild(); } //mxd @@ -1448,31 +1437,27 @@ namespace CodeImp.DoomBuilder.BuilderModes // No sectors or geometry changed. So we only have // to update things when they have changed. HashSet toremove = new HashSet(); //mxd - foreach(KeyValuePair vt in allthings) + foreach(Thing t in General.Map.Map.Things.Where(x => x.VisualThing != null && x.Marked)) { - if((vt.Value != null) && vt.Key.Marked) - { - if(vt.Key.IsDisposed) toremove.Add(vt.Key); //mxd. Disposed things will cause problems - else ((BaseVisualThing)vt.Value).Rebuild(); - } + if(t.IsDisposed) toremove.Add(t); //mxd. Disposed things will cause problems + else ((BaseVisualThing)t.VisualThing).Rebuild(); } //mxd. Remove disposed things foreach(Thing t in toremove) { - if(allthings[t] != null) allthings[t].Dispose(); - allthings.Remove(t); + if(t.VisualThing != null) { t.VisualThing.Dispose(); t.VisualThing = null; } } } else { // Things depend on the sector they are in and because we can't // easily determine which ones changed, we dispose all things - foreach(KeyValuePair vt in allthings) - if(vt.Value != null) vt.Value.Dispose(); - - // Apply new lists - allthings = new Dictionary(allthings.Count); + foreach(Thing t in General.Map.Map.Things.Where(x => x.VisualThing != null)) + { + t.VisualThing.Dispose(); + t.VisualThing = null; + } } // Clear visibility collections @@ -1584,12 +1569,10 @@ namespace CodeImp.DoomBuilder.BuilderModes //mxd private void Interface_OnSectorEditFormValuesChanged(object sender, EventArgs e) { - if(allsectors == null) return; - // Reset changed flags - foreach(KeyValuePair vs in allsectors) + foreach(Sector s in General.Map.Map.Sectors.Where(x => x.VisualSector != null)) { - BaseVisualSector bvs = (BaseVisualSector)vs.Value; + BaseVisualSector bvs = (BaseVisualSector)s.VisualSector; foreach(VisualFloor vf in bvs.ExtraFloors) vf.Changed = false; foreach(VisualCeiling vc in bvs.ExtraCeilings) vc.Changed = false; foreach(VisualFloor vf in bvs.ExtraBackFloors) vf.Changed = false; @@ -2072,41 +2055,35 @@ namespace CodeImp.DoomBuilder.BuilderModes }); // - foreach (KeyValuePair vs in allsectors) + foreach (Sector s in General.Map.Map.Sectors.Where(x => x.VisualSector != null)) { - if (vs.Value != null) + BaseVisualSector bvs = (BaseVisualSector)s.VisualSector; + if (clearsectors) { - BaseVisualSector bvs = (BaseVisualSector)vs.Value; - if (clearsectors) - { - if (bvs.Floor != null) bvs.Floor.Selected = false; - if (bvs.Ceiling != null) bvs.Ceiling.Selected = false; - foreach (VisualFloor vf in bvs.ExtraFloors) vf.Selected = false; - foreach (VisualCeiling vc in bvs.ExtraCeilings) vc.Selected = false; - foreach (VisualFloor vf in bvs.ExtraBackFloors) vf.Selected = false; //mxd - foreach (VisualCeiling vc in bvs.ExtraBackCeilings) vc.Selected = false; //mxd - } + if (bvs.Floor != null) bvs.Floor.Selected = false; + if (bvs.Ceiling != null) bvs.Ceiling.Selected = false; + foreach (VisualFloor vf in bvs.ExtraFloors) vf.Selected = false; + foreach (VisualCeiling vc in bvs.ExtraCeilings) vc.Selected = false; + foreach (VisualFloor vf in bvs.ExtraBackFloors) vf.Selected = false; //mxd + foreach (VisualCeiling vc in bvs.ExtraBackCeilings) vc.Selected = false; //mxd + } - if (clearsidedefs) + if (clearsidedefs) + { + foreach (Sidedef sd in s.Sidedefs) { - foreach (Sidedef sd in vs.Key.Sidedefs) - { - //mxd. VisualSidedefParts can contain references to visual geometry, which is not present in VisualSector.sidedefgeometry - bvs.GetSidedefParts(sd).DeselectAllParts(); - } + //mxd. VisualSidedefParts can contain references to visual geometry, which is not present in VisualSector.sidedefgeometry + bvs.GetSidedefParts(sd).DeselectAllParts(); } } } if (clearthings) { - foreach (KeyValuePair vt in allthings) + foreach (Thing t in General.Map.Map.Things.Where(x => x.VisualThing != null)) { - if (vt.Value != null) - { - BaseVisualThing bvt = (BaseVisualThing)vt.Value; - bvt.Selected = false; - } + BaseVisualThing bvt = (BaseVisualThing)t.VisualThing; + bvt.Selected = false; } } From 994eda485288c4850fb6267144a1b16495cb6587 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 26 Dec 2019 00:37:47 +0100 Subject: [PATCH 2/7] Fix shutdown crash caused by C# finalizers deleting texture objects after renderdevice already left the building --- Source/Native/OpenGL/GLIndexBuffer.cpp | 2 ++ Source/Native/OpenGL/GLIndexBuffer.h | 2 ++ Source/Native/OpenGL/GLRenderDevice.cpp | 16 +++++++++++++--- Source/Native/OpenGL/GLRenderDevice.h | 4 ++++ Source/Native/OpenGL/GLTexture.cpp | 6 ++++-- Source/Native/OpenGL/GLTexture.h | 2 ++ 6 files changed, 27 insertions(+), 5 deletions(-) diff --git a/Source/Native/OpenGL/GLIndexBuffer.cpp b/Source/Native/OpenGL/GLIndexBuffer.cpp index cbc123c0..8adbcc51 100644 --- a/Source/Native/OpenGL/GLIndexBuffer.cpp +++ b/Source/Native/OpenGL/GLIndexBuffer.cpp @@ -27,6 +27,8 @@ GLIndexBuffer::~GLIndexBuffer() { if (Device && mBuffer != 0) { + Device->mIndexBuffers.erase(ItBuffer); + Device = nullptr; glDeleteBuffers(1, &mBuffer); mBuffer = 0; } diff --git a/Source/Native/OpenGL/GLIndexBuffer.h b/Source/Native/OpenGL/GLIndexBuffer.h index 4d20f47b..64ea71c8 100644 --- a/Source/Native/OpenGL/GLIndexBuffer.h +++ b/Source/Native/OpenGL/GLIndexBuffer.h @@ -22,6 +22,7 @@ #pragma once #include "../Backend.h" +#include class GLRenderDevice; @@ -33,6 +34,7 @@ public: GLuint GetBuffer(); GLRenderDevice* Device = nullptr; + std::list::iterator ItBuffer; private: GLuint mBuffer = 0; diff --git a/Source/Native/OpenGL/GLRenderDevice.cpp b/Source/Native/OpenGL/GLRenderDevice.cpp index f34f266f..9c6d988a 100644 --- a/Source/Native/OpenGL/GLRenderDevice.cpp +++ b/Source/Native/OpenGL/GLRenderDevice.cpp @@ -82,6 +82,11 @@ GLRenderDevice::~GLRenderDevice() { Context->MakeCurrent(); + ProcessDeleteList(); + for (GLTexture* tex : mTextures) mDeleteList.Textures.push_back(tex); + for (GLIndexBuffer* buffer : mIndexBuffers) mDeleteList.IndexBuffers.push_back(buffer); + for (GLVertexBuffer* buffer : mSharedVertexBuffers[0]->VertexBuffers) mDeleteList.VertexBuffers.push_back(buffer); + for (GLVertexBuffer* buffer : mSharedVertexBuffers[1]->VertexBuffers) mDeleteList.VertexBuffers.push_back(buffer); ProcessDeleteList(); glDeleteBuffers(1, &mStreamVertexBuffer); @@ -89,9 +94,6 @@ GLRenderDevice::~GLRenderDevice() for (auto& sharedbuf : mSharedVertexBuffers) { - for (GLVertexBuffer* buf : sharedbuf->VertexBuffers) - buf->Device = nullptr; - GLuint handle = sharedbuf->GetBuffer(); glDeleteBuffers(1, &handle); handle = sharedbuf->GetVAO(); @@ -107,6 +109,7 @@ GLRenderDevice::~GLRenderDevice() } } + mShaderManager->ReleaseResources(); Context->ClearCurrent(); } @@ -584,6 +587,11 @@ bool GLRenderDevice::SetIndexBufferData(IndexBuffer* ibuffer, void* data, int64_ { CheckContext(); GLIndexBuffer* buffer = static_cast(ibuffer); + if (buffer->Device == nullptr) + { + buffer->ItBuffer = mIndexBuffers.insert(mIndexBuffers.end(), buffer); + buffer->Device = this; + } GLint oldbinding = 0; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &oldbinding); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->GetBuffer()); @@ -960,9 +968,11 @@ void GLRenderDevice::DeleteObject(GLTexture* texture) void GLRenderDevice::ProcessDeleteList() { std::unique_lock lock(GLRenderDevice::GetMutex()); + for (auto buffer : mDeleteList.IndexBuffers) delete buffer; for (auto buffer : mDeleteList.VertexBuffers) delete buffer; for (auto texture : mDeleteList.Textures) delete texture; + mDeleteList.IndexBuffers.clear(); mDeleteList.VertexBuffers.clear(); mDeleteList.Textures.clear(); diff --git a/Source/Native/OpenGL/GLRenderDevice.h b/Source/Native/OpenGL/GLRenderDevice.h index 7a9919f9..6d22a90b 100644 --- a/Source/Native/OpenGL/GLRenderDevice.h +++ b/Source/Native/OpenGL/GLRenderDevice.h @@ -23,6 +23,7 @@ #include "../Backend.h" #include "OpenGLContext.h" +#include class GLSharedVertexBuffer; class GLShader; @@ -150,6 +151,9 @@ public: std::unique_ptr mSharedVertexBuffers[2]; + std::list mTextures; + std::list mIndexBuffers; + std::unique_ptr mShaderManager; ShaderName mShaderName = {}; diff --git a/Source/Native/OpenGL/GLTexture.cpp b/Source/Native/OpenGL/GLTexture.cpp index f2dbaf7e..f41d86a0 100644 --- a/Source/Native/OpenGL/GLTexture.cpp +++ b/Source/Native/OpenGL/GLTexture.cpp @@ -120,6 +120,7 @@ void GLTexture::Invalidate() mFramebuffer = 0; mTexture = 0; mPBO = 0; + if (Device) Device->mTextures.erase(ItTexture); Device = nullptr; } @@ -128,6 +129,7 @@ GLuint GLTexture::GetTexture(GLRenderDevice* device) if (mTexture == 0) { Device = device; + ItTexture = Device->mTextures.insert(Device->mTextures.end(), this); GLint oldActiveTex = GL_TEXTURE0; glGetIntegerv(GL_ACTIVE_TEXTURE, &oldActiveTex); @@ -174,7 +176,7 @@ GLuint GLTexture::GetFramebuffer(GLRenderDevice* device, bool usedepthbuffer) { if (mFramebuffer == 0) { - GLuint texture = GetTexture(Device); + GLuint texture = GetTexture(device); glGenFramebuffers(1, &mFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); @@ -197,7 +199,7 @@ GLuint GLTexture::GetFramebuffer(GLRenderDevice* device, bool usedepthbuffer) if (mFramebuffer == 0) { - GLuint texture = GetTexture(Device); + GLuint texture = GetTexture(device); glGenFramebuffers(1, &mFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); diff --git a/Source/Native/OpenGL/GLTexture.h b/Source/Native/OpenGL/GLTexture.h index 3fbd7593..6c47e3a5 100644 --- a/Source/Native/OpenGL/GLTexture.h +++ b/Source/Native/OpenGL/GLTexture.h @@ -22,6 +22,7 @@ #pragma once #include "../Backend.h" +#include class GLRenderDevice; @@ -49,6 +50,7 @@ public: GLuint GetPBO(GLRenderDevice* device); GLRenderDevice* Device = nullptr; + std::list::iterator ItTexture; private: int mWidth = 0; From 9d5f8ec7c1fd9823dd726f747a1ce91a6d2539ac Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 26 Dec 2019 00:39:15 +0100 Subject: [PATCH 3/7] Rewrite VisualBlockMap to use a quad tree --- Source/Core/Map/MapSet.cs | 9 +- Source/Core/Map/Thing.cs | 14 +- Source/Core/VisualModes/VisualBlockEntry.cs | 30 +- Source/Core/VisualModes/VisualBlockMap.cs | 709 +++++++----------- .../BuilderModes/General/BuilderModesTools.cs | 13 +- .../VisualModes/BaseVisualMode.cs | 29 +- 6 files changed, 304 insertions(+), 500 deletions(-) diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs index 411449e8..9dd2bfe2 100755 --- a/Source/Core/Map/MapSet.cs +++ b/Source/Core/Map/MapSet.cs @@ -3952,14 +3952,7 @@ namespace CodeImp.DoomBuilder.Map /// This returns a sector if given coordinates are inside one. public Sector GetSectorByCoordinates(Vector2D pos, VisualBlockMap blockmap) { - // Find nearest sectors using the blockmap - List possiblesectors = blockmap.GetBlock(blockmap.GetBlockCoordinates(pos)).Sectors; - foreach(Sector s in possiblesectors) - { - if(s.Intersect(pos)) return s; - } - - return null; + return blockmap.GetSectorAt(pos); } //mxd diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs index 08a08124..328c10dc 100755 --- a/Source/Core/Map/Thing.cs +++ b/Source/Core/Map/Thing.cs @@ -277,19 +277,7 @@ namespace CodeImp.DoomBuilder.Map // This determines which sector the thing is in and links it public void DetermineSector(VisualBlockMap blockmap) { - // Find nearest sectors using the blockmap - List possiblesectors = blockmap.GetBlock(blockmap.GetBlockCoordinates(pos)).Sectors; - - // Check in which sector we are - sector = null; - foreach(Sector s in possiblesectors) - { - if(s.Intersect(pos)) - { - sector = s; - break; - } - } + sector = blockmap.GetSectorAt(pos); } // This translates the flags into UDMF fields diff --git a/Source/Core/VisualModes/VisualBlockEntry.cs b/Source/Core/VisualModes/VisualBlockEntry.cs index ce3bca25..05d12f40 100755 --- a/Source/Core/VisualModes/VisualBlockEntry.cs +++ b/Source/Core/VisualModes/VisualBlockEntry.cs @@ -25,33 +25,15 @@ namespace CodeImp.DoomBuilder.VisualModes { public sealed class VisualBlockEntry { - #region ================== Variables + public List Lines { get; set; } + public List Things { get; set; } + public List Sectors { get; set; } - // Members - private List lines; - private List things; - private List sectors; - - #endregion - - #region ================== Properties - - public List Lines { get { return lines; } } - public List Things { get { return things; } } - public List Sectors { get { return sectors; } } - - #endregion - - #region ================== Constructor - - // Constructor for empty block internal VisualBlockEntry() { - lines = new List(2); - things = new List(2); - sectors = new List(2); + Lines = new List(2); + Things = new List(2); + Sectors = new List(2); } - - #endregion } } diff --git a/Source/Core/VisualModes/VisualBlockMap.cs b/Source/Core/VisualModes/VisualBlockMap.cs index cc5daa04..393349c0 100755 --- a/Source/Core/VisualModes/VisualBlockMap.cs +++ b/Source/Core/VisualModes/VisualBlockMap.cs @@ -28,453 +28,296 @@ using System.Linq; namespace CodeImp.DoomBuilder.VisualModes { - public sealed class VisualBlockMap - { - #region ================== Constants - - public const int BLOCK_SIZE_SHIFT = 7; - public const int BLOCK_SIZE = 1 << BLOCK_SIZE_SHIFT; - public const float BLOCK_RADIUS = BLOCK_SIZE * Angle2D.SQRT2; - - #endregion - - #region ================== Variables - - // Blocks -#if DICTIONARY_BLOCKMAP - private Dictionary blockmap; -#else - private VisualBlockEntry[,] blockmap; -#endif - - // State - private bool isdisposed; - - #endregion - - #region ================== Properties - - public bool IsDisposed { get { return isdisposed; } } - - #endregion - - #region ================== Constructor / Disposer - - // Constructor - internal VisualBlockMap() - { -#if DICTIONARY_BLOCKMAP - // Initialize - blockmap = new Dictionary(); -#else - blockmap = new VisualBlockEntry[(1 << 16) / BLOCK_SIZE, (1 << 16) / BLOCK_SIZE]; // 1 megabyte per blockmap -#endif - } - - // Disposer - internal void Dispose() - { - // Not already disposed? - if(!isdisposed) - { - // Clean up - blockmap = null; - - // Done - isdisposed = true; - } - } - - #endregion - - #region ================== Methods - - // This returns the block coordinates - public Point GetBlockCoordinates(Vector2D v) - { - return new Point((int)v.x >> BLOCK_SIZE_SHIFT, - (int)v.y >> BLOCK_SIZE_SHIFT); - } - - // This returns the block center in world coordinates - public Vector2D GetBlockCenter(Point p) - { - return new Vector2D((p.X << BLOCK_SIZE_SHIFT) + (BLOCK_SIZE >> 1), - (p.Y << BLOCK_SIZE_SHIFT) + (BLOCK_SIZE >> 1)); - } - - // This returns the key for a block at the given coordinates - // TODO: Could we just use the Point struct as key? - private static ulong GetBlockKey(Point p) - { - return unchecked( ((ulong)(uint)p.X << 32) + (uint)p.Y ); - } - - // This returns the block with the given coordinates - // Creates the block if it doesn't exist yet - public VisualBlockEntry GetBlock(Point p) - { -#if DICTIONARY_BLOCKMAP - ulong k = GetBlockKey(p); - VisualBlockEntry vbe; - - if (blockmap.TryGetValue(k, out vbe)) - return vbe; - else - return (blockmap[k] = new VisualBlockEntry()); -#else - int blockX = p.X % blockmap.GetLength(0); - int blockY = p.Y % blockmap.GetLength(1); - if (blockX < 0) blockX += blockmap.GetLength(0); - if (blockY < 0) blockY += blockmap.GetLength(1); - if (blockmap[blockX, blockY] == null) - blockmap[blockX, blockY] = new VisualBlockEntry(); - return blockmap[blockX, blockY]; -#endif - } - - // This clears the blockmap - public void Clear() - { -#if DICTIONARY_BLOCKMAP - blockmap = new Dictionary(); -#else - blockmap = new VisualBlockEntry[(1 << 16) / BLOCK_SIZE, (1 << 16) / BLOCK_SIZE]; // ok this a little bit expensive.. -#endif - } - - // This returns a range of blocks in a square - public List GetSquareRange(RectangleF rect) - { - // Calculate block coordinates - Point lt = GetBlockCoordinates(new Vector2D(rect.Left, rect.Top)); - Point rb = GetBlockCoordinates(new Vector2D(rect.Right, rect.Bottom)); - - // Go through the range to make a list - int entriescount = (rb.X - lt.X) * (rb.Y - lt.Y); - List entries = new List(entriescount); - for(int x = lt.X; x <= rb.X; x++) - { - for(int y = lt.Y; y <= rb.Y; y++) - { - entries.Add(GetBlock(new Point(x, y))); - } - } - - // Return list - return entries; - } - - // This returns a range of blocks in a frustum - public List GetFrustumRange(ProjectedFrustum2D frustum) - { - // Make square range from frustum circle - // This will be the range in which we will test blocks - Point lb = GetBlockCoordinates(frustum.Center - frustum.Radius); - Point rt = GetBlockCoordinates(frustum.Center + frustum.Radius); - - Vector2D maplb = new Vector2D(); - Vector2D maprt = new Vector2D(); - - Vertex firstvertex = General.Map.Map.Vertices.OfType().FirstOrDefault(); - - if (firstvertex != null) - maplb = maprt = firstvertex.Position; - - // Get maximum dimensions of the map. First vertices... - foreach (Vertex v in General.Map.Map.Vertices) - { - if (v.Position.x < maplb.x) maplb.x = v.Position.x; - if (v.Position.y < maplb.y) maplb.y = v.Position.y; - if (v.Position.x > maprt.x) maprt.x = v.Position.x; - if (v.Position.y > maprt.y) maprt.y = v.Position.y; - } - - // ... then things - foreach (Thing t in General.Map.Map.Things) - { - if (t.Position.x < maplb.x) maplb.x = t.Position.x; - if (t.Position.y < maplb.y) maplb.y = t.Position.y; - if (t.Position.x > maprt.x) maprt.x = t.Position.x; - if (t.Position.y > maprt.y) maprt.y = t.Position.y; - } - - Point mlb = GetBlockCoordinates(maplb); - Point mrt = GetBlockCoordinates(maprt); - - // Make sure that the checked region does not exceed the dimensions where something is to be displayed - if (lb.X < mlb.X) lb.X = mlb.X; - if (lb.Y < mlb.Y) lb.Y = mlb.Y; - if (rt.X > mrt.X) rt.X = mrt.X; - if (rt.Y > mrt.Y) rt.Y = mrt.Y; - - // Constants we need - float blockfrustumdistance2 = (frustum.Radius * frustum.Radius) + (BLOCK_RADIUS * BLOCK_RADIUS); - - // Go through the range to make a list - int entriescount = (rt.X - lb.X) * (rt.Y - lb.Y); - List entries = new List(entriescount); - - for (int x = lb.X; x <= rt.X; x++) - { - for(int y = lb.Y; y <= rt.Y; y++) - { - // First check if the block circle is intersecting the frustum circle - Point block = new Point(x, y); - Vector2D blockcenter = GetBlockCenter(block); - if(Vector2D.DistanceSq(frustum.Center, blockcenter) < blockfrustumdistance2) - { - // Add the block if the block circle is inside the frustum - if (frustum.IntersectCircle(blockcenter, BLOCK_RADIUS)) entries.Add(GetBlock(block)); - } - } - } - - // Return list - return entries; - } - + public sealed class VisualBlockMap + { // This returns all blocks along the given line public List GetLineBlocks(Vector2D v1, Vector2D v2) - { - // Estimate number of blocks we will go through and create list - int entriescount = (int)(Vector2D.ManhattanDistance(v1, v2) * 2.0f) / BLOCK_SIZE; - List entries = new List(entriescount); + { + int x0 = (int)Math.Floor(Math.Min(v1.x, v2.x)); + int y0 = (int)Math.Floor(Math.Min(v1.y, v2.y)); + int x1 = (int)Math.Floor(Math.Max(v1.x, v2.x)) + 1; + int y1 = (int)Math.Floor(Math.Max(v1.y, v2.y)) + 1; - // Find start and end block - Point pos = GetBlockCoordinates(v1); - Point end = GetBlockCoordinates(v2); + var result = new List(); + root.GetBlocks(new Rectangle(x0, y0, x1 - x0, y1 - y0), ref result); + return result; + } - // Add this block - entries.Add(GetBlock(pos)); + public List GetBlocks(RectangleF box) + { + var result = new List(); + root.GetBlocks(ToRectangle(box), ref result); + return result; + } - // Moving outside the block? - if(pos != end) - { - // Calculate current block edges - float cl = pos.X * BLOCK_SIZE; - float cr = (pos.X + 1) * BLOCK_SIZE; - float ct = pos.Y * BLOCK_SIZE; - float cb = (pos.Y + 1) * BLOCK_SIZE; + public List GetBlocks(Vector2D pos) + { + var result = new List(); + root.GetBlocks(new Point((int)Math.Floor(pos.x), (int)Math.Floor(pos.y)), ref result); + return result; + } - // Line directions - int dirx = Math.Sign(v2.x - v1.x); - int diry = Math.Sign(v2.y - v1.y); + // This returns a range of blocks in a frustum + public List GetFrustumRange(ProjectedFrustum2D frustum2D) + { + var frustum = new Frustum(); + frustum.planes = new Plane[4] + { + new Plane(frustum2D.Lines[0]), + new Plane(frustum2D.Lines[1]), + new Plane(frustum2D.Lines[2]), + new Plane(frustum2D.Lines[3]) + }; - // Calculate offset and delta movement over x - float posx, deltax; - if(dirx >= 0) - { - posx = (cr - v1.x) / (v2.x - v1.x); - deltax = BLOCK_SIZE / (v2.x - v1.x); - } - else - { - // Calculate offset and delta movement over x - posx = (v1.x - cl) / (v1.x - v2.x); - deltax = BLOCK_SIZE / (v1.x - v2.x); - } + var result = new List(); + root.GetBlocks(frustum, ref result); + return result; + } - // Calculate offset and delta movement over y - float posy, deltay; - if(diry >= 0) - { - posy = (cb - v1.y) / (v2.y - v1.y); - deltay = BLOCK_SIZE / (v2.y - v1.y); - } - else - { - posy = (v1.y - ct) / (v1.y - v2.y); - deltay = BLOCK_SIZE / (v1.y - v2.y); - } + public Sector GetSectorAt(Vector2D pos) + { + foreach (VisualBlockEntry e in GetBlocks(pos)) + { + foreach (Sector s in e.Sectors) + { + if (s.Intersect(pos)) + { + return s; + } + } + } + return null; + } - // Continue while not reached the end - while(pos != end) - { - // Check in which direction to move - if(posx < posy) - { - // Move horizontally - posx += deltax; - if(pos.X != end.X) pos.X += dirx; - } - else - { - // Move vertically - posy += deltay; - if(pos.Y != end.Y) pos.Y += diry; - } + public void Clear() + { + root = new Node(new Rectangle(MapMinX, MapMinY, MapMaxX - MapMinX, MapMaxY - MapMinY)); + } - // Add lines to this block - entries.Add(GetBlock(pos)); - } - } - - // Return list - return entries; - } - - // This puts a thing in the blockmap - public void AddThingsSet(ICollection things) - { - foreach(Thing t in things) AddThing(t); - } - - // This puts a thing in the blockmap - public void AddThing(Thing t) - { - //mxd - Point p1 = GetBlockCoordinates(new Vector2D(t.Position.x - t.RenderSize, t.Position.y - t.RenderSize)); - Point p2 = GetBlockCoordinates(new Vector2D(t.Position.x + t.RenderSize, t.Position.y + t.RenderSize)); - for(int x = p1.X; x <= p2.X; x++) - { - for(int y = p1.Y; y <= p2.Y; y++) - { - VisualBlockEntry block = GetBlock(new Point(x, y)); - block.Things.Add(t); - } - } - } - - // This puts a secotr in the blockmap public void AddSectorsSet(ICollection sectors) { - foreach(Sector s in sectors) AddSector(s); + foreach (Sector s in sectors) AddSector(s); } - // This puts a sector in the blockmap - public void AddSector(Sector s) + public void AddLinedefsSet(ICollection lines) + { + foreach (Linedef line in lines) AddLinedef(line); + } + + public void AddThingsSet(ICollection things) + { + foreach (Thing t in things) AddThing(t); + } + + public void AddSector(Sector sector) + { + root.GetEntry(ToRectangle(sector.BBox)).Sectors.Add(sector); + } + + public void AddLinedef(Linedef line) + { + int x0 = (int)Math.Floor(Math.Min(line.Start.Position.x, line.End.Position.x)); + int y0 = (int)Math.Floor(Math.Min(line.Start.Position.y, line.End.Position.y)); + int x1 = (int)Math.Floor(Math.Max(line.Start.Position.x, line.End.Position.x)) + 1; + int y1 = (int)Math.Floor(Math.Max(line.Start.Position.y, line.End.Position.y)) + 1; + root.GetEntry(new Rectangle(x0, y0, x1 - x0, y1 - y0)).Lines.Add(line); + } + + public void AddThing(Thing thing) + { + int x0 = (int)Math.Floor(thing.Position.x - thing.Size); + int x1 = (int)Math.Floor(thing.Position.x + thing.Size) + 1; + int y0 = (int)Math.Floor(thing.Position.y - thing.Size); + int y1 = (int)Math.Floor(thing.Position.y + thing.Size) + 1; + root.GetEntry(new Rectangle(x0, y0, x1 - x0, y1 - y0)).Things.Add(thing); + } + + internal void Dispose() { - Point p1 = GetBlockCoordinates(new Vector2D(s.BBox.Left, s.BBox.Top)); - Point p2 = GetBlockCoordinates(new Vector2D(s.BBox.Right, s.BBox.Bottom)); - for(int x = p1.X; x <= p2.X; x++) - { - for(int y = p1.Y; y <= p2.Y; y++) - { - VisualBlockEntry block = GetBlock(new Point(x, y)); - block.Sectors.Add(s); - } - } + Clear(); } - - // This puts a whole set of linedefs in the blocks they cross - public void AddLinedefsSet(ICollection lines) - { - foreach(Linedef l in lines) AddLinedef(l); - } - - // This puts a single linedef in all blocks it crosses - public void AddLinedef(Linedef line) - { - // Get coordinates - Vector2D v1 = line.Start.Position; - Vector2D v2 = line.End.Position; - - // Find start and end block - Point pos = GetBlockCoordinates(v1); - Point end = GetBlockCoordinates(v2); - - // Horizontal straight line? - if(pos.Y == end.Y) - { - // Simple loop - int dirx = Math.Sign(v2.x - v1.x); - for(int x = pos.X; x != end.X; x += dirx) - { - GetBlock(new Point(x, pos.Y)).Lines.Add(line); - } - GetBlock(end).Lines.Add(line); - } - // Vertical straight line? - else if(pos.X == end.X) - { - // Simple loop - int diry = Math.Sign(v2.y - v1.y); - for(int y = pos.Y; y != end.Y; y += diry) - { - GetBlock(new Point(pos.X, y)).Lines.Add(line); - } - GetBlock(end).Lines.Add(line); - } - else - { - // Add lines to this block - GetBlock(pos).Lines.Add(line); - - // Moving outside the block? - if(pos != end) - { - // Calculate current block edges - float cl = pos.X * BLOCK_SIZE; - float cr = (pos.X + 1) * BLOCK_SIZE; - float ct = pos.Y * BLOCK_SIZE; - float cb = (pos.Y + 1) * BLOCK_SIZE; - - // Line directions - int dirx = Math.Sign(v2.x - v1.x); - int diry = Math.Sign(v2.y - v1.y); - - // Calculate offset and delta movement over x - float posx, deltax; - if(dirx == 0) - { - posx = float.MaxValue; - deltax = float.MaxValue; - } - else if(dirx > 0) - { - posx = (cr - v1.x) / (v2.x - v1.x); - deltax = BLOCK_SIZE / (v2.x - v1.x); - } - else - { - // Calculate offset and delta movement over x - posx = (v1.x - cl) / (v1.x - v2.x); - deltax = BLOCK_SIZE / (v1.x - v2.x); - } - - // Calculate offset and delta movement over y - float posy, deltay; - if(diry == 0) - { - posy = float.MaxValue; - deltay = float.MaxValue; - } - else if(diry > 0) - { - posy = (cb - v1.y) / (v2.y - v1.y); - deltay = BLOCK_SIZE / (v2.y - v1.y); - } - else - { - posy = (v1.y - ct) / (v1.y - v2.y); - deltay = BLOCK_SIZE / (v1.y - v2.y); - } - - // Continue while not reached the end - while(pos != end) - { - // Check in which direction to move - if(posx < posy) - { - // Move horizontally - posx += deltax; - if(pos.X != end.X) pos.X += dirx; - } - else - { - // Move vertically - posy += deltay; - if(pos.Y != end.Y) pos.Y += diry; - } - - // Add lines to this block - GetBlock(pos).Lines.Add(line); - } - } - } - } - -#endregion - } + + static Rectangle ToRectangle(RectangleF bbox) + { + int x0 = (int)Math.Floor(bbox.Left); + int y0 = (int)Math.Floor(bbox.Top); + int x1 = (int)Math.Floor(bbox.Right) + 1; + int y1 = (int)Math.Floor(bbox.Bottom) + 1; + return new Rectangle(x0, y0, x1 - x0, y1 - y0); + } + + const int MapMinX = -32768; + const int MapMinY = -32768; + const int MapMaxX = 32768; + const int MapMaxY = 32768; + const int MaxLevels = 8; + + Node root = new Node(new Rectangle(MapMinX, MapMinY, MapMaxX - MapMinX, MapMaxY - MapMinY)); + + struct Plane + { + public Plane(Line2D line) + { + Vector2D dir = line.v2 - line.v1; + A = -dir.y; + B = dir.x; + D = -(line.v1.x * A + line.v1.y * B); + } + + public float A, B, D; + } + + class Frustum + { + public Plane[] planes; + } + + class Node + { + enum Visibility { Inside, Intersecting, Outside }; + + public Node(Rectangle bbox) + { + this.bbox = bbox; + extents = new Vector2D(bbox.Width * 0.5f, bbox.Height * 0.5f); + center = new Vector2D(bbox.X + extents.x, bbox.Y + extents.y); + } + + public void GetBlocks(Frustum frustum, ref List list) + { + Visibility vis = TestVisibility(frustum); + if (vis == Visibility.Inside) + { + GetAllBlocks(ref list); + } + else if (vis == Visibility.Intersecting) + { + if (visualBlock != null) + list.Add(visualBlock); + + if (topLeft != null) + { + topLeft.GetBlocks(frustum, ref list); + topRight.GetBlocks(frustum, ref list); + bottomLeft.GetBlocks(frustum, ref list); + bottomRight.GetBlocks(frustum, ref list); + } + } + } + + void GetAllBlocks(ref List list) + { + if (visualBlock != null) + list.Add(visualBlock); + + if (topLeft != null) + { + topLeft.GetAllBlocks(ref list); + topRight.GetAllBlocks(ref list); + bottomLeft.GetAllBlocks(ref list); + bottomRight.GetAllBlocks(ref list); + } + } + + Visibility TestVisibility(Frustum frustum) + { + Visibility result = Visibility.Inside; + for (int i = 0; i < 4; i++) + { + Visibility vis = TestFrustumLineVisibility(frustum.planes[i]); + if (vis == Visibility.Outside) + return Visibility.Outside; + else if (vis == Visibility.Intersecting) + result = Visibility.Intersecting; + } + return result; + } + + Visibility TestFrustumLineVisibility(Plane plane) + { + float e = extents.x * Math.Abs(plane.A) + extents.y * Math.Abs(plane.B); + float s = center.x * plane.A + center.y * plane.B + plane.D; + if (s - e > 0.0) + return Visibility.Inside; + else if (s + e < 0) + return Visibility.Outside; + else + return Visibility.Intersecting; + } + + public void GetBlocks(Point pos, ref List list) + { + if (visualBlock != null) + list.Add(visualBlock); + + if (topLeft != null) + { + if (topLeft.bbox.Contains(pos)) topLeft.GetBlocks(pos, ref list); + if (topRight.bbox.Contains(pos)) topRight.GetBlocks(pos, ref list); + if (bottomLeft.bbox.Contains(pos)) bottomLeft.GetBlocks(pos, ref list); + if (bottomRight.bbox.Contains(pos)) bottomRight.GetBlocks(pos, ref list); + } + } + + public void GetBlocks(Rectangle box, ref List list) + { + if (visualBlock != null) + list.Add(visualBlock); + + if (topLeft != null) + { + if (topLeft.bbox.IntersectsWith(box)) topLeft.GetBlocks(box, ref list); + if (topRight.bbox.IntersectsWith(box)) topRight.GetBlocks(box, ref list); + if (bottomLeft.bbox.IntersectsWith(box)) bottomLeft.GetBlocks(box, ref list); + if (bottomRight.bbox.IntersectsWith(box)) bottomRight.GetBlocks(box, ref list); + } + } + + public VisualBlockEntry GetEntry(Rectangle box, int level = 0) + { + if (level == MaxLevels) + { + if (visualBlock == null) + visualBlock = new VisualBlockEntry(); + return visualBlock; + } + + if (topLeft == null) + CreateChildren(); + + if (topLeft.bbox.Contains(box)) return topLeft.GetEntry(box, level + 1); + if (topRight.bbox.Contains(box)) return topRight.GetEntry(box, level + 1); + if (bottomLeft.bbox.Contains(box)) return bottomLeft.GetEntry(box, level + 1); + if (bottomRight.bbox.Contains(box)) return bottomRight.GetEntry(box, level + 1); + + if (visualBlock == null) + visualBlock = new VisualBlockEntry(); + return visualBlock; + } + + void CreateChildren() + { + int x0 = bbox.X; + int x1 = bbox.X + bbox.Width / 2; + int x2 = bbox.X + bbox.Width; + int y0 = bbox.Y; + int y1 = bbox.Y + bbox.Height / 2; + int y2 = bbox.Y + bbox.Height; + topLeft = new Node(new Rectangle(x0, y0, x1 - x0, y1 - y0)); + topRight = new Node(new Rectangle(x1, y0, x2 - x1, y1 - y0)); + bottomLeft = new Node(new Rectangle(x0, y1, x1 - x0, y2 - y1)); + bottomRight = new Node(new Rectangle(x1, y1, x2 - x1, y2 - y1)); + } + + Rectangle bbox; + Vector2D extents; + Vector2D center; + + Node topLeft; + Node topRight; + Node bottomLeft; + Node bottomRight; + VisualBlockEntry visualBlock; + } + } } diff --git a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs index 449805d2..e3120a22 100755 --- a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs +++ b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs @@ -600,15 +600,10 @@ namespace CodeImp.DoomBuilder.BuilderModes // Get nearby things List neighbours = new List(); RectangleF bbox = new RectangleF(thing.Position.x - thing.Size, thing.Position.y - thing.Size, thing.Size * 2, thing.Size * 2); - Point p1 = mode.BlockMap.GetBlockCoordinates(new Vector2D(bbox.Left, bbox.Top)); - Point p2 = mode.BlockMap.GetBlockCoordinates(new Vector2D(bbox.Right, bbox.Bottom)); - for(int x = p1.X; x <= p2.X; x++) - { - for(int y = p1.Y; y <= p2.Y; y++) - { - neighbours.AddRange(mode.BlockMap.GetBlock(new Point(x, y)).Things); - } - } + foreach (var block in mode.BlockMap.GetBlocks(bbox)) + { + neighbours.AddRange(block.Things); + } // Collect things intersecting with target thing List intersectingthings = new List(); diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index cce60c8b..58830f48 100755 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -32,6 +32,7 @@ using CodeImp.DoomBuilder.GZBuilder.Data; using CodeImp.DoomBuilder.Types; using CodeImp.DoomBuilder.Data; using System.Linq; +using System.Drawing; #endregion @@ -1025,19 +1026,21 @@ namespace CodeImp.DoomBuilder.BuilderModes { Vertex v = sd.IsFront ? sd.Line.End : sd.Line.Start; - // Check if a thing is at this vertex - VisualBlockEntry b = blockmap.GetBlock(blockmap.GetBlockCoordinates(v.Position)); - foreach (Thing t in b.Things) - { - if ((Vector2D)t.Position == v.Position) - { - switch (t.Type) - { - case 1504: slopefloorthings.Add(t); break; - case 1505: slopeceilingthings.Add(t); break; - } - } - } + // Check if a thing is at this vertex + foreach (VisualBlockEntry block in blockmap.GetBlocks(v.Position)) + { + foreach (Thing t in block.Things) + { + if ((Vector2D)t.Position == v.Position) + { + switch (t.Type) + { + case 1504: slopefloorthings.Add(t); break; + case 1505: slopeceilingthings.Add(t); break; + } + } + } + } } // Slope any floor vertices? From e68da4331a182e0492bed0a5f2b5e4d717ec6ed6 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 26 Dec 2019 00:46:05 +0100 Subject: [PATCH 4/7] Also clean up textures not created by SetPixels --- Source/Native/OpenGL/GLTexture.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Source/Native/OpenGL/GLTexture.cpp b/Source/Native/OpenGL/GLTexture.cpp index f41d86a0..c3c65582 100644 --- a/Source/Native/OpenGL/GLTexture.cpp +++ b/Source/Native/OpenGL/GLTexture.cpp @@ -128,8 +128,11 @@ GLuint GLTexture::GetTexture(GLRenderDevice* device) { if (mTexture == 0) { - Device = device; - ItTexture = Device->mTextures.insert(Device->mTextures.end(), this); + if (Device == nullptr) + { + Device = device; + ItTexture = Device->mTextures.insert(Device->mTextures.end(), this); + } GLint oldActiveTex = GL_TEXTURE0; glGetIntegerv(GL_ACTIVE_TEXTURE, &oldActiveTex); @@ -189,7 +192,11 @@ GLuint GLTexture::GetFramebuffer(GLRenderDevice* device, bool usedepthbuffer) { if (mDepthRenderbuffer == 0) { - Device = device; + if (Device == nullptr) + { + Device = device; + ItTexture = Device->mTextures.insert(Device->mTextures.end(), this); + } glGenRenderbuffers(1, &mDepthRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbuffer); @@ -216,7 +223,11 @@ GLuint GLTexture::GetPBO(GLRenderDevice* device) { if (mPBO == 0) { - Device = device; + if (Device == nullptr) + { + Device = device; + ItTexture = Device->mTextures.insert(Device->mTextures.end(), this); + } glGenBuffers(1, &mPBO); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO); From 459742c840f57b59d05257011d4cd205ba5ecd23 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 26 Dec 2019 01:09:31 +0100 Subject: [PATCH 5/7] Fix double delete bug --- Source/Native/OpenGL/GLIndexBuffer.cpp | 11 +++++++++-- Source/Native/OpenGL/GLIndexBuffer.h | 2 ++ Source/Native/OpenGL/GLRenderDevice.cpp | 19 ++++++++++++++----- Source/Native/OpenGL/GLRenderDevice.h | 2 +- Source/Native/OpenGL/GLTexture.cpp | 5 +++++ Source/Native/OpenGL/GLTexture.h | 2 ++ Source/Native/OpenGL/GLVertexBuffer.cpp | 5 +++++ Source/Native/OpenGL/GLVertexBuffer.h | 2 ++ 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/Source/Native/OpenGL/GLIndexBuffer.cpp b/Source/Native/OpenGL/GLIndexBuffer.cpp index 8adbcc51..0df2642b 100644 --- a/Source/Native/OpenGL/GLIndexBuffer.cpp +++ b/Source/Native/OpenGL/GLIndexBuffer.cpp @@ -25,11 +25,18 @@ GLIndexBuffer::~GLIndexBuffer() { - if (Device && mBuffer != 0) + Finalize(); +} + +void GLIndexBuffer::Finalize() +{ + if (Device) { Device->mIndexBuffers.erase(ItBuffer); Device = nullptr; - glDeleteBuffers(1, &mBuffer); + + if (mBuffer != 0) + glDeleteBuffers(1, &mBuffer); mBuffer = 0; } } diff --git a/Source/Native/OpenGL/GLIndexBuffer.h b/Source/Native/OpenGL/GLIndexBuffer.h index 64ea71c8..dce8825f 100644 --- a/Source/Native/OpenGL/GLIndexBuffer.h +++ b/Source/Native/OpenGL/GLIndexBuffer.h @@ -31,6 +31,8 @@ class GLIndexBuffer : public IndexBuffer public: ~GLIndexBuffer(); + void Finalize(); + GLuint GetBuffer(); GLRenderDevice* Device = nullptr; diff --git a/Source/Native/OpenGL/GLRenderDevice.cpp b/Source/Native/OpenGL/GLRenderDevice.cpp index 9c6d988a..55fd0653 100644 --- a/Source/Native/OpenGL/GLRenderDevice.cpp +++ b/Source/Native/OpenGL/GLRenderDevice.cpp @@ -87,7 +87,7 @@ GLRenderDevice::~GLRenderDevice() for (GLIndexBuffer* buffer : mIndexBuffers) mDeleteList.IndexBuffers.push_back(buffer); for (GLVertexBuffer* buffer : mSharedVertexBuffers[0]->VertexBuffers) mDeleteList.VertexBuffers.push_back(buffer); for (GLVertexBuffer* buffer : mSharedVertexBuffers[1]->VertexBuffers) mDeleteList.VertexBuffers.push_back(buffer); - ProcessDeleteList(); + ProcessDeleteList(true); glDeleteBuffers(1, &mStreamVertexBuffer); glDeleteVertexArrays(1, &mStreamVAO); @@ -965,13 +965,22 @@ void GLRenderDevice::DeleteObject(GLTexture* texture) delete texture; } -void GLRenderDevice::ProcessDeleteList() +void GLRenderDevice::ProcessDeleteList(bool finalize) { std::unique_lock lock(GLRenderDevice::GetMutex()); - for (auto buffer : mDeleteList.IndexBuffers) delete buffer; - for (auto buffer : mDeleteList.VertexBuffers) delete buffer; - for (auto texture : mDeleteList.Textures) delete texture; + if (!finalize) + { + for (auto buffer : mDeleteList.IndexBuffers) delete buffer; + for (auto buffer : mDeleteList.VertexBuffers) delete buffer; + for (auto texture : mDeleteList.Textures) delete texture; + } + else + { + for (auto buffer : mDeleteList.IndexBuffers) buffer->Finalize(); + for (auto buffer : mDeleteList.VertexBuffers) buffer->Finalize(); + for (auto texture : mDeleteList.Textures) texture->Finalize(); + } mDeleteList.IndexBuffers.clear(); mDeleteList.VertexBuffers.clear(); diff --git a/Source/Native/OpenGL/GLRenderDevice.h b/Source/Native/OpenGL/GLRenderDevice.h index 6d22a90b..d9ab4bd6 100644 --- a/Source/Native/OpenGL/GLRenderDevice.h +++ b/Source/Native/OpenGL/GLRenderDevice.h @@ -106,7 +106,7 @@ public: static void DeleteObject(GLIndexBuffer* buffer); static void DeleteObject(GLTexture* texture); - void ProcessDeleteList(); + void ProcessDeleteList(bool finalize = false); std::unique_ptr Context; diff --git a/Source/Native/OpenGL/GLTexture.cpp b/Source/Native/OpenGL/GLTexture.cpp index c3c65582..9ce12fb1 100644 --- a/Source/Native/OpenGL/GLTexture.cpp +++ b/Source/Native/OpenGL/GLTexture.cpp @@ -29,6 +29,11 @@ GLTexture::GLTexture() } GLTexture::~GLTexture() +{ + Finalize(); +} + +void GLTexture::Finalize() { if (Device) Invalidate(); diff --git a/Source/Native/OpenGL/GLTexture.h b/Source/Native/OpenGL/GLTexture.h index 6c47e3a5..b34c24ce 100644 --- a/Source/Native/OpenGL/GLTexture.h +++ b/Source/Native/OpenGL/GLTexture.h @@ -32,6 +32,8 @@ public: GLTexture(); ~GLTexture(); + void Finalize(); + void Set2DImage(int width, int height) override; void SetCubeImage(int size) override; diff --git a/Source/Native/OpenGL/GLVertexBuffer.cpp b/Source/Native/OpenGL/GLVertexBuffer.cpp index b59b9408..7b7511ed 100644 --- a/Source/Native/OpenGL/GLVertexBuffer.cpp +++ b/Source/Native/OpenGL/GLVertexBuffer.cpp @@ -72,6 +72,11 @@ void GLSharedVertexBuffer::SetupWorldVAO() ///////////////////////////////////////////////////////////////////////////// GLVertexBuffer::~GLVertexBuffer() +{ + Finalize(); +} + +void GLVertexBuffer::Finalize() { if (Device) { diff --git a/Source/Native/OpenGL/GLVertexBuffer.h b/Source/Native/OpenGL/GLVertexBuffer.h index ea16d6f4..ed50eb67 100644 --- a/Source/Native/OpenGL/GLVertexBuffer.h +++ b/Source/Native/OpenGL/GLVertexBuffer.h @@ -56,6 +56,8 @@ class GLVertexBuffer : public VertexBuffer public: ~GLVertexBuffer(); + void Finalize(); + VertexFormat Format = VertexFormat::Flat; GLRenderDevice* Device = nullptr; From 061fa30a45cbe3ba7c63454670ab660aba1889ea Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 26 Dec 2019 01:10:00 +0100 Subject: [PATCH 6/7] Improve camera sector search somewhat --- Source/Core/VisualModes/VisualMode.cs | 88 +++++++++++++++------------ 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/Source/Core/VisualModes/VisualMode.cs b/Source/Core/VisualModes/VisualMode.cs index 4dbd9d2f..02bb835a 100755 --- a/Source/Core/VisualModes/VisualMode.cs +++ b/Source/Core/VisualModes/VisualMode.cs @@ -592,45 +592,55 @@ namespace CodeImp.DoomBuilder.VisualModes if(processgeometry) { - // Find camera sector - Linedef nld = MapSet.NearestLinedef(visiblelines, campos2d); - if(nld != null) - { - General.Map.VisualCamera.Sector = GetCameraSectorFromLinedef(nld); - } - else - { - // Exceptional case: no lines found in any nearby blocks! - // This could happen in the middle of an extremely large sector and in this case - // the above code will not have found any sectors/sidedefs for rendering. - // Here we handle this special case with brute-force. Let's find the sector - // the camera is in by searching the entire map and render that sector only. - nld = General.Map.Map.NearestLinedef(campos2d); - if(nld != null) - { - General.Map.VisualCamera.Sector = GetCameraSectorFromLinedef(nld); - if(General.Map.VisualCamera.Sector != null) - { - foreach(Sidedef sd in General.Map.VisualCamera.Sector.Sidedefs) - { - float side = sd.Line.SideOfLine(campos2d); - if(((side < 0) && sd.IsFront) || - ((side > 0) && !sd.IsFront)) - ProcessSidedefCulling(sd); - } - } - else - { - // Too far away from the map to see anything - General.Map.VisualCamera.Sector = null; - } - } - else - { - // Map is empty - General.Map.VisualCamera.Sector = null; - } - } + // Find camera sector + Sector camsector = blockmap.GetSectorAt(campos2d); + if (camsector != null) + { + General.Map.VisualCamera.Sector = camsector; + } + else + { + // To do: fix this code. It is retarded. Walking over all visible lines is extremely expensive. + + Linedef nld = MapSet.NearestLinedef(visiblelines, campos2d); + if (nld != null) + { + General.Map.VisualCamera.Sector = GetCameraSectorFromLinedef(nld); + } + else + { + // Exceptional case: no lines found in any nearby blocks! + // This could happen in the middle of an extremely large sector and in this case + // the above code will not have found any sectors/sidedefs for rendering. + // Here we handle this special case with brute-force. Let's find the sector + // the camera is in by searching the entire map and render that sector only. + nld = General.Map.Map.NearestLinedef(campos2d); + if (nld != null) + { + General.Map.VisualCamera.Sector = GetCameraSectorFromLinedef(nld); + if (General.Map.VisualCamera.Sector != null) + { + foreach (Sidedef sd in General.Map.VisualCamera.Sector.Sidedefs) + { + float side = sd.Line.SideOfLine(campos2d); + if (((side < 0) && sd.IsFront) || + ((side > 0) && !sd.IsFront)) + ProcessSidedefCulling(sd); + } + } + else + { + // Too far away from the map to see anything + General.Map.VisualCamera.Sector = null; + } + } + else + { + // Map is empty + General.Map.VisualCamera.Sector = null; + } + } + } } } From b466035bc8a9516eaacdf187314ba43c67eb169e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Thu, 26 Dec 2019 02:02:53 +0100 Subject: [PATCH 7/7] Fix wrong mipmapping filtering and missing anisotropy --- Source/Native/OpenGL/GLRenderDevice.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/Native/OpenGL/GLRenderDevice.cpp b/Source/Native/OpenGL/GLRenderDevice.cpp index 55fd0653..7ad93b57 100644 --- a/Source/Native/OpenGL/GLRenderDevice.cpp +++ b/Source/Native/OpenGL/GLRenderDevice.cpp @@ -282,7 +282,7 @@ GLint GLRenderDevice::GetGLMinFilter(TextureFilter filter, TextureFilter mipfilt if (mipfilter == TextureFilter::Linear) { if (filter == TextureFilter::Point || filter == TextureFilter::None) - return GL_LINEAR_MIPMAP_NEAREST; + return GL_NEAREST_MIPMAP_LINEAR; else return GL_LINEAR_MIPMAP_LINEAR; } @@ -291,7 +291,7 @@ GLint GLRenderDevice::GetGLMinFilter(TextureFilter filter, TextureFilter mipfilt if (filter == TextureFilter::Point || filter == TextureFilter::None) return GL_NEAREST_MIPMAP_NEAREST; else - return GL_NEAREST_MIPMAP_LINEAR; + return GL_LINEAR_MIPMAP_NEAREST; } else { @@ -914,6 +914,8 @@ bool GLRenderDevice::ApplyTextures() glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_S, wrapMode[(int)mTextureUnit.WrapMode]); glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_T, wrapMode[(int)mTextureUnit.WrapMode]); glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_R, wrapMode[(int)mTextureUnit.WrapMode]); + if (mSamplerFilterKey.MaxAnisotropy > 0.0f) + glSamplerParameterf(samplerHandle, GL_TEXTURE_MAX_ANISOTROPY_EXT, mSamplerFilterKey.MaxAnisotropy); } if (mTextureUnit.SamplerHandle != samplerHandle)