diff --git a/OpenRA.Game/Graphics/Model.cs b/OpenRA.Game/Graphics/Model.cs index a05ffe6d41..5fb0dc4639 100644 --- a/OpenRA.Game/Graphics/Model.cs +++ b/OpenRA.Game/Graphics/Model.cs @@ -10,6 +10,7 @@ #endregion using System; +using System.Drawing; using OpenRA.FileSystem; namespace OpenRA.Graphics @@ -23,6 +24,9 @@ namespace OpenRA.Graphics float[] Size { get; } float[] Bounds(uint frame); ModelRenderData RenderData(uint section); + + /// Returns the smallest rectangle that covers all rotations of all frames in a model + Rectangle AggregateBounds { get; } } public struct ModelRenderData diff --git a/OpenRA.Game/Graphics/ModelAnimation.cs b/OpenRA.Game/Graphics/ModelAnimation.cs index 8470470e44..768d26b08c 100644 --- a/OpenRA.Game/Graphics/ModelAnimation.cs +++ b/OpenRA.Game/Graphics/ModelAnimation.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Drawing; namespace OpenRA.Graphics { @@ -33,6 +34,19 @@ namespace OpenRA.Graphics ShowShadow = showshadow; } + public Rectangle ScreenBounds(WPos pos, WorldRenderer wr, float scale) + { + var r = Model.AggregateBounds; + var offset = OffsetFunc != null ? OffsetFunc() : WVec.Zero; + var xy = wr.ScreenPxPosition(pos) + wr.ScreenPxOffset(offset); + + return Rectangle.FromLTRB( + xy.X + (int)(r.Left * scale), + xy.Y + (int)(r.Top * scale), + xy.X + (int)(r.Right * scale), + xy.Y + (int)(r.Bottom * scale)); + } + public bool IsVisible { get diff --git a/OpenRA.Mods.Cnc/Graphics/Voxel.cs b/OpenRA.Mods.Cnc/Graphics/Voxel.cs index 14e2d98f43..a04cdbc9ce 100644 --- a/OpenRA.Mods.Cnc/Graphics/Voxel.cs +++ b/OpenRA.Mods.Cnc/Graphics/Voxel.cs @@ -10,6 +10,7 @@ #endregion using System; +using System.Drawing; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Cnc.FileFormats; @@ -125,5 +126,33 @@ namespace OpenRA.Mods.Cnc.Graphics return ret; } + + public Rectangle AggregateBounds + { + get + { + // Corner offsets + var ix = new uint[] { 0, 0, 0, 0, 3, 3, 3, 3 }; + var iy = new uint[] { 1, 1, 4, 4, 1, 1, 4, 4 }; + var iz = new uint[] { 2, 5, 2, 5, 2, 5, 2, 5 }; + + // Calculate the smallest sphere that covers the model limbs + var rSquared = 0f; + for (var f = 0U; f < frames; f++) + { + var bounds = Bounds(f); + for (var i = 0; i < 8; i++) + { + var x = bounds[ix[i]]; + var y = bounds[iy[i]]; + var z = bounds[iz[i]]; + rSquared = Math.Max(rSquared, x * x + y * y + z * z); + } + } + + var r = (int)Math.Sqrt(rSquared) + 1; + return Rectangle.FromLTRB(-r, -r, r, r); + } + } } }