Simple MapEntity visibility culling (structures outside the camera view or items with nothing to render aren't drawn)

Could be optimized further, but already gives a pretty nice performance boost
This commit is contained in:
Regalis
2016-11-30 21:09:11 +02:00
parent 42ff4a0d9a
commit a2442bfcb8
5 changed files with 61 additions and 41 deletions
+5
View File
@@ -888,6 +888,11 @@ namespace Barotrauma
} }
} }
public override bool IsVisible(Rectangle worldView)
{
return drawableComponents.Count > 0 || body == null || body.Enabled;
}
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true) public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{ {
if (!Visible) return; if (!Visible) return;
+5
View File
@@ -319,6 +319,11 @@ namespace Barotrauma
mapEntityList.Insert(i, this); mapEntityList.Insert(i, this);
} }
public virtual bool IsVisible(Rectangle worldView)
{
return true;
}
public virtual void Draw(SpriteBatch spriteBatch, bool editing, bool back=true) {} public virtual void Draw(SpriteBatch spriteBatch, bool editing, bool back=true) {}
public virtual void DrawDamage(SpriteBatch spriteBatch, Effect damageEffect) {} public virtual void DrawDamage(SpriteBatch spriteBatch, Effect damageEffect) {}
+11 -2
View File
@@ -475,6 +475,15 @@ namespace Barotrauma
if (convexHulls != null) convexHulls.ForEach(x => x.Remove()); if (convexHulls != null) convexHulls.ForEach(x => x.Remove());
} }
public override bool IsVisible(Rectangle WorldView)
{
Rectangle worldRect = WorldRect;
if (worldRect.X > WorldView.Right || worldRect.Right < WorldView.X) return false;
if (worldRect.Y < WorldView.Y - WorldView.Height || worldRect.Y - worldRect.Height > WorldView.Y) return false;
return true;
}
public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true) public override void Draw(SpriteBatch spriteBatch, bool editing, bool back = true)
{ {
@@ -514,7 +523,7 @@ namespace Barotrauma
spriteBatch, spriteBatch,
new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)), new Vector2(rect.X + drawOffset.X, -(rect.Y + drawOffset.Y)),
new Vector2(rect.Width, rect.Height), new Vector2(rect.Width, rect.Height),
Vector2.Zero, color, Point.Zero); color, Point.Zero);
} }
} }
@@ -553,7 +562,7 @@ namespace Barotrauma
spriteBatch, spriteBatch,
new Vector2(sections[i].rect.X + drawOffset.X, -(sections[i].rect.Y + drawOffset.Y)), new Vector2(sections[i].rect.X + drawOffset.X, -(sections[i].rect.Y + drawOffset.Y)),
new Vector2(sections[i].rect.Width, sections[i].rect.Height), new Vector2(sections[i].rect.Width, sections[i].rect.Height),
Vector2.Zero, color, color,
textureOffset, depth); textureOffset, depth);
} }
} }
+5 -4
View File
@@ -289,10 +289,10 @@ namespace Barotrauma
} }
//drawing ---------------------------------------------------- //drawing ----------------------------------------------------
public static void CullEntities(Camera cam) public static void CullEntities(Camera cam)
{ {
List<Submarine> visibleSubs = new List<Submarine>(); HashSet<Submarine> visibleSubs = new HashSet<Submarine>();
foreach (Submarine sub in Submarine.Loaded) foreach (Submarine sub in Submarine.Loaded)
{ {
Rectangle worldBorders = new Rectangle( Rectangle worldBorders = new Rectangle(
@@ -301,19 +301,20 @@ namespace Barotrauma
sub.Borders.Width + 1000, sub.Borders.Width + 1000,
sub.Borders.Height + 1000); sub.Borders.Height + 1000);
if (Submarine.RectsOverlap(worldBorders, cam.WorldView)) if (Submarine.RectsOverlap(worldBorders, cam.WorldView))
{ {
visibleSubs.Add(sub); visibleSubs.Add(sub);
} }
} }
Rectangle worldView = cam.WorldView;
visibleEntities = new List<MapEntity>(); visibleEntities = new List<MapEntity>();
foreach (MapEntity me in MapEntity.mapEntityList) foreach (MapEntity me in MapEntity.mapEntityList)
{ {
if (me.Submarine == null || visibleSubs.Contains(me.Submarine)) if (me.Submarine == null || visibleSubs.Contains(me.Submarine))
{ {
visibleEntities.Add(me); if (me.IsVisible(worldView)) visibleEntities.Add(me);
} }
} }
} }
+35 -35
View File
@@ -223,79 +223,79 @@ namespace Barotrauma
DrawTiled(spriteBatch, pos, targetSize, Vector2.Zero, color); DrawTiled(spriteBatch, pos, targetSize, Vector2.Zero, color);
} }
public void DrawTiled(SpriteBatch spriteBatch, Vector2 pos, Vector2 targetSize, Vector2 startOffset, Color color, Point offset, float? overrideDepth = null) public void DrawTiled(SpriteBatch spriteBatch, Vector2 pos, Vector2 targetSize, Color color, Point offset, float? overrideDepth = null)
{ {
//how many times the texture needs to be drawn on the x-axis //how many times the texture needs to be drawn on the x-axis
int xTiles = (int)Math.Ceiling((targetSize.X + startOffset.X) / sourceRect.Width); int xTiles = (int)Math.Ceiling(targetSize.X / sourceRect.Width);
//how many times the texture needs to be drawn on the y-axis //how many times the texture needs to be drawn on the y-axis
int yTiles = (int)Math.Ceiling((targetSize.Y + startOffset.Y) / sourceRect.Height); int yTiles = (int)Math.Ceiling(targetSize.Y / sourceRect.Height);
float depth = overrideDepth == null ? this.depth : (float)overrideDepth; float depth = overrideDepth == null ? this.depth : (float)overrideDepth;
Rectangle texPerspective = sourceRect; Rectangle texPerspective = sourceRect;
texPerspective.Location += offset; texPerspective.Location += offset;
while (texPerspective.Location.X >= sourceRect.X + sourceRect.Width) while (texPerspective.X >= sourceRect.Right)
texPerspective.X = sourceRect.X + (texPerspective.Location.X - (sourceRect.X + sourceRect.Width)); texPerspective.X = sourceRect.X + (texPerspective.X - sourceRect.Right);
while (texPerspective.Location.Y >= sourceRect.Y + sourceRect.Height) while (texPerspective.Y >= sourceRect.Bottom)
texPerspective.Y = sourceRect.Y + (texPerspective.Location.Y - (sourceRect.Y + sourceRect.Height)); texPerspective.Y = sourceRect.Y + (texPerspective.Y - sourceRect.Bottom);
texPerspective.Width = (int)Math.Min(targetSize.X, sourceRect.Width); float top = pos.Y;
texPerspective.Height = (int)Math.Min(targetSize.Y, sourceRect.Height); texPerspective.Height = (int)Math.Min(targetSize.Y, sourceRect.Height);
for (int y = 0; y < yTiles; y++) for (int y = 0; y < yTiles; y++)
{ {
var movementY = texPerspective.Height;
texPerspective.Height = Math.Min((int)(targetSize.Y - texPerspective.Height * y), texPerspective.Height);
float left = pos.X;
texPerspective.Width = (int)Math.Min(targetSize.X, sourceRect.Width); texPerspective.Width = (int)Math.Min(targetSize.X, sourceRect.Width);
texPerspective.Height = (int)Math.Min(targetSize.Y, sourceRect.Height);
float top = pos.Y + texPerspective.Height * y;
for (int x = 0; x < xTiles; x++) for (int x = 0; x < xTiles; x++)
{ {
float left = pos.X + texPerspective.Width * x;
texPerspective.Width = Math.Min((int)(targetSize.X - texPerspective.Width * x), texPerspective.Width);
texPerspective.Height = Math.Min((int)(targetSize.Y - texPerspective.Height * y), texPerspective.Height);
var movementX = texPerspective.Width; var movementX = texPerspective.Width;
var movementY = texPerspective.Height; texPerspective.Width = Math.Min((int)(targetSize.X - texPerspective.Width * x), texPerspective.Width);
if (texPerspective.Right > sourceRect.Right) if (texPerspective.Right > sourceRect.Right)
{ {
int diff = texPerspective.Right - sourceRect.Right;
if (effects.HasFlag(SpriteEffects.FlipHorizontally)) if (effects.HasFlag(SpriteEffects.FlipHorizontally))
{ {
int diff = (texPerspective.X + texPerspective.Width) - (sourceRect.Right); spriteBatch.Draw(texture,
new Vector2(left, top),
spriteBatch.Draw(texture, new Rectangle(sourceRect.X, texPerspective.Y, diff, texPerspective.Height),
new Vector2(left, top),
new Rectangle(sourceRect.X, texPerspective.Y, diff, texPerspective.Height),
color, rotation, Vector2.Zero, 1.0f, effects, depth); color, rotation, Vector2.Zero, 1.0f, effects, depth);
texPerspective.Width -= diff; texPerspective.Width -= diff;
left += diff; left += diff;
} }
else else
{ {
float diff = (texPerspective.X + texPerspective.Width) - (sourceRect.X + sourceRect.Width);
texPerspective.Width -= (int)diff; texPerspective.Width -= (int)diff;
spriteBatch.Draw(texture, spriteBatch.Draw(texture,
new Vector2(left + texPerspective.Width, top), new Vector2(left + texPerspective.Width, top),
new Rectangle(sourceRect.X, texPerspective.Y, (int)diff, texPerspective.Height), new Rectangle(sourceRect.X, texPerspective.Y, (int)diff, texPerspective.Height),
color, rotation, Vector2.Zero, 1.0f, effects, depth); color, rotation, Vector2.Zero, 1.0f, effects, depth);
} }
} }
else if (texPerspective.Bottom > sourceRect.Bottom) else if (texPerspective.Bottom > sourceRect.Bottom)
{ {
int diff = (texPerspective.Bottom) - (sourceRect.Bottom); int diff = texPerspective.Bottom - sourceRect.Bottom;
texPerspective.Height -= diff; texPerspective.Height -= diff;
spriteBatch.Draw(texture, spriteBatch.Draw(texture,
new Vector2(left, top + texPerspective.Height), new Vector2(left, top + texPerspective.Height),
new Rectangle(texPerspective.X, sourceRect.Y, texPerspective.Width, diff), new Rectangle(texPerspective.X, sourceRect.Y, texPerspective.Width, diff),
color, rotation, Vector2.Zero, 1.0f, effects, depth); color, rotation, Vector2.Zero, 1.0f, effects, depth);
} }
spriteBatch.Draw(texture, new Vector2(left, top), texPerspective, color, rotation, Vector2.Zero, 1.0f, effects, depth); spriteBatch.Draw(texture, new Vector2(left, top), texPerspective, color, rotation, Vector2.Zero, 1.0f, effects, depth);
if (texPerspective.X + movementX >= sourceRect.Right) if (texPerspective.X + movementX >= sourceRect.Right) texPerspective.X = sourceRect.X;
texPerspective.X = sourceRect.X; left += movementX;
if (texPerspective.Y + movementY >= sourceRect.Y + sourceRect.Height)
texPerspective.Y = sourceRect.Y;
} }
if (texPerspective.Y + movementY >= sourceRect.Bottom) texPerspective.Y = sourceRect.Y;
top += movementY;
} }
} }