diff --git a/Source/Core/Rendering/Display2DShader.cs b/Source/Core/Rendering/Display2DShader.cs index ca7a009b82f1009c592e29a32e33d4a708dffae0..680ead9d8fe2812af34e3e36bc918aa49c70041f 100644 --- a/Source/Core/Rendering/Display2DShader.cs +++ b/Source/Core/Rendering/Display2DShader.cs @@ -29,16 +29,16 @@ namespace CodeImp.DoomBuilder.Rendering #region ================== Variables // Property handlers - private EffectHandle texture1; - private EffectHandle rendersettings; - private EffectHandle transformsettings; - private EffectHandle filtersettings; + private readonly EffectHandle texture1; + private readonly EffectHandle rendersettings; + private readonly EffectHandle transformsettings; + private readonly EffectHandle filtersettings; #endregion #region ================== Properties - public Texture Texture1 { set { if(manager.Enabled) effect.SetTexture(texture1, value); } } + public Texture Texture1 { set { if(manager.Enabled) effect.SetTexture(texture1, value); settingschanged = true; } } #endregion @@ -60,7 +60,7 @@ namespace CodeImp.DoomBuilder.Rendering } // Initialize world vertex declaration - VertexElement[] elements = new VertexElement[] + VertexElement[] elements = new[] { new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0), new VertexElement(0, 12, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0), @@ -106,6 +106,7 @@ namespace CodeImp.DoomBuilder.Rendering effect.SetValue(transformsettings, world * view); TextureFilter filter = (bilinear ? TextureFilter.Linear : TextureFilter.Point); effect.SetValue(filtersettings, (int)filter); + settingschanged = true; //mxd } } diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs index 1a47f745baf86a55ca6518c3d783cf27c0519cc8..f89bd72c13b0dbbf81b5d3c151a970aca9715d6e 100644 --- a/Source/Core/Rendering/Renderer3D.cs +++ b/Source/Core/Rendering/Renderer3D.cs @@ -164,6 +164,7 @@ namespace CodeImp.DoomBuilder.Rendering if(highlightimage != null) highlightimage.Dispose(); selectionimage = null; highlightimage = null; + vertexHandle.Dispose(); //mxd // Done base.Dispose(); @@ -748,7 +749,6 @@ namespace CodeImp.DoomBuilder.Rendering curtexture.CreateTexture(); // Apply texture - if(!graphics.Shaders.Enabled) graphics.Device.SetTexture(0, curtexture.Texture); graphics.Shaders.World3D.Texture1 = curtexture.Texture; //mxd. Sort geometry by sector index @@ -1248,14 +1248,12 @@ namespace CodeImp.DoomBuilder.Rendering //mxd private Matrix CreateThingPositionMatrix(VisualThing t) { - Matrix result; - //mxd. Create the matrix for positioning if(t.Info.RenderMode == Thing.SpriteRenderMode.NORMAL) // Apply billboarding? { if(t.Info.XYBillboard) { - result = Matrix.Translation(0f, 0f, -t.LocalCenterZ) + return Matrix.Translation(0f, 0f, -t.LocalCenterZ) * Matrix.RotationX(Angle2D.PI - General.Map.VisualCamera.AngleZ) * Matrix.Translation(0f, 0f, t.LocalCenterZ) * billboard @@ -1264,18 +1262,16 @@ namespace CodeImp.DoomBuilder.Rendering } else { - result = billboard + return billboard * Matrix.Scaling(t.Thing.ScaleX, t.Thing.ScaleX, t.Thing.ScaleY) * t.Position; } } else { - result = Matrix.Scaling(t.Thing.ScaleX, t.Thing.ScaleX, t.Thing.ScaleY) + return Matrix.Scaling(t.Thing.ScaleX, t.Thing.ScaleX, t.Thing.ScaleY) * t.Position; } - - return result; } //mxd. Dynamic lights pass! @@ -1328,12 +1324,12 @@ namespace CodeImp.DoomBuilder.Rendering { graphics.Device.SetRenderState(RenderState.BlendOperation, BlendOperation.Add); - for (i = 0; i < count; i++) + for(i = 0; i < count; i++) { - if (BoundingBoxesIntersect(g.BoundingBox, lights[i].BoundingBox)) + if(BoundingBoxesIntersect(g.BoundingBox, lights[i].BoundingBox)) { lpr = new Vector4(lights[i].Center, lights[i].LightRadius); - if (lpr.W == 0) continue; + if(lpr.W == 0) continue; graphics.Shaders.World3D.LightColor = lights[i].LightColor; graphics.Shaders.World3D.LightPositionAndRadius = lpr; graphics.Shaders.World3D.ApplySettings(); @@ -1348,12 +1344,12 @@ namespace CodeImp.DoomBuilder.Rendering count += lightOffsets[1]; graphics.Device.SetRenderState(RenderState.BlendOperation, BlendOperation.Add); - for (i = lightOffsets[0]; i < count; i++) + for(i = lightOffsets[0]; i < count; i++) { - if (BoundingBoxesIntersect(g.BoundingBox, lights[i].BoundingBox)) + if(BoundingBoxesIntersect(g.BoundingBox, lights[i].BoundingBox)) { lpr = new Vector4(lights[i].Center, lights[i].LightRadius); - if (lpr.W == 0) continue; + if(lpr.W == 0) continue; graphics.Shaders.World3D.LightColor = lights[i].LightColor; graphics.Shaders.World3D.LightPositionAndRadius = lpr; graphics.Shaders.World3D.ApplySettings(); @@ -1368,12 +1364,12 @@ namespace CodeImp.DoomBuilder.Rendering count += lightOffsets[2]; graphics.Device.SetRenderState(RenderState.BlendOperation, BlendOperation.ReverseSubtract); - for (i = lightOffsets[0] + lightOffsets[1]; i < count; i++) + for(i = lightOffsets[0] + lightOffsets[1]; i < count; i++) { - if (BoundingBoxesIntersect(g.BoundingBox, lights[i].BoundingBox)) + if(BoundingBoxesIntersect(g.BoundingBox, lights[i].BoundingBox)) { lpr = new Vector4(lights[i].Center, lights[i].LightRadius); - if (lpr.W == 0) continue; + if(lpr.W == 0) continue; Color4 lc = lights[i].LightColor; graphics.Shaders.World3D.LightColor = new Color4(lc.Alpha, (lc.Green + lc.Blue) / 2, (lc.Red + lc.Blue) / 2, (lc.Green + lc.Red) / 2); graphics.Shaders.World3D.LightPositionAndRadius = lpr; diff --git a/Source/Core/Rendering/Things2DShader.cs b/Source/Core/Rendering/Things2DShader.cs index 7ce7d0a0e33a52d5a24c9886ed69748117b453c6..51e78001808ee3ee2698de324ddae2bbcaa0f348 100644 --- a/Source/Core/Rendering/Things2DShader.cs +++ b/Source/Core/Rendering/Things2DShader.cs @@ -29,20 +29,31 @@ namespace CodeImp.DoomBuilder.Rendering #region ================== Variables // Property handlers - private EffectHandle texture1; - private EffectHandle rendersettings; - private EffectHandle transformsettings; - - //mxd - private EffectHandle fillColorHandle; + private readonly EffectHandle texture1; + private readonly EffectHandle rendersettings; + private readonly EffectHandle transformsettings; + private readonly EffectHandle fillcolor; //mxd #endregion #region ================== Properties - public Texture Texture1 { set { if(manager.Enabled) effect.SetTexture(texture1, value); } } + public Texture Texture1 { set { if(manager.Enabled) effect.SetTexture(texture1, value); settingschanged = true; } } + //mxd - public Color4 FillColor { set { if (manager.Enabled) effect.SetValue<Color4>(fillColorHandle, value); } } + private Color4 fc; + public Color4 FillColor + { + set + { + if(manager.Enabled && fc != value) + { + effect.SetValue(fillcolor, value); + fc = value; + settingschanged = true; + } + } + } #endregion @@ -60,12 +71,11 @@ namespace CodeImp.DoomBuilder.Rendering texture1 = effect.GetParameter(null, "texture1"); rendersettings = effect.GetParameter(null, "rendersettings"); transformsettings = effect.GetParameter(null, "transformsettings"); - //mxd - fillColorHandle = effect.GetParameter(null, "fillColor"); + fillcolor = effect.GetParameter(null, "fillColor"); //mxd } // Initialize world vertex declaration - VertexElement[] elements = new VertexElement[] + VertexElement[] elements = new[] { new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0), new VertexElement(0, 12, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0), @@ -88,8 +98,7 @@ namespace CodeImp.DoomBuilder.Rendering if(texture1 != null) texture1.Dispose(); if(rendersettings != null) rendersettings.Dispose(); if(transformsettings != null) transformsettings.Dispose(); - //mxd - if (fillColorHandle != null) fillColorHandle.Dispose(); + if(fillcolor != null) fillcolor.Dispose(); //mxd // Done base.Dispose(); @@ -110,6 +119,7 @@ namespace CodeImp.DoomBuilder.Rendering Matrix world = manager.D3DDevice.Device.GetTransform(TransformState.World); Matrix view = manager.D3DDevice.Device.GetTransform(TransformState.View); effect.SetValue(transformsettings, world * view); + settingschanged = true; //mxd } } diff --git a/Source/Core/Rendering/World3DShader.cs b/Source/Core/Rendering/World3DShader.cs index eb04f0b9dd52a879c825c49410b6936f9e740d64..dcb6031a448d41beea1c0454d9c84023aa5009b0 100644 --- a/Source/Core/Rendering/World3DShader.cs +++ b/Source/Core/Rendering/World3DShader.cs @@ -53,7 +53,20 @@ namespace CodeImp.DoomBuilder.Rendering #region ================== Properties - public Matrix WorldViewProj { set { if(manager.Enabled) effect.SetValue(worldviewproj, value); settingschanged = true; } } + private Matrix wwp; + public Matrix WorldViewProj + { + set + { + if(manager.Enabled && wwp != value) + { + effect.SetValue(worldviewproj, value); + wwp = value; + settingschanged = true; + } + } + } + public Texture Texture1 { set { if(manager.Enabled) effect.SetTexture(texture1, value); settingschanged = true; } } //mxd @@ -264,6 +277,8 @@ namespace CodeImp.DoomBuilder.Rendering effect.SetValue(mipfiltersettings, (int)TextureFilter.Linear); effect.SetValue(maxanisotropysetting, 1.0f); } + + settingschanged = true; //mxd } } diff --git a/Source/Core/Resources/world3d.fx b/Source/Core/Resources/world3d.fx index e855cfb0274e5de889a1780bd58cdbea34da779d..0710f0abc7faa11b820f2840ea6967fad6b7a8f0 100644 --- a/Source/Core/Resources/world3d.fx +++ b/Source/Core/Resources/world3d.fx @@ -33,7 +33,7 @@ struct LitPixelData float4 highlightcolor; // Matrix for final transformation -float4x4 worldviewproj; +const float4x4 worldviewproj; //mxd float4x4 world; @@ -44,16 +44,16 @@ float4 lightPosAndRadius; float4 lightColor; //also used as fog color //fog -float4 cameraPos; //w is set to fade factor (distance, at wich fog color completely overrides pixel color) +const float4 cameraPos; //w is set to fade factor (distance, at wich fog color completely overrides pixel color) // Texture input -texture texture1; +const texture texture1; // Filter settings -dword minfiltersettings; -dword magfiltersettings; -dword mipfiltersettings; -float maxanisotropysetting; +const dword minfiltersettings; +const dword magfiltersettings; +const dword mipfiltersettings; +const float maxanisotropysetting; // Texture sampler settings sampler2D texturesamp = sampler_state diff --git a/Source/Core/VisualModes/VisualBlockMap.cs b/Source/Core/VisualModes/VisualBlockMap.cs index 18291d2e2de9e391b680e32ad3ff5aff431cd521..23bd8c6192f09892a6ab81cd78205362c31cc7f7 100644 --- a/Source/Core/VisualModes/VisualBlockMap.cs +++ b/Source/Core/VisualModes/VisualBlockMap.cs @@ -268,9 +268,17 @@ namespace CodeImp.DoomBuilder.VisualModes // This puts a thing in the blockmap public void AddThing(Thing t) { - Point p = GetBlockCoordinates(t.Position); - VisualBlockEntry block = GetBlock(p); - block.Things.Add(t); + //mxd + Point p1 = GetBlockCoordinates(new Vector2D(t.Position.x - t.Size, t.Position.y - t.Size)); + Point p2 = GetBlockCoordinates(new Vector2D(t.Position.x + t.Size, t.Position.y + t.Size)); + 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 diff --git a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs index 24322ec792f1ed243e142b73fcb06e838c18b30c..156d4cc92d5f05d92e9460ca9a6654e4254da43d 100644 --- a/Source/Plugins/BuilderModes/General/BuilderModesTools.cs +++ b/Source/Plugins/BuilderModes/General/BuilderModesTools.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using CodeImp.DoomBuilder.Config; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.VisualModes; @@ -366,13 +367,21 @@ namespace CodeImp.DoomBuilder.BuilderModes #region ================== Things - internal static float GetHigherThingZ(SectorData sd, Vector3D pos, float thingheight, bool absolute, bool hangs) + internal static float GetHigherThingZ(BaseVisualMode mode, SectorData sd, VisualThing thing) { + Vector3D pos = thing.Thing.Position; + float thingheight = thing.Thing.Height; + bool absolute = thing.Info.AbsoluteZ; + bool hangs = thing.Info.Hangs; + if(absolute && hangs) { General.Interface.DisplayStatus(StatusType.Warning, "Sorry, can't have both 'absolute' and 'hangs' flags..."); return pos.z; } + + // Get things, which bounding boxes intersect with target thing + IEnumerable<Thing> intersectingthings = GetIntersectingThings(mode, thing.Thing); float fz = (absolute ? 0 : sd.Floor.plane.GetZ(pos)); float cz = sd.Ceiling.plane.GetZ(pos); @@ -381,41 +390,95 @@ namespace CodeImp.DoomBuilder.BuilderModes { // Transform to floor-aligned position Vector3D floorpos = new Vector3D(pos, (cz - fz) - pos.z - thingheight); + float highertingz = GetNextHigherThingZ(mode, intersectingthings, floorpos.z, thingheight); + float higherfloorz = float.MinValue; + + // Do it only when there are extrafloors + if(sd.LightLevels.Count > 2) + { + // Unlike sd.ExtraFloors, these are sorted by height + foreach(SectorLevel level in sd.LightLevels) + { + if(level.type == SectorLevelType.Light || level.type == SectorLevelType.Glow) continue; // Skip lights and glows + float z = level.plane.GetZ(floorpos) - fz; + if(level.type == SectorLevelType.Ceiling) z -= thingheight; + if(z > floorpos.z) + { + higherfloorz = z; + break; + } + } + } + + if(higherfloorz != float.MinValue && highertingz != float.MaxValue) + { + // Transform back to ceiling-aligned position + return cz - fz - Math.Max(Math.Min(higherfloorz, highertingz), 0) - thingheight; + } - // Unlike sd.ExtraFloors, these are sorted by height - foreach (SectorLevel level in sd.LightLevels) + if(higherfloorz != float.MinValue) { - if(level.type == SectorLevelType.Light) continue; // Skip lights - float z = level.plane.GetZ(floorpos) - fz; - if(level.type == SectorLevelType.Ceiling) z -= thingheight; - if(z > floorpos.z) return cz - fz - z - thingheight; // Transform back to ceiling-aligned position + // Transform back to ceiling-aligned position + return Math.Max(cz - fz - higherfloorz - thingheight, 0); + } + + if(highertingz != float.MaxValue) + { + // Transform back to ceiling-aligned position + return Math.Max(cz - fz - highertingz - thingheight, 0); } return 0; // Align to real ceiling } else { - // Unlike sd.ExtraFloors, these are sorted by height - foreach(SectorLevel level in sd.LightLevels) + float highertingz = GetNextHigherThingZ(mode, intersectingthings, (absolute ? pos.z - fz : pos.z), thingheight); + float higherfloorz = float.MinValue; + + // Do it only when there are extrafloors + if(sd.LightLevels.Count > 2) { - if(level.type == SectorLevelType.Light) continue; // Skip lights - float z = level.plane.GetZ(pos) - fz; - if(level.type == SectorLevelType.Ceiling) z -= thingheight; - if(z > pos.z) return z; + // Unlike sd.ExtraFloors, these are sorted by height + foreach(SectorLevel level in sd.LightLevels) + { + if(level.type == SectorLevelType.Light || level.type == SectorLevelType.Glow) continue; // Skip lights and glows + float z = level.plane.GetZ(pos) - fz; + if(level.type == SectorLevelType.Ceiling) z -= thingheight; + if(z > pos.z) + { + higherfloorz = z; + break; + } + } } - return cz - fz - thingheight; // Align to real ceiling + float floorz = sd.Floor.plane.GetZ(pos); + float ceilpos = cz - floorz - thingheight; // Ceiling-aligned relative target thing z + + if(higherfloorz != float.MinValue && highertingz != float.MaxValue) ceilpos = Math.Min(ceilpos, Math.Min(higherfloorz, highertingz)); + if(higherfloorz != float.MinValue) ceilpos = Math.Min(ceilpos, higherfloorz); + if(highertingz != float.MaxValue) ceilpos = Math.Min(ceilpos, highertingz); + + return (absolute ? ceilpos + floorz : ceilpos); // Convert to absolute position if necessary } } - internal static float GetLowerThingZ(SectorData sd, Vector3D pos, float thingheight, bool absolute, bool hangs) + internal static float GetLowerThingZ(BaseVisualMode mode, SectorData sd, VisualThing thing) { + Vector3D pos = thing.Thing.Position; + float thingheight = thing.Thing.Height; + bool absolute = thing.Info.AbsoluteZ; + bool hangs = thing.Info.Hangs; + if(absolute && hangs) { General.Interface.DisplayStatus(StatusType.Warning, "Sorry, can't have both 'absolute' and 'hangs' flags..."); return pos.z; } + // Get things, which bounding boxes intersect with target thing + IEnumerable<Thing> intersectingthings = GetIntersectingThings(mode, thing.Thing); + float fz = (absolute ? 0 : sd.Floor.plane.GetZ(pos)); float cz = sd.Ceiling.plane.GetZ(pos); @@ -423,33 +486,198 @@ namespace CodeImp.DoomBuilder.BuilderModes { // Transform to floor-aligned position Vector3D floorpos = new Vector3D(pos, (cz - fz) - pos.z - thingheight); + float lowertingz = GetNextLowerThingZ(mode, intersectingthings, floorpos.z, thingheight); + float lowerfloorz = float.MaxValue; + + // Do it only when there are extrafloors + if(sd.LightLevels.Count > 2) + { + // Unlike sd.ExtraFloors, these are sorted by height + for(int i = sd.LightLevels.Count - 1; i > -1; i--) + { + SectorLevel level = sd.LightLevels[i]; + if(level.type == SectorLevelType.Light || level.type == SectorLevelType.Glow) continue; // Skip lights and glows + float z = level.plane.GetZ(floorpos) - fz; + if(level.type == SectorLevelType.Ceiling) z -= thingheight; + if(z < floorpos.z) + { + lowerfloorz = z; + break; + } + } + } + + float floorz = cz - fz; // Floor height when counted from ceiling + + if(lowerfloorz != float.MaxValue && lowertingz != float.MinValue) + { + // Transform back to ceiling-aligned position + return cz - fz - Math.Min(Math.Max(lowerfloorz, lowertingz), floorz) - thingheight; + } + + if(lowerfloorz != float.MaxValue) + { + // Transform back to ceiling-aligned position + return cz - fz - Math.Min(lowerfloorz, floorz) - thingheight; + } - // Unlike sd.ExtraFloors, these are sorted by height - for(int i = sd.LightLevels.Count - 1; i > -1; i--) + if(lowertingz != float.MinValue) { - SectorLevel level = sd.LightLevels[i]; - if(level.type == SectorLevelType.Light) continue; // Skip lights - float z = level.plane.GetZ(floorpos) - fz; - if(level.type == SectorLevelType.Ceiling) z -= thingheight; - if(z < floorpos.z) return cz - fz - z - thingheight; // Transform back to ceiling-aligned position + // Transform back to ceiling-aligned position + return cz - fz - Math.Min(lowertingz, floorz) - thingheight; } - return cz - fz - thingheight; // Align to real floor + return floorz - thingheight; // Align to real floor } else { - // Unlike sd.ExtraFloors, these are sorted by height - for(int i = sd.LightLevels.Count - 1; i > -1; i--) + float lowertingz = GetNextLowerThingZ(mode, intersectingthings, (absolute ? pos.z - fz : pos.z), thingheight); + float lowerfloorz = float.MaxValue; + + // Do it only when there are extrafloors + if(sd.LightLevels.Count > 2) + { + // Unlike sd.ExtraFloors, these are sorted by height + for(int i = sd.LightLevels.Count - 1; i > -1; i--) + { + SectorLevel level = sd.LightLevels[i]; + if(level.type == SectorLevelType.Light || level.type == SectorLevelType.Glow) continue; // Skip lights and glows + float z = level.plane.GetZ(pos) - fz; + if(level.type == SectorLevelType.Ceiling) z -= thingheight; + if(z < pos.z) + { + lowerfloorz = z; + break; + } + } + } + + float floorz = sd.Floor.plane.GetZ(pos); // Floor-aligned relative target thing z + float floorpos = 0; + + if(lowerfloorz != float.MaxValue && lowertingz != float.MinValue) floorpos = Math.Max(Math.Max(lowerfloorz, lowertingz), floorz); + if(lowerfloorz != float.MaxValue) floorpos = Math.Max(lowerfloorz, floorz); + if(lowertingz != float.MinValue) floorpos = Math.Max(lowertingz, floorz); + + return (absolute ? floorpos + floorz : floorpos); // Convert to absolute position if necessary + } + } + + //mxd. Gets thing z next higher to target thing z + private static float GetNextHigherThingZ(BaseVisualMode mode, IEnumerable<Thing> things, float thingz, float thingheight) + { + float higherthingz = float.MaxValue; + foreach(Thing t in things) + { + float neighbourz = GetAlignedThingZ(mode, t, thingheight); + if(neighbourz > thingz && neighbourz < higherthingz) higherthingz = neighbourz; + } + return higherthingz; + } + + //mxd. Gets thing z next lower to target thing z + private static float GetNextLowerThingZ(BaseVisualMode mode, IEnumerable<Thing> things, float thingz, float thingheight) + { + float lowerthingz = float.MinValue; + foreach(Thing t in things) + { + float neighbourz = GetAlignedThingZ(mode, t, thingheight); + if(neighbourz < thingz && neighbourz > lowerthingz) lowerthingz = neighbourz; + } + + return lowerthingz; + } + + private static float GetAlignedThingZ(BaseVisualMode mode, Thing t, float targtthingheight) + { + ThingTypeInfo info = General.Map.Data.GetThingInfoEx(t.Type); + if(info != null) + { + if(info.AbsoluteZ && info.Hangs) return t.Position.z; // Not sure what to do here... + if(info.AbsoluteZ) + { + // Transform to floor-aligned position + SectorData nsd = mode.GetSectorData(t.Sector); + return t.Position.z - nsd.Floor.plane.GetZ(t.Position) + t.Height; + } + + if(info.Hangs) + { + // Transform to floor-aligned position. Align top of target thing to the bottom of the hanging thing + SectorData nsd = mode.GetSectorData(t.Sector); + return (nsd.Ceiling.plane.GetZ(t.Position) - nsd.Floor.plane.GetZ(t.Position)) - t.Position.z - t.Height - targtthingheight; + } + } + + return t.Position.z + t.Height; + } + + private static IEnumerable<Thing> GetIntersectingThings(VisualMode mode, Thing thing) + { + // Get nearby things + List<Thing> neighbours = new List<Thing>(); + 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++) { - SectorLevel level = sd.LightLevels[i]; - if(level.type == SectorLevelType.Light) continue; // Skip lights - float z = level.plane.GetZ(pos) - fz; - if(level.type == SectorLevelType.Ceiling) z -= thingheight; - if(z < pos.z) return z; + neighbours.AddRange(mode.BlockMap.GetBlock(new Point(x, y)).Things); } + } - return (absolute ? sd.Floor.plane.GetZ(pos) : 0); // Align to real floor + // Collect things intersecting with target thing + List<Thing> intersectingthings = new List<Thing>(); + + foreach(Thing t in neighbours) + { + if(t != thing && t.Sector != null && bbox.IntersectsWith(new RectangleF(t.Position.x - t.Size, t.Position.y - t.Size, t.Size * 2, t.Size * 2))) + intersectingthings.Add(t); } + + return intersectingthings; + } + + #endregion + + #region ================== Sectors + + // This gets sectors which surround given sectors + internal static IEnumerable<Sector> GetSectorsAround(IEnumerable<Sector> selected) + { + HashSet<int> processedsectors = new HashSet<int>(); + HashSet<Vertex> verts = new HashSet<Vertex>(); + List<Sector> result = new List<Sector>(); + + foreach(Sector s in selected) + { + processedsectors.Add(s.Index); + foreach(Sidedef side in s.Sidedefs) + { + if(!verts.Contains(side.Line.Start)) verts.Add(side.Line.Start); + if(!verts.Contains(side.Line.End)) verts.Add(side.Line.End); + } + } + + foreach(Vertex v in verts) + { + foreach(Linedef l in v.Linedefs) + { + if(l.Front != null && l.Front.Sector != null && !processedsectors.Contains(l.Front.Sector.Index)) + { + result.Add(l.Front.Sector); + processedsectors.Add(l.Front.Sector.Index); + } + if(l.Back != null && l.Back.Sector != null && !processedsectors.Contains(l.Back.Sector.Index)) + { + result.Add(l.Back.Sector); + processedsectors.Add(l.Back.Sector.Index); + } + } + } + + return result; } #endregion diff --git a/Source/Plugins/BuilderModes/Resources/Actions.cfg b/Source/Plugins/BuilderModes/Resources/Actions.cfg index fa6954c44faf02c6c6a7567d99e9dce667005204..444923fcd039f2e8397109122c0b1182e2c68c8a 100644 --- a/Source/Plugins/BuilderModes/Resources/Actions.cfg +++ b/Source/Plugins/BuilderModes/Resources/Actions.cfg @@ -569,7 +569,7 @@ errorcheckmode lowersector8 { - title = "Lower Floor/Ceiling by 8 mp"; + title = "Lower Floor/Ceiling/Thing by 8 mp"; category = "visual"; description = "Lowers the targeted or selected floors/ceilings by 8 mp. This also lowers selected or targeted things."; allowkeys = true; @@ -580,7 +580,7 @@ lowersector8 raisesector8 { - title = "Raise Floor/Ceiling by 8 mp"; + title = "Raise Floor/Ceiling/Thing by 8 mp"; category = "visual"; description = "Raises the targeted or selected floors/ceilings by 8 mp. This also raises selected or targeted things."; allowkeys = true; @@ -591,7 +591,7 @@ raisesector8 lowersector1 { - title = "Lower Floor/Ceiling by 1 mp"; + title = "Lower Floor/Ceiling/Thing by 1 mp"; category = "visual"; description = "Lowers the targeted or selected floors/ceilings by 1 mp. This also lowers selected or targeted things."; allowkeys = true; @@ -602,7 +602,7 @@ lowersector1 raisesector1 { - title = "Raise Floor/Ceiling by 1 mp"; + title = "Raise Floor/Ceiling/Thing by 1 mp"; category = "visual"; description = "Raises the targeted or selected floors/ceilings by 1 mp. This also raises selected or targeted things."; allowkeys = true; @@ -614,9 +614,9 @@ raisesector1 //mxd lowersectortonearest { - title = "Lower Floor/Ceiling to adjacent sector"; + title = "Lower Floor/Ceiling/Thing to adjacent Sector/Thing"; category = "visual"; - description = "Lowers the targeted or selected floors/ceilings to match the height of adjacent sector. Hold Ctrl to lower to lowest surface in selection. Also drops targeted or selected things to the nearest floor or ceiling."; + description = "Lowers the targeted or selected floors/ceilings to match the height of adjacent sector. Hold Ctrl to lower to lowest surface in selection. Also drops targeted or selected things to the nearest floor or ceiling or on top of another thing."; allowkeys = true; allowmouse = true; allowscroll = true; @@ -627,9 +627,9 @@ lowersectortonearest //mxd raisesectortonearest { - title = "Raise Floor/Ceiling to adjacent sector"; + title = "Raise Floor/Ceiling/Thing to adjacent Sector/Thing"; category = "visual"; - description = "Raises the targeted or selected floors/ceilings to match the height of adjacent sector. Hold Ctrl to raise to highest surface in selection. Also raises targeted or selected things to the nearest ceiling or floor."; + description = "Raises the targeted or selected floors/ceilings to match the height of adjacent sector. Hold Ctrl to raise to highest surface in selection. Also raises targeted or selected things to the nearest ceiling or floor or puts them on top of another thing."; allowkeys = true; allowmouse = true; allowscroll = true; diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs index 8ec4eb67e6b487572a4ac23cba0ce613b10d6634..835d27d3d54edc42399060a9c9b0b356ea5e194f 100644 --- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs +++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs @@ -18,6 +18,7 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Windows.Forms; using CodeImp.DoomBuilder.BuilderModes.Interface; using CodeImp.DoomBuilder.Windows; @@ -824,7 +825,6 @@ namespace CodeImp.DoomBuilder.BuilderModes // Find all sector who's tag is not 0 and hash them so that we can find them quicly foreach(Sector s in General.Map.Map.Sectors) { - s.UpdateFogColor(); //mxd. Also update fog color foreach(int tag in s.Tags) { if(tag == 0) continue; @@ -1066,6 +1066,9 @@ namespace CodeImp.DoomBuilder.BuilderModes cameraflooroffset = General.Map.Config.ReadSetting("cameraflooroffset", cameraflooroffset); cameraceilingoffset = General.Map.Config.ReadSetting("cameraceilingoffset", cameraceilingoffset); + //mxd. Update fog color (otherwise FogBoundaries won't be setup correctly) + foreach(Sector s in General.Map.Map.Sectors) s.UpdateFogColor(); + // (Re)create special effects RebuildElementData(); @@ -2034,8 +2037,8 @@ namespace CodeImp.DoomBuilder.BuilderModes List<BaseVisualThing> things = new List<BaseVisualThing>(); bool withinSelection = General.Interface.CtrlState; - //get selection - if(selectedobjects.Count == 0) + // Get selection + if(selectedobjects.Count == 0) { IVisualEventReceiver i = (target.picked as IVisualEventReceiver); if(i is VisualFloor) @@ -2074,7 +2077,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - //check what we have + // Check what we have if(floors.Count + ceilings.Count == 0 && (things.Count == 0 || !General.Map.FormatInterface.HasThingHeight)) { General.Interface.DisplayStatus(StatusType.Warning, "No suitable objects found!"); @@ -2100,57 +2103,48 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - //process floors... + // Process floors... int maxSelectedHeight = int.MinValue; int minSelectedCeilingHeight = int.MaxValue; int targetCeilingHeight = int.MaxValue; - //get highest ceiling height from selection + // Get highest ceiling height from selection foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) { - if(group.Key.CeilHeight > maxSelectedHeight) - maxSelectedHeight = group.Key.CeilHeight; + if(group.Key.CeilHeight > maxSelectedHeight) maxSelectedHeight = group.Key.CeilHeight; } if(withinSelection) { - //we are raising, so we don't need to check anything + // We are raising, so we don't need to check anything targetCeilingHeight = maxSelectedHeight; } else { - //get next higher floor or ceiling from surrounding unselected sectors - foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) + // Get next higher floor or ceiling from surrounding unselected sectors + foreach(Sector s in BuilderModesTools.GetSectorsAround(ceilings.Keys)) { - foreach(Sidedef side in group.Key.Sidedefs) - { - if(side.Other == null || ceilings.ContainsKey(side.Other.Sector) || floors.ContainsKey(side.Other.Sector)) - continue; - if(side.Other.Sector.FloorHeight < targetCeilingHeight && side.Other.Sector.FloorHeight > maxSelectedHeight) - targetCeilingHeight = side.Other.Sector.FloorHeight; - else if(side.Other.Sector.CeilHeight < targetCeilingHeight && side.Other.Sector.CeilHeight > maxSelectedHeight) - targetCeilingHeight = side.Other.Sector.CeilHeight; - } + if(s.FloorHeight < targetCeilingHeight && s.FloorHeight > maxSelectedHeight) + targetCeilingHeight = s.FloorHeight; + else if(s.CeilHeight < targetCeilingHeight && s.CeilHeight > maxSelectedHeight) + targetCeilingHeight = s.CeilHeight; } } - //ceilings... + // Ceilings... maxSelectedHeight = int.MinValue; int targetFloorHeight = int.MaxValue; - //get maximum floor and minimum ceiling heights from selection + // Get maximum floor and minimum ceiling heights from selection foreach(KeyValuePair<Sector, VisualFloor> group in floors) { - if(group.Key.FloorHeight > maxSelectedHeight) - maxSelectedHeight = group.Key.FloorHeight; - - if(group.Key.CeilHeight < minSelectedCeilingHeight) - minSelectedCeilingHeight = group.Key.CeilHeight; + if(group.Key.FloorHeight > maxSelectedHeight) maxSelectedHeight = group.Key.FloorHeight; + if(group.Key.CeilHeight < minSelectedCeilingHeight) minSelectedCeilingHeight = group.Key.CeilHeight; } if(withinSelection) { - //check heights + // Check heights if(minSelectedCeilingHeight < maxSelectedHeight) { General.Interface.DisplayStatus(StatusType.Warning, "Can't do: lowest ceiling is lower than highest floor!"); @@ -2160,27 +2154,22 @@ namespace CodeImp.DoomBuilder.BuilderModes } else { - //get next higher floor or ceiling from surrounding unselected sectors - foreach(KeyValuePair<Sector, VisualFloor> group in floors) + // Get next higher floor or ceiling from surrounding unselected sectors + foreach(Sector s in BuilderModesTools.GetSectorsAround(floors.Keys)) { - foreach(Sidedef side in group.Key.Sidedefs) - { - if(side.Other == null || ceilings.ContainsKey(side.Other.Sector) || floors.ContainsKey(side.Other.Sector)) - continue; - if(side.Other.Sector.FloorHeight > maxSelectedHeight && side.Other.Sector.FloorHeight < targetFloorHeight && side.Other.Sector.FloorHeight <= minSelectedCeilingHeight) - targetFloorHeight = side.Other.Sector.FloorHeight; - else if(side.Other.Sector.CeilHeight > maxSelectedHeight && side.Other.Sector.CeilHeight < targetFloorHeight && side.Other.Sector.CeilHeight <= side.Sector.CeilHeight) - targetFloorHeight = side.Other.Sector.CeilHeight; - } + if(s.FloorHeight > maxSelectedHeight && s.FloorHeight < targetFloorHeight && s.FloorHeight <= minSelectedCeilingHeight) + targetFloorHeight = s.FloorHeight; + else if(s.CeilHeight > maxSelectedHeight && s.CeilHeight < targetFloorHeight && s.CeilHeight <= minSelectedCeilingHeight) + targetFloorHeight = s.CeilHeight; } } //CHECK VALUES string alignFailDescription = string.Empty; - if (floors.Count > 0 && targetFloorHeight == int.MaxValue) + if(floors.Count > 0 && targetFloorHeight == int.MaxValue) { - //raise to lowest ceiling? + // Raise to lowest ceiling? if(!withinSelection && minSelectedCeilingHeight > maxSelectedHeight) { targetFloorHeight = minSelectedCeilingHeight; @@ -2193,9 +2182,7 @@ namespace CodeImp.DoomBuilder.BuilderModes if(ceilings.Count > 0 && targetCeilingHeight == int.MaxValue) { - if(!string.IsNullOrEmpty(alignFailDescription)) - alignFailDescription += " and "; - + if(!string.IsNullOrEmpty(alignFailDescription)) alignFailDescription += " and "; alignFailDescription += ceilings.Count > 1 ? "ceilings" : "ceiling"; } @@ -2208,7 +2195,7 @@ namespace CodeImp.DoomBuilder.BuilderModes //APPLY VALUES PreAction(UndoGroup.SectorHeightChange); - //change floors heights + // Change floors heights if(floors.Count > 0) { foreach(KeyValuePair<Sector, VisualFloor> group in floors) @@ -2218,7 +2205,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - //change ceilings heights + // Change ceilings heights if(ceilings.Count > 0) { foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) @@ -2235,7 +2222,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(vt.Thing.Sector == null) continue; SectorData sd = GetSectorData(vt.Thing.Sector); - vt.OnMove(new Vector3D(vt.Thing.Position, BuilderModesTools.GetHigherThingZ(sd, vt.Thing.Position, vt.Thing.Height, vt.Info.AbsoluteZ, vt.Info.Hangs))); + vt.OnMove(new Vector3D(vt.Thing.Position, BuilderModesTools.GetHigherThingZ(this, sd, vt))); } } @@ -2291,7 +2278,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - //check what we have + // Check what we have if(floors.Count + ceilings.Count == 0 && (things.Count == 0 || !General.Map.FormatInterface.HasThingHeight)) { General.Interface.DisplayStatus(StatusType.Warning, "No suitable objects found!"); @@ -2317,52 +2304,43 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - //process floors... + // Process floors... int minSelectedHeight = int.MaxValue; int targetFloorHeight = int.MinValue; - //get minimum floor height from selection + // Get minimum floor height from selection foreach(KeyValuePair<Sector, VisualFloor> group in floors) { - if(group.Key.FloorHeight < minSelectedHeight) - minSelectedHeight = group.Key.FloorHeight; + if(group.Key.FloorHeight < minSelectedHeight) minSelectedHeight = group.Key.FloorHeight; } if(withinSelection) { - //we are lowering, so we don't need to check anything + // We are lowering, so we don't need to check anything targetFloorHeight = minSelectedHeight; } else { - //get next lower ceiling or floor from surrounding unselected sectors - foreach(KeyValuePair<Sector, VisualFloor> group in floors) + // Get next lower ceiling or floor from surrounding unselected sectors + foreach(Sector s in BuilderModesTools.GetSectorsAround(floors.Keys)) { - foreach(Sidedef side in group.Key.Sidedefs) - { - if(side.Other == null || ceilings.ContainsKey(side.Other.Sector) || floors.ContainsKey(side.Other.Sector)) - continue; - if(side.Other.Sector.CeilHeight > targetFloorHeight && side.Other.Sector.CeilHeight < minSelectedHeight) - targetFloorHeight = side.Other.Sector.CeilHeight; - else if(side.Other.Sector.FloorHeight > targetFloorHeight && side.Other.Sector.FloorHeight < minSelectedHeight) - targetFloorHeight = side.Other.Sector.FloorHeight; - } + if(s.CeilHeight > targetFloorHeight && s.CeilHeight < minSelectedHeight) + targetFloorHeight = s.CeilHeight; + else if(s.FloorHeight > targetFloorHeight && s.FloorHeight < minSelectedHeight) + targetFloorHeight = s.FloorHeight; } } - //ceilings... + // Ceilings... minSelectedHeight = int.MaxValue; int maxSelectedFloorHeight = int.MinValue; int targetCeilingHeight = int.MinValue; - //get minimum ceiling and maximum floor heights from selection + // Get minimum ceiling and maximum floor heights from selection foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) { - if(group.Key.CeilHeight < minSelectedHeight) - minSelectedHeight = group.Key.CeilHeight; - - if(group.Key.FloorHeight > maxSelectedFloorHeight) - maxSelectedFloorHeight = group.Key.FloorHeight; + if(group.Key.CeilHeight < minSelectedHeight) minSelectedHeight = group.Key.CeilHeight; + if(group.Key.FloorHeight > maxSelectedFloorHeight) maxSelectedFloorHeight = group.Key.FloorHeight; } if(withinSelection) @@ -2376,18 +2354,13 @@ namespace CodeImp.DoomBuilder.BuilderModes } else { - //get next lower ceiling or floor from surrounding unselected sectors - foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) + // Get next lower ceiling or floor from surrounding unselected sectors + foreach(Sector s in BuilderModesTools.GetSectorsAround(ceilings.Keys)) { - foreach(Sidedef side in group.Key.Sidedefs) - { - if(side.Other == null || ceilings.ContainsKey(side.Other.Sector) || floors.ContainsKey(side.Other.Sector)) - continue; - if(side.Other.Sector.CeilHeight > targetCeilingHeight && side.Other.Sector.CeilHeight < minSelectedHeight && side.Other.Sector.CeilHeight >= maxSelectedFloorHeight) - targetCeilingHeight = side.Other.Sector.CeilHeight; - else if(side.Other.Sector.FloorHeight > targetCeilingHeight && side.Other.Sector.FloorHeight < minSelectedHeight && side.Other.Sector.FloorHeight >= side.Sector.FloorHeight) - targetCeilingHeight = side.Other.Sector.FloorHeight; - } + if(s.CeilHeight > targetCeilingHeight && s.CeilHeight < minSelectedHeight && s.CeilHeight >= maxSelectedFloorHeight) + targetCeilingHeight = s.CeilHeight; + else if(s.FloorHeight > targetCeilingHeight && s.FloorHeight < minSelectedHeight && s.FloorHeight >= maxSelectedFloorHeight) + targetCeilingHeight = s.FloorHeight; } } @@ -2399,7 +2372,7 @@ namespace CodeImp.DoomBuilder.BuilderModes if(ceilings.Count > 0 && targetCeilingHeight == int.MinValue) { - //drop to highest floor? + // Drop to highest floor? if(!withinSelection && maxSelectedFloorHeight < minSelectedHeight) { targetCeilingHeight = maxSelectedFloorHeight; @@ -2420,7 +2393,7 @@ namespace CodeImp.DoomBuilder.BuilderModes //APPLY VALUES: PreAction(UndoGroup.SectorHeightChange); - //change floor height + // Change floor height if(floors.Count > 0) { foreach(KeyValuePair<Sector, VisualFloor> group in floors) @@ -2430,7 +2403,7 @@ namespace CodeImp.DoomBuilder.BuilderModes } } - //change ceiling height + // Change ceiling height if(ceilings.Count > 0) { foreach(KeyValuePair<Sector, VisualCeiling> group in ceilings) @@ -2447,7 +2420,7 @@ namespace CodeImp.DoomBuilder.BuilderModes { if(vt.Thing.Sector == null) continue; SectorData sd = GetSectorData(vt.Thing.Sector); - vt.OnMove(new Vector3D(vt.Thing.Position, BuilderModesTools.GetLowerThingZ(sd, vt.Thing.Position, vt.Thing.Height, vt.Info.AbsoluteZ, vt.Info.Hangs))); + vt.OnMove(new Vector3D(vt.Thing.Position, BuilderModesTools.GetLowerThingZ(this, sd, vt))); } }