diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index 07bf276e91..a7d62c1f58 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -24,7 +24,7 @@ namespace OpenRA.Graphics theater = wr.Theater; mapTiles = world.Map.MapTiles.Value; - terrain = new TerrainSpriteLayer(world, wr, theater.Sheet, BlendMode.Alpha, wr.Palette("terrain")); + terrain = new TerrainSpriteLayer(world, wr, theater.Sheet, BlendMode.Alpha, wr.Palette("terrain"), true); foreach (var cell in world.Map.AllCells) UpdateCell(cell); diff --git a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs index 14d8b1ba4e..bf828bbc36 100644 --- a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs +++ b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs @@ -25,6 +25,7 @@ namespace OpenRA.Graphics readonly Vertex[] vertices; readonly HashSet dirtyRows = new HashSet(); readonly int rowStride; + readonly bool restrictToBounds; readonly WorldRenderer worldRenderer; readonly Map map; @@ -34,9 +35,10 @@ namespace OpenRA.Graphics float paletteIndex; - public TerrainSpriteLayer(World world, WorldRenderer wr, Sheet sheet, BlendMode blendMode, PaletteReference palette) + public TerrainSpriteLayer(World world, WorldRenderer wr, Sheet sheet, BlendMode blendMode, PaletteReference palette, bool restrictToBounds) { worldRenderer = wr; + this.restrictToBounds = restrictToBounds; this.sheet = sheet; this.blendMode = blendMode; paletteIndex = palette.TextureIndex; @@ -92,7 +94,7 @@ namespace OpenRA.Graphics public void Draw(Viewport viewport) { - var cells = viewport.VisibleCells; + var cells = restrictToBounds ? viewport.VisibleCellsInsideBounds : viewport.AllVisibleCells; // Only draw the rows that are visible. var firstRow = cells.MapCoords.TopLeft.V; diff --git a/OpenRA.Game/Graphics/Viewport.cs b/OpenRA.Game/Graphics/Viewport.cs index cf5b369780..1b5ab1444f 100644 --- a/OpenRA.Game/Graphics/Viewport.cs +++ b/OpenRA.Game/Graphics/Viewport.cs @@ -53,6 +53,9 @@ namespace OpenRA.Graphics CellRegion cells; bool cellsDirty = true; + CellRegion allCells; + bool allCellsDirty = true; + float zoom = 1f; public float Zoom { @@ -66,6 +69,7 @@ namespace OpenRA.Graphics zoom = value; viewportSize = (1f / zoom * new float2(Game.Renderer.Resolution)).ToInt2(); cellsDirty = true; + allCellsDirty = true; } } @@ -187,6 +191,7 @@ namespace OpenRA.Graphics { CenterLocation = worldRenderer.ScreenPxPosition(pos).Clamp(mapBounds); cellsDirty = true; + allCellsDirty = true; } public void Scroll(float2 delta, bool ignoreBorders) @@ -194,6 +199,7 @@ namespace OpenRA.Graphics // Convert scroll delta from world-px to viewport-px CenterLocation += (1f / Zoom * delta).ToInt2(); cellsDirty = true; + allCellsDirty = true; if (!ignoreBorders) CenterLocation = CenterLocation.Clamp(mapBounds); @@ -207,8 +213,8 @@ namespace OpenRA.Graphics { // Visible rectangle in world coordinates (expanded to the corners of the cells) var map = worldRenderer.World.Map; - var ctl = map.CenterOfCell(VisibleCells.TopLeft) - new WVec(512, 512, 0); - var cbr = map.CenterOfCell(VisibleCells.BottomRight) + new WVec(512, 512, 0); + var ctl = map.CenterOfCell(VisibleCellsInsideBounds.TopLeft) - new WVec(512, 512, 0); + var cbr = map.CenterOfCell(VisibleCellsInsideBounds.BottomRight) + new WVec(512, 512, 0); // Convert to screen coordinates var tl = WorldToViewPx(worldRenderer.ScreenPxPosition(ctl - new WVec(0, 0, ctl.Z))).Clamp(ScreenClip); @@ -220,42 +226,61 @@ namespace OpenRA.Graphics } } - public CellRegion VisibleCells + CellRegion CalculateVisibleCells(bool insideBounds) + { + var map = worldRenderer.World.Map; + var wtl = worldRenderer.Position(TopLeft); + var wbr = worldRenderer.Position(BottomRight); + + // Map editor shows the full map (including the area outside the regular bounds) + Func clamp = map.Clamp; + if (!insideBounds) + clamp = map.MapTiles.Value.Clamp; + + // Due to diamond tile staggering, we need to adjust the top-left bounds outwards by half a cell. + if (map.TileShape == TileShape.Diamond) + wtl -= new WVec(512, 512, 0); + + // Visible rectangle in map coordinates. + var dy = map.TileShape == TileShape.Diamond ? 512 : 1024; + var ctl = new MPos(wtl.X / 1024, wtl.Y / dy); + var cbr = new MPos(wbr.X / 1024, wbr.Y / dy); + + var tl = clamp(ctl).ToCPos(map.TileShape); + + // Also need to account for height of cells in rows below the bottom. + var heightPadding = map.TileShape == TileShape.Diamond ? 3 : 0; + var br = clamp(new MPos(cbr.U, cbr.V + heightPadding + maxGroundHeight / 2 + 1)).ToCPos(map.TileShape); + + return new CellRegion(map.TileShape, tl, br); + } + + public CellRegion VisibleCellsInsideBounds { get { if (cellsDirty) { - var map = worldRenderer.World.Map; - var wtl = worldRenderer.Position(TopLeft); - var wbr = worldRenderer.Position(BottomRight); - - // Map editor shows the full map (including the area outside the regular bounds) - Func clamp = map.Clamp; - if (worldRenderer.World.Type == WorldType.Editor) - clamp = map.MapTiles.Value.Clamp; - - // Due to diamond tile staggering, we need to adjust the top-left bounds outwards by half a cell. - if (map.TileShape == TileShape.Diamond) - wtl -= new WVec(512, 512, 0); - - // Visible rectangle in map coordinates. - var dy = map.TileShape == TileShape.Diamond ? 512 : 1024; - var ctl = new MPos(wtl.X / 1024, wtl.Y / dy); - var cbr = new MPos(wbr.X / 1024, wbr.Y / dy); - - var tl = clamp(ctl).ToCPos(map.TileShape); - - // Also need to account for height of cells in rows below the bottom. - var heightPadding = map.TileShape == TileShape.Diamond ? 3 : 0; - var br = clamp(new MPos(cbr.U, cbr.V + heightPadding + maxGroundHeight / 2 + 1)).ToCPos(map.TileShape); - - cells = new CellRegion(map.TileShape, tl, br); + cells = CalculateVisibleCells(worldRenderer.World.Type != WorldType.Editor); cellsDirty = false; } return cells; } } + + public CellRegion AllVisibleCells + { + get + { + if (allCellsDirty) + { + allCells = CalculateVisibleCells(false); + allCellsDirty = false; + } + + return allCells; + } + } } } \ No newline at end of file diff --git a/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs index f90f549466..2c9a49922e 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs @@ -146,7 +146,7 @@ namespace OpenRA.Mods.Common.Traits Dirty.Clear(); - foreach (var uv in wr.Viewport.VisibleCells.MapCoords) + foreach (var uv in wr.Viewport.VisibleCellsInsideBounds.MapCoords) { var t = Tiles[uv]; if (t.Sprite != null) diff --git a/OpenRA.Mods.Common/Traits/World/PathfinderDebugOverlay.cs b/OpenRA.Mods.Common/Traits/World/PathfinderDebugOverlay.cs index 3fff22448b..102cc53000 100644 --- a/OpenRA.Mods.Common/Traits/World/PathfinderDebugOverlay.cs +++ b/OpenRA.Mods.Common/Traits/World/PathfinderDebugOverlay.cs @@ -66,7 +66,7 @@ namespace OpenRA.Mods.Common.Traits var layer = pair.Value; // Only render quads in viewing range: - foreach (var cell in wr.Viewport.VisibleCells) + foreach (var cell in wr.Viewport.VisibleCellsInsideBounds) { if (layer[cell] <= 0) continue; diff --git a/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs b/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs index 13198a388d..a6d2c9e329 100644 --- a/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs @@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Traits public void Render(WorldRenderer wr) { var shroudObscured = world.ShroudObscuresTest; - foreach (var uv in wr.Viewport.VisibleCells.MapCoords) + foreach (var uv in wr.Viewport.VisibleCellsInsideBounds.MapCoords) { if (shroudObscured(uv)) continue; diff --git a/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs b/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs index c08c3a010e..6a32bfdad9 100644 --- a/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs +++ b/OpenRA.Mods.Common/Traits/World/ShroudRenderer.cs @@ -189,8 +189,8 @@ namespace OpenRA.Mods.Common.Traits if (fogSprites.Any(s => s.BlendMode != fogBlend)) throw new InvalidDataException("Fog sprites must all use the same blend mode."); - shroudLayer = new TerrainSpriteLayer(w, wr, shroudSheet, shroudBlend, wr.Palette(info.ShroudPalette)); - fogLayer = new TerrainSpriteLayer(w, wr, fogSheet, fogBlend, wr.Palette(info.FogPalette)); + shroudLayer = new TerrainSpriteLayer(w, wr, shroudSheet, shroudBlend, wr.Palette(info.ShroudPalette), false); + fogLayer = new TerrainSpriteLayer(w, wr, fogSheet, fogBlend, wr.Palette(info.FogPalette), false); } Edges GetEdges(MPos uv, Func isVisible) diff --git a/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs b/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs index 90b80645b3..0711a7f1c2 100644 --- a/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs @@ -144,7 +144,7 @@ namespace OpenRA.Mods.Common.Traits foreach (var kv in tiles) { - if (!wr.Viewport.VisibleCells.Contains(kv.Key)) + if (!wr.Viewport.VisibleCellsInsideBounds.Contains(kv.Key)) continue; if (world.ShroudObscures(kv.Key)) diff --git a/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs b/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs index d6fe424846..391ed0045d 100644 --- a/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs +++ b/OpenRA.Mods.Common/Traits/World/TerrainGeometryOverlay.cs @@ -57,7 +57,7 @@ namespace OpenRA.Mods.Common.Traits var colors = wr.World.TileSet.HeightDebugColors; var mouseCell = wr.Viewport.ViewToWorld(Viewport.LastMousePos).ToMPos(wr.World.Map); - foreach (var uv in wr.Viewport.VisibleCells.MapCoords) + foreach (var uv in wr.Viewport.VisibleCellsInsideBounds.MapCoords) { var height = (int)map.MapHeight.Value[uv]; var tile = map.MapTiles.Value[uv]; diff --git a/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs b/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs index 50ef007822..39f4481a93 100644 --- a/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs +++ b/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs @@ -64,7 +64,7 @@ namespace OpenRA.Mods.D2k.Traits foreach (var kv in tiles) { - if (!wr.Viewport.VisibleCells.Contains(kv.Key)) + if (!wr.Viewport.VisibleCellsInsideBounds.Contains(kv.Key)) continue; if (wr.World.ShroudObscures(kv.Key))