From a495a2f5280cc8632d75b6148a0d0c36af8766e9 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Tue, 3 Feb 2015 08:30:33 +0000 Subject: [PATCH] Split IFinalizedRenderable from Renderable to remove mutable structs. --- OpenRA.Game/Graphics/Renderable.cs | 10 +- .../Graphics/SelectionBarsRenderable.cs | 4 +- .../Graphics/SelectionBoxRenderable.cs | 4 +- OpenRA.Game/Graphics/TargetLineRenderable.cs | 4 +- OpenRA.Game/Graphics/UISpriteRenderable.cs | 4 +- OpenRA.Game/Graphics/WorldRenderer.cs | 19 +- OpenRA.Mods.Common/Graphics/BeamRenderable.cs | 4 +- .../Graphics/ContrailRenderable.cs | 4 +- .../Graphics/RangeCircleRenderable.cs | 4 +- OpenRA.Mods.Common/Graphics/TextRenderable.cs | 4 +- .../Graphics/VoxelRenderable.cs | 180 +++++++++--------- OpenRA.Mods.RA/Graphics/TeslaZapRenderable.cs | 20 +- 12 files changed, 134 insertions(+), 127 deletions(-) diff --git a/OpenRA.Game/Graphics/Renderable.cs b/OpenRA.Game/Graphics/Renderable.cs index 2dc089f326..0f8c1ba420 100644 --- a/OpenRA.Game/Graphics/Renderable.cs +++ b/OpenRA.Game/Graphics/Renderable.cs @@ -28,12 +28,16 @@ namespace OpenRA.Graphics IRenderable OffsetBy(WVec offset); IRenderable AsDecoration(); - void BeforeRender(WorldRenderer wr); + IFinalizedRenderable PrepareRender(WorldRenderer wr); + } + + public interface IFinalizedRenderable + { void Render(WorldRenderer wr); void RenderDebugGeometry(WorldRenderer wr); } - public struct SpriteRenderable : IRenderable + public struct SpriteRenderable : IRenderable, IFinalizedRenderable { public static readonly IEnumerable None = new IRenderable[0].AsEnumerable(); @@ -74,7 +78,7 @@ namespace OpenRA.Graphics return wr.ScreenPxPosition(pos) + wr.ScreenPxOffset(offset) - (0.5f * scale * sprite.Size).ToInt2(); } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { Game.Renderer.WorldSpriteRenderer.DrawSprite(sprite, ScreenPosition(wr), palette, sprite.Size * scale); diff --git a/OpenRA.Game/Graphics/SelectionBarsRenderable.cs b/OpenRA.Game/Graphics/SelectionBarsRenderable.cs index 2c4711ecf7..7ac0e5cb88 100644 --- a/OpenRA.Game/Graphics/SelectionBarsRenderable.cs +++ b/OpenRA.Game/Graphics/SelectionBarsRenderable.cs @@ -14,7 +14,7 @@ using OpenRA.Traits; namespace OpenRA.Graphics { - public struct SelectionBarsRenderable : IRenderable + public struct SelectionBarsRenderable : IRenderable, IFinalizedRenderable { readonly WPos pos; readonly Actor actor; @@ -135,7 +135,7 @@ namespace OpenRA.Graphics } } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { if (!actor.IsInWorld || actor.IsDead) diff --git a/OpenRA.Game/Graphics/SelectionBoxRenderable.cs b/OpenRA.Game/Graphics/SelectionBoxRenderable.cs index 2f44fe1041..98f7cb5e25 100644 --- a/OpenRA.Game/Graphics/SelectionBoxRenderable.cs +++ b/OpenRA.Game/Graphics/SelectionBoxRenderable.cs @@ -14,7 +14,7 @@ using OpenRA.Traits; namespace OpenRA.Graphics { - public struct SelectionBoxRenderable : IRenderable + public struct SelectionBoxRenderable : IRenderable, IFinalizedRenderable { readonly WPos pos; readonly float scale; @@ -45,7 +45,7 @@ namespace OpenRA.Graphics public IRenderable OffsetBy(WVec vec) { return new SelectionBoxRenderable(pos + vec, bounds, scale, color); } public IRenderable AsDecoration() { return this; } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { var screenPos = wr.ScreenPxPosition(pos); diff --git a/OpenRA.Game/Graphics/TargetLineRenderable.cs b/OpenRA.Game/Graphics/TargetLineRenderable.cs index 0231d390e4..1bfd44a0b5 100644 --- a/OpenRA.Game/Graphics/TargetLineRenderable.cs +++ b/OpenRA.Game/Graphics/TargetLineRenderable.cs @@ -16,7 +16,7 @@ using OpenRA.Traits; namespace OpenRA.Graphics { - public struct TargetLineRenderable : IRenderable + public struct TargetLineRenderable : IRenderable, IFinalizedRenderable { readonly IEnumerable waypoints; readonly Color color; @@ -39,7 +39,7 @@ namespace OpenRA.Graphics public IRenderable OffsetBy(WVec vec) { return new TargetLineRenderable(waypoints.Select(w => w + vec), color); } public IRenderable AsDecoration() { return this; } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { if (!waypoints.Any()) diff --git a/OpenRA.Game/Graphics/UISpriteRenderable.cs b/OpenRA.Game/Graphics/UISpriteRenderable.cs index 3bd66d967d..5029953806 100644 --- a/OpenRA.Game/Graphics/UISpriteRenderable.cs +++ b/OpenRA.Game/Graphics/UISpriteRenderable.cs @@ -14,7 +14,7 @@ using System.Linq; namespace OpenRA.Graphics { - public struct UISpriteRenderable : IRenderable + public struct UISpriteRenderable : IRenderable, IFinalizedRenderable { readonly Sprite sprite; readonly int2 screenPos; @@ -46,7 +46,7 @@ namespace OpenRA.Graphics public IRenderable OffsetBy(WVec vec) { return this; } public IRenderable AsDecoration() { return this; } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { Game.Renderer.SpriteRenderer.DrawSprite(sprite, screenPos, palette, sprite.Size * scale); diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index e79e551af9..4f3ba875d4 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -77,7 +77,7 @@ namespace OpenRA.Graphics public void AddPalette(string name, ImmutablePalette pal, bool allowModifiers) { palette.AddPalette(name, pal, allowModifiers); } public void ReplacePalette(string name, IPalette pal) { palette.ReplacePalette(name, pal); palettes[name].Palette = pal; } - List GenerateRenderables() + List GenerateRenderables() { var actors = World.ScreenMap.ActorsInBox(Viewport.TopLeft, Viewport.BottomRight) .Append(World.WorldActor); @@ -100,12 +100,9 @@ namespace OpenRA.Graphics if (World.OrderGenerator != null) effectRenderables = effectRenderables.Concat(World.OrderGenerator.RenderAfterWorld(this, World)); - // Iterating via foreach copies the structs, so enumerate by index - var renderables = worldRenderables.Concat(effectRenderables).ToList(); - Game.Renderer.WorldVoxelRenderer.BeginFrame(); - for (var i = 0; i < renderables.Count; i++) - renderables[i].BeforeRender(this); + var renderables = worldRenderables.Concat(effectRenderables) + .Select(r => r.PrepareRender(this)).ToList(); Game.Renderer.WorldVoxelRenderer.EndFrame(); return renderables; @@ -146,21 +143,19 @@ namespace OpenRA.Graphics var overlayRenderables = World.Selection.Actors.Where(a => !a.Destroyed) .SelectMany(a => a.TraitsImplementing()) - .SelectMany(t => t.RenderAfterWorld(this)) - .ToList(); + .SelectMany(t => t.RenderAfterWorld(this)); Game.Renderer.WorldVoxelRenderer.BeginFrame(); - for (var i = 0; i < overlayRenderables.Count; i++) - overlayRenderables[i].BeforeRender(this); + var finalOverlayRenderables = overlayRenderables.Select(r => r.PrepareRender(this)); Game.Renderer.WorldVoxelRenderer.EndFrame(); // HACK: Keep old grouping behaviour - foreach (var g in overlayRenderables.GroupBy(prs => prs.GetType())) + foreach (var g in finalOverlayRenderables.GroupBy(prs => prs.GetType())) foreach (var r in g) r.Render(this); if (devTrait.Value != null && devTrait.Value.ShowDebugGeometry) - foreach (var g in overlayRenderables.GroupBy(prs => prs.GetType())) + foreach (var g in finalOverlayRenderables.GroupBy(prs => prs.GetType())) foreach (var r in g) r.RenderDebugGeometry(this); diff --git a/OpenRA.Mods.Common/Graphics/BeamRenderable.cs b/OpenRA.Mods.Common/Graphics/BeamRenderable.cs index fcb9113cc8..4be2adee13 100644 --- a/OpenRA.Mods.Common/Graphics/BeamRenderable.cs +++ b/OpenRA.Mods.Common/Graphics/BeamRenderable.cs @@ -13,7 +13,7 @@ using OpenRA.Graphics; namespace OpenRA.Mods.Common.Graphics { - public struct BeamRenderable : IRenderable + public struct BeamRenderable : IRenderable, IFinalizedRenderable { readonly WPos pos; readonly int zOffset; @@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Graphics public IRenderable OffsetBy(WVec vec) { return new BeamRenderable(pos + vec, zOffset, length, width, color); } public IRenderable AsDecoration() { return this; } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { var wlr = Game.Renderer.WorldLineRenderer; diff --git a/OpenRA.Mods.Common/Graphics/ContrailRenderable.cs b/OpenRA.Mods.Common/Graphics/ContrailRenderable.cs index c4f315aa64..25c86a915e 100644 --- a/OpenRA.Mods.Common/Graphics/ContrailRenderable.cs +++ b/OpenRA.Mods.Common/Graphics/ContrailRenderable.cs @@ -14,7 +14,7 @@ using OpenRA.Graphics; namespace OpenRA.Mods.Common.Graphics { - public struct ContrailRenderable : IRenderable + public struct ContrailRenderable : IRenderable, IFinalizedRenderable { public int Length { get { return trail.Length; } } @@ -54,7 +54,7 @@ namespace OpenRA.Mods.Common.Graphics public IRenderable OffsetBy(WVec vec) { return new ContrailRenderable(world, trail.Select(pos => pos + vec).ToArray(), next, length, skip, color, zOffset); } public IRenderable AsDecoration() { return this; } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { // Need at least 4 points to smooth the contrail over diff --git a/OpenRA.Mods.Common/Graphics/RangeCircleRenderable.cs b/OpenRA.Mods.Common/Graphics/RangeCircleRenderable.cs index 6961899bfc..3c3cd02363 100644 --- a/OpenRA.Mods.Common/Graphics/RangeCircleRenderable.cs +++ b/OpenRA.Mods.Common/Graphics/RangeCircleRenderable.cs @@ -13,7 +13,7 @@ using OpenRA.Graphics; namespace OpenRA.Mods.Common.Graphics { - public struct RangeCircleRenderable : IRenderable + public struct RangeCircleRenderable : IRenderable, IFinalizedRenderable { readonly WPos centerPosition; readonly WRange radius; @@ -42,7 +42,7 @@ namespace OpenRA.Mods.Common.Graphics public IRenderable OffsetBy(WVec vec) { return new RangeCircleRenderable(centerPosition + vec, radius, zOffset, color, contrastColor); } public IRenderable AsDecoration() { return this; } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { var wlr = Game.Renderer.WorldLineRenderer; diff --git a/OpenRA.Mods.Common/Graphics/TextRenderable.cs b/OpenRA.Mods.Common/Graphics/TextRenderable.cs index 03e09e26f7..09f816c1e1 100644 --- a/OpenRA.Mods.Common/Graphics/TextRenderable.cs +++ b/OpenRA.Mods.Common/Graphics/TextRenderable.cs @@ -14,7 +14,7 @@ using OpenRA.Graphics; namespace OpenRA.Mods.Common.Graphics { - public struct TextRenderable : IRenderable + public struct TextRenderable : IRenderable, IFinalizedRenderable { readonly SpriteFont font; readonly WPos pos; @@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.Graphics public IRenderable OffsetBy(WVec vec) { return new TextRenderable(font, pos + vec, zOffset, color, text); } public IRenderable AsDecoration() { return this; } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void Render(WorldRenderer wr) { var screenPos = wr.Viewport.Zoom * (wr.ScreenPosition(pos) - wr.Viewport.TopLeft.ToFloat2()) - 0.5f * font.Measure(text).ToFloat2(); diff --git a/OpenRA.Mods.Common/Graphics/VoxelRenderable.cs b/OpenRA.Mods.Common/Graphics/VoxelRenderable.cs index 2ff1381906..95b3e4c16f 100644 --- a/OpenRA.Mods.Common/Graphics/VoxelRenderable.cs +++ b/OpenRA.Mods.Common/Graphics/VoxelRenderable.cs @@ -29,9 +29,6 @@ namespace OpenRA.Mods.Common.Graphics readonly PaletteReference shadowPalette; readonly float scale; - // Generated at render-time - VoxelRenderProxy renderProxy; - public VoxelRenderable( IEnumerable voxels, WPos pos, int zOffset, WRot camera, float scale, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, @@ -48,7 +45,6 @@ namespace OpenRA.Mods.Common.Graphics this.palette = color; this.normalsPalette = normals; this.shadowPalette = shadow; - this.renderProxy = null; } public WPos Pos { get { return pos; } } @@ -93,99 +89,111 @@ namespace OpenRA.Mods.Common.Graphics // This will need generalizing once we support TS/RA2 terrain static readonly float[] GroundNormal = new float[] { 0, 0, 1, 1 }; - public void BeforeRender(WorldRenderer wr) + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { - var draw = voxels.Where(v => v.DisableFunc == null || !v.DisableFunc()); - - renderProxy = Game.Renderer.WorldVoxelRenderer.RenderAsync( - wr, draw, camera, scale, GroundNormal, lightSource, - lightAmbientColor, lightDiffuseColor, - palette, normalsPalette, shadowPalette); + return new FinalizedVoxelRenderable(wr, this); } - public void Render(WorldRenderer wr) + struct FinalizedVoxelRenderable : IFinalizedRenderable { - // TODO: This is a temporary workaround until we have a proper ramp-aware height calculation - var groundPos = wr.World.Map.CenterOfCell(wr.World.Map.CellContaining(pos)); + readonly VoxelRenderable voxel; + readonly VoxelRenderProxy renderProxy; - var ts = Game.ModData.Manifest.TileSize; - var groundZ = ts.Height * (groundPos.Z - pos.Z) / 1024f; - - var pxOrigin = wr.ScreenPosition(pos); - var shadowOrigin = pxOrigin - groundZ * (new float2(renderProxy.ShadowDirection, 1)); - - var psb = renderProxy.ProjectedShadowBounds; - var sa = shadowOrigin + psb[0]; - var sb = shadowOrigin + psb[2]; - var sc = shadowOrigin + psb[1]; - var sd = shadowOrigin + psb[3]; - Game.Renderer.WorldRgbaSpriteRenderer.DrawSprite(renderProxy.ShadowSprite, sa, sb, sc, sd); - Game.Renderer.WorldRgbaSpriteRenderer.DrawSprite(renderProxy.Sprite, pxOrigin - 0.5f * renderProxy.Sprite.Size); - } - - public void RenderDebugGeometry(WorldRenderer wr) - { - var pxOrigin = wr.ScreenPosition(pos); - var groundZ = 0.5f * (pxOrigin.Y - wr.ScreenZPosition(pos, 0)); - var shadowOrigin = pxOrigin - groundZ * (new float2(renderProxy.ShadowDirection, 1)); - - // Draw sprite rect - var offset = pxOrigin + renderProxy.Sprite.Offset - 0.5f * renderProxy.Sprite.Size; - Game.Renderer.WorldLineRenderer.DrawRect(offset, offset + renderProxy.Sprite.Size, Color.Red); - - // Draw transformed shadow sprite rect - var c = Color.Purple; - var psb = renderProxy.ProjectedShadowBounds; - Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[1], shadowOrigin + psb[3], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[3], shadowOrigin + psb[0], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[0], shadowOrigin + psb[2], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[2], shadowOrigin + psb[1], c, c); - - // Draw voxel bounding box - var draw = voxels.Where(v => v.DisableFunc == null || !v.DisableFunc()); - var scaleTransform = Util.ScaleMatrix(scale, scale, scale); - var cameraTransform = Util.MakeFloatMatrix(camera.AsMatrix()); - - foreach (var v in draw) + public FinalizedVoxelRenderable(WorldRenderer wr, VoxelRenderable voxel) { - var bounds = v.Voxel.Bounds(v.FrameFunc()); - var worldTransform = v.RotationFunc().Reverse().Aggregate(scaleTransform, - (x, y) => Util.MatrixMultiply(x, Util.MakeFloatMatrix(y.AsMatrix()))); + this.voxel = voxel; + var draw = voxel.voxels.Where(v => v.DisableFunc == null || !v.DisableFunc()); - var pxOffset = wr.ScreenVector(v.OffsetFunc()); - var pxPos = pxOrigin + new float2(pxOffset[0], pxOffset[1]); - var screenTransform = Util.MatrixMultiply(cameraTransform, worldTransform); - DrawBoundsBox(pxPos, screenTransform, bounds, Color.Yellow); - } - } - - static readonly uint[] CornerXIndex = new uint[] { 0, 0, 0, 0, 3, 3, 3, 3 }; - static readonly uint[] CornerYIndex = new uint[] { 1, 1, 4, 4, 1, 1, 4, 4 }; - static readonly uint[] CornerZIndex = new uint[] { 2, 5, 2, 5, 2, 5, 2, 5 }; - static void DrawBoundsBox(float2 pxPos, float[] transform, float[] bounds, Color c) - { - var corners = new float2[8]; - for (var i = 0; i < 8; i++) - { - var vec = new float[] { bounds[CornerXIndex[i]], bounds[CornerYIndex[i]], bounds[CornerZIndex[i]], 1 }; - var screen = Util.MatrixVectorMultiply(transform, vec); - corners[i] = pxPos + new float2(screen[0], screen[1]); + renderProxy = Game.Renderer.WorldVoxelRenderer.RenderAsync( + wr, draw, voxel.camera, voxel.scale, VoxelRenderable.GroundNormal, voxel.lightSource, + voxel.lightAmbientColor, voxel.lightDiffuseColor, + voxel.palette, voxel.normalsPalette, voxel.shadowPalette); } - Game.Renderer.WorldLineRenderer.DrawLine(corners[0], corners[1], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(corners[1], corners[3], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(corners[3], corners[2], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(corners[2], corners[0], c, c); + public void Render(WorldRenderer wr) + { + // TODO: This is a temporary workaround until we have a proper ramp-aware height calculation + var groundPos = wr.World.Map.CenterOfCell(wr.World.Map.CellContaining(voxel.pos)); - Game.Renderer.WorldLineRenderer.DrawLine(corners[4], corners[5], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(corners[5], corners[7], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(corners[7], corners[6], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(corners[6], corners[4], c, c); + var ts = Game.ModData.Manifest.TileSize; + var groundZ = ts.Height * (groundPos.Z - voxel.pos.Z) / 1024f; - Game.Renderer.WorldLineRenderer.DrawLine(corners[0], corners[4], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(corners[1], corners[5], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(corners[2], corners[6], c, c); - Game.Renderer.WorldLineRenderer.DrawLine(corners[3], corners[7], c, c); + var pxOrigin = wr.ScreenPosition(voxel.pos); + var shadowOrigin = pxOrigin - groundZ * (new float2(renderProxy.ShadowDirection, 1)); + + var psb = renderProxy.ProjectedShadowBounds; + var sa = shadowOrigin + psb[0]; + var sb = shadowOrigin + psb[2]; + var sc = shadowOrigin + psb[1]; + var sd = shadowOrigin + psb[3]; + Game.Renderer.WorldRgbaSpriteRenderer.DrawSprite(renderProxy.ShadowSprite, sa, sb, sc, sd); + Game.Renderer.WorldRgbaSpriteRenderer.DrawSprite(renderProxy.Sprite, pxOrigin - 0.5f * renderProxy.Sprite.Size); + } + + public void RenderDebugGeometry(WorldRenderer wr) + { + var pxOrigin = wr.ScreenPosition(voxel.pos); + var groundZ = 0.5f * (pxOrigin.Y - wr.ScreenZPosition(voxel.pos, 0)); + var shadowOrigin = pxOrigin - groundZ * (new float2(renderProxy.ShadowDirection, 1)); + + // Draw sprite rect + var offset = pxOrigin + renderProxy.Sprite.Offset - 0.5f * renderProxy.Sprite.Size; + Game.Renderer.WorldLineRenderer.DrawRect(offset, offset + renderProxy.Sprite.Size, Color.Red); + + // Draw transformed shadow sprite rect + var c = Color.Purple; + var psb = renderProxy.ProjectedShadowBounds; + Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[1], shadowOrigin + psb[3], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[3], shadowOrigin + psb[0], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[0], shadowOrigin + psb[2], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(shadowOrigin + psb[2], shadowOrigin + psb[1], c, c); + + // Draw voxel bounding box + var draw = voxel.voxels.Where(v => v.DisableFunc == null || !v.DisableFunc()); + var scaleTransform = Util.ScaleMatrix(voxel.scale, voxel.scale, voxel.scale); + var cameraTransform = Util.MakeFloatMatrix(voxel.camera.AsMatrix()); + + foreach (var v in draw) + { + var bounds = v.Voxel.Bounds(v.FrameFunc()); + var worldTransform = v.RotationFunc().Reverse().Aggregate(scaleTransform, + (x, y) => Util.MatrixMultiply(x, Util.MakeFloatMatrix(y.AsMatrix()))); + + var pxOffset = wr.ScreenVector(v.OffsetFunc()); + var pxPos = pxOrigin + new float2(pxOffset[0], pxOffset[1]); + var screenTransform = Util.MatrixMultiply(cameraTransform, worldTransform); + DrawBoundsBox(pxPos, screenTransform, bounds, Color.Yellow); + } + } + + static readonly uint[] CornerXIndex = new uint[] { 0, 0, 0, 0, 3, 3, 3, 3 }; + static readonly uint[] CornerYIndex = new uint[] { 1, 1, 4, 4, 1, 1, 4, 4 }; + static readonly uint[] CornerZIndex = new uint[] { 2, 5, 2, 5, 2, 5, 2, 5 }; + static void DrawBoundsBox(float2 pxPos, float[] transform, float[] bounds, Color c) + { + var corners = new float2[8]; + for (var i = 0; i < 8; i++) + { + var vec = new float[] { bounds[CornerXIndex[i]], bounds[CornerYIndex[i]], bounds[CornerZIndex[i]], 1 }; + var screen = Util.MatrixVectorMultiply(transform, vec); + corners[i] = pxPos + new float2(screen[0], screen[1]); + } + + Game.Renderer.WorldLineRenderer.DrawLine(corners[0], corners[1], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(corners[1], corners[3], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(corners[3], corners[2], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(corners[2], corners[0], c, c); + + Game.Renderer.WorldLineRenderer.DrawLine(corners[4], corners[5], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(corners[5], corners[7], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(corners[7], corners[6], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(corners[6], corners[4], c, c); + + Game.Renderer.WorldLineRenderer.DrawLine(corners[0], corners[4], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(corners[1], corners[5], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(corners[2], corners[6], c, c); + Game.Renderer.WorldLineRenderer.DrawLine(corners[3], corners[7], c, c); + } } } } diff --git a/OpenRA.Mods.RA/Graphics/TeslaZapRenderable.cs b/OpenRA.Mods.RA/Graphics/TeslaZapRenderable.cs index 8afabe99b2..ec3dde5945 100644 --- a/OpenRA.Mods.RA/Graphics/TeslaZapRenderable.cs +++ b/OpenRA.Mods.RA/Graphics/TeslaZapRenderable.cs @@ -15,7 +15,7 @@ using OpenRA.Graphics; namespace OpenRA.Mods.RA.Graphics { - struct TeslaZapRenderable : IRenderable + struct TeslaZapRenderable : IRenderable, IFinalizedRenderable { static int[][] steps = new[] { @@ -38,7 +38,7 @@ namespace OpenRA.Mods.RA.Graphics WPos cachedPos; WVec cachedLength; - IEnumerable cache; + IEnumerable cache; public TeslaZapRenderable(WPos pos, int zOffset, WVec length, string image, int brightZaps, int dimZaps, string palette) { @@ -52,7 +52,7 @@ namespace OpenRA.Mods.RA.Graphics cachedPos = WPos.Zero; cachedLength = WVec.Zero; - cache = new IRenderable[] { }; + cache = new IFinalizedRenderable[] { }; } public WPos Pos { get { return pos; } } @@ -67,7 +67,7 @@ namespace OpenRA.Mods.RA.Graphics public IRenderable OffsetBy(WVec vec) { return new TeslaZapRenderable(pos + vec, zOffset, length, image, brightZaps, dimZaps, palette); } public IRenderable AsDecoration() { return this; } - public void BeforeRender(WorldRenderer wr) { } + public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } public void RenderDebugGeometry(WorldRenderer wr) { } public void Render(WorldRenderer wr) { @@ -77,7 +77,7 @@ namespace OpenRA.Mods.RA.Graphics cache.Do(c => c.Render(wr)); } - public IEnumerable GenerateRenderables(WorldRenderer wr) + public IEnumerable GenerateRenderables(WorldRenderer wr) { var bright = wr.World.Map.SequenceProvider.GetSequence(image, "bright"); var dim = wr.World.Map.SequenceProvider.GetSequence(image, "dim"); @@ -93,13 +93,13 @@ namespace OpenRA.Mods.RA.Graphics yield return z; } - static IEnumerable DrawZapWandering(WorldRenderer wr, float2 from, float2 to, Sequence s, string pal) + static IEnumerable DrawZapWandering(WorldRenderer wr, float2 from, float2 to, Sequence s, string pal) { var z = float2.Zero; /* hack */ var dist = to - from; var norm = (1f / dist.Length) * new float2(-dist.Y, dist.X); - var renderables = new List(); + var renderables = new List(); if (Game.CosmeticRandom.Next(2) != 0) { var p1 = from + (1 / 3f) * dist + WRange.FromPDF(Game.CosmeticRandom, 2).Range * dist.Length / 4096 * norm; @@ -120,12 +120,12 @@ namespace OpenRA.Mods.RA.Graphics return renderables; } - static IEnumerable DrawZap(WorldRenderer wr, float2 from, float2 to, Sequence s, out float2 p, string palette) + static IEnumerable DrawZap(WorldRenderer wr, float2 from, float2 to, Sequence s, out float2 p, string palette) { var dist = to - from; var q = new float2(-dist.Y, dist.X); var c = -float2.Dot(from, q); - var rs = new List(); + var rs = new List(); var z = from; var pal = wr.Palette(palette); @@ -135,7 +135,7 @@ namespace OpenRA.Mods.RA.Graphics .MinBy(t => Math.Abs(float2.Dot(z + new float2(t[0], t[1]), q) + c)); var pos = wr.Position((z + new float2(step[2], step[3])).ToInt2()); - rs.Add(new SpriteRenderable(s.GetSprite(step[4]), pos, WVec.Zero, 0, pal, 1f, true)); + rs.Add(new SpriteRenderable(s.GetSprite(step[4]), pos, WVec.Zero, 0, pal, 1f, true).PrepareRender(wr)); z += new float2(step[0], step[1]); if (rs.Count >= 1000)