From 1aebf9857c73fddf5e78937570bbc31d0e85b9c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Mail=C3=A4nder?= Date: Fri, 19 Feb 2016 19:57:16 +0100 Subject: [PATCH] Add support for only rendering effects inside screen bounds --- OpenRA.Game/Effects/IEffect.cs | 3 ++ OpenRA.Game/Graphics/WorldRenderer.cs | 8 +++- .../Primitives/SpatiallyPartitioned.cs | 9 +++- OpenRA.Game/Traits/World/ScreenMap.cs | 44 +++++++++++++++++++ OpenRA.Game/World.cs | 13 ++++++ 5 files changed, 74 insertions(+), 3 deletions(-) diff --git a/OpenRA.Game/Effects/IEffect.cs b/OpenRA.Game/Effects/IEffect.cs index 1353449306..c37a4fea75 100644 --- a/OpenRA.Game/Effects/IEffect.cs +++ b/OpenRA.Game/Effects/IEffect.cs @@ -20,5 +20,8 @@ namespace OpenRA.Effects IEnumerable Render(WorldRenderer r); } + // Identifier interface for effects that are added to ScreenMap + public interface ISpatiallyPartitionable { } + public interface IEffectAboveShroud { IEnumerable RenderAboveShroud(WorldRenderer wr); } } diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 2881aa6e22..bea22d0c79 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -110,7 +110,13 @@ namespace OpenRA.Graphics if (World.OrderGenerator != null) worldRenderables = worldRenderables.Concat(World.OrderGenerator.Render(this, World)); - worldRenderables = worldRenderables.Concat(World.Effects.SelectMany(e => e.Render(this))); + // Unpartitioned effects + worldRenderables = worldRenderables.Concat(World.UnpartitionedEffects.SelectMany(e => e.Render(this))); + + // Partitioned, currently on-screen effects + var effectRenderables = World.ScreenMap.EffectsInBox(Viewport.TopLeft, Viewport.BottomRight); + worldRenderables = worldRenderables.Concat(effectRenderables.SelectMany(e => e.Render(this))); + worldRenderables = worldRenderables.OrderBy(RenderableScreenZPositionComparisonKey); Game.Renderer.WorldModelRenderer.BeginFrame(); diff --git a/OpenRA.Game/Primitives/SpatiallyPartitioned.cs b/OpenRA.Game/Primitives/SpatiallyPartitioned.cs index ccd49b6737..3e6683b485 100644 --- a/OpenRA.Game/Primitives/SpatiallyPartitioned.cs +++ b/OpenRA.Game/Primitives/SpatiallyPartitioned.cs @@ -51,10 +51,15 @@ namespace OpenRA.Primitives MutateBins(item, itemBounds[item] = bounds, addItem); } - public void Remove(T item) + public bool Remove(T item) { - MutateBins(item, itemBounds[item], removeItem); + Rectangle bounds; + if (!itemBounds.TryGetValue(item, out bounds)) + return false; + + MutateBins(item, bounds, removeItem); itemBounds.Remove(item); + return true; } Dictionary BinAt(int row, int col) diff --git a/OpenRA.Game/Traits/World/ScreenMap.cs b/OpenRA.Game/Traits/World/ScreenMap.cs index c0819348f5..a72ad2496b 100644 --- a/OpenRA.Game/Traits/World/ScreenMap.cs +++ b/OpenRA.Game/Traits/World/ScreenMap.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Linq; +using OpenRA.Effects; using OpenRA.Graphics; using OpenRA.Primitives; @@ -33,6 +34,7 @@ namespace OpenRA.Traits readonly Func actorIsInWorld = a => a.IsInWorld; readonly Cache> partitionedFrozenActors; readonly SpatiallyPartitioned partitionedActors; + readonly SpatiallyPartitioned partitionedEffects; WorldRenderer worldRenderer; public ScreenMap(World world, ScreenMapInfo info) @@ -43,6 +45,7 @@ namespace OpenRA.Traits partitionedFrozenActors = new Cache>( _ => new SpatiallyPartitioned(width, height, info.BinSize)); partitionedActors = new SpatiallyPartitioned(width, height, info.BinSize); + partitionedEffects = new SpatiallyPartitioned(width, height, info.BinSize); } public void WorldLoaded(World w, WorldRenderer wr) { worldRenderer = wr; } @@ -88,6 +91,37 @@ namespace OpenRA.Traits partitionedActors.Remove(a); } + public void Add(IEffect effect, WPos position, Size size) + { + var screenPos = worldRenderer.ScreenPxPosition(position); + var screenBounds = new Rectangle(screenPos.X - size.Width / 2, screenPos.Y - size.Height / 2, size.Width, size.Height); + partitionedEffects.Add(effect, screenBounds); + } + + public void Add(IEffect effect, WPos position, Sprite sprite) + { + var size = new Size((int)sprite.Size.X, (int)sprite.Size.Y); + Add(effect, position, size); + } + + public void Update(IEffect effect, WPos position, Size size) + { + var screenPos = worldRenderer.ScreenPxPosition(position); + var screenBounds = new Rectangle(screenPos.X - size.Width / 2, screenPos.Y - size.Height / 2, size.Width, size.Height); + partitionedEffects.Update(effect, screenBounds); + } + + public void Update(IEffect effect, WPos position, Sprite sprite) + { + var size = new Size((int)sprite.Size.X, (int)sprite.Size.Y); + Update(effect, position, size); + } + + public void Remove(IEffect e) + { + partitionedEffects.Remove(e); + } + public IEnumerable FrozenActorsAt(Player viewer, int2 worldPx) { if (viewer == null) @@ -120,6 +154,11 @@ namespace OpenRA.Traits return ActorsInBox(RectWithCorners(a, b)); } + public IEnumerable EffectsInBox(int2 a, int2 b) + { + return partitionedEffects.InBox(RectWithCorners(a, b)); + } + public IEnumerable ActorsInBox(Rectangle r) { return partitionedActors.InBox(r).Where(actorIsInWorld); @@ -130,6 +169,11 @@ namespace OpenRA.Traits return FrozenActorsInBox(p, RectWithCorners(a, b)); } + public IEnumerable EffectsInBox(Rectangle r) + { + return partitionedEffects.InBox(r); + } + public IEnumerable FrozenActorsInBox(Player p, Rectangle r) { if (p == null) diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 349605b610..8127fe9ddb 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -30,6 +30,7 @@ namespace OpenRA internal readonly TraitDictionary TraitDict = new TraitDictionary(); readonly SortedDictionary actors = new SortedDictionary(); readonly List effects = new List(); + readonly List unpartitionedEffects = new List(); readonly List syncedEffects = new List(); readonly Queue> frameEndActions = new Queue>(); @@ -285,6 +286,11 @@ namespace OpenRA public void Add(IEffect e) { effects.Add(e); + + var sp = e as ISpatiallyPartitionable; + if (sp == null) + unpartitionedEffects.Add(e); + var se = e as ISync; if (se != null) syncedEffects.Add(se); @@ -293,6 +299,11 @@ namespace OpenRA public void Remove(IEffect e) { effects.Remove(e); + + var sp = e as ISpatiallyPartitionable; + if (sp == null) + unpartitionedEffects.Remove(e); + var se = e as ISync; if (se != null) syncedEffects.Remove(se); @@ -301,6 +312,7 @@ namespace OpenRA public void RemoveAll(Predicate predicate) { effects.RemoveAll(predicate); + unpartitionedEffects.RemoveAll(e => predicate((IEffect)e)); syncedEffects.RemoveAll(e => predicate((IEffect)e)); } @@ -361,6 +373,7 @@ namespace OpenRA public IEnumerable Actors { get { return actors.Values; } } public IEnumerable Effects { get { return effects; } } + public IEnumerable UnpartitionedEffects { get { return unpartitionedEffects; } } public IEnumerable SyncedEffects { get { return syncedEffects; } } public Actor GetActorById(uint actorId)