From 2e4279664fb27f13d76aa9f8ee0a04ffc4c534e8 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Thu, 8 Oct 2009 21:53:59 +1300 Subject: [PATCH] line rendering - selection box!! --- OpenRa.Game/Graphics/LineRenderer.cs | 66 +++++++++++++++++++++++++ OpenRa.Game/Graphics/Region.cs | 1 + OpenRa.Game/Graphics/Renderer.cs | 48 +++++++++++------- OpenRa.Game/Graphics/SpriteRenderer.cs | 19 +++---- OpenRa.Game/Graphics/TerrainRenderer.cs | 15 +++--- OpenRa.Game/Graphics/WorldRenderer.cs | 31 +++++++++++- OpenRa.Game/MainWindow.cs | 2 +- OpenRa.Game/OpenRa.Game.csproj | 1 + OpenRa.Game/Unit.cs | 9 ++-- line.fx | 54 ++++++++++++++++++++ diffuse.fx => sprite.fx | 2 + 11 files changed, 206 insertions(+), 42 deletions(-) create mode 100644 OpenRa.Game/Graphics/LineRenderer.cs create mode 100644 line.fx rename diffuse.fx => sprite.fx (93%) diff --git a/OpenRa.Game/Graphics/LineRenderer.cs b/OpenRa.Game/Graphics/LineRenderer.cs new file mode 100644 index 0000000000..181072c856 --- /dev/null +++ b/OpenRa.Game/Graphics/LineRenderer.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Ijw.DirectX; +using System.Runtime.InteropServices; +using System.Drawing; + +namespace OpenRa.Game.Graphics +{ + class LineRenderer + { + Renderer renderer; + FvfVertexBuffer vertexBuffer; + IndexBuffer indexBuffer; /* kindof a waste of space, but the GPU likes indexing, oh well */ + + const int linesPerBatch = 1024; + + Vertex[] vertices = new Vertex[2 * linesPerBatch]; + ushort[] indices = new ushort[2 * linesPerBatch]; + int lines = 0; + int nv = 0, ni = 0; + + public LineRenderer(Renderer renderer) + { + this.renderer = renderer; + vertexBuffer = new FvfVertexBuffer(renderer.Device, vertices.Length, Vertex.Format); + indexBuffer = new IndexBuffer(renderer.Device, indices.Length); + } + + public void Flush() + { + if (lines > 0) + { + renderer.LineShader.Render(() => + { + vertexBuffer.SetData(vertices); + indexBuffer.SetData(indices); + renderer.DrawBatch(vertexBuffer, indexBuffer, + nv, ni / 2, null, PrimitiveType.LineList); + }); + + nv = 0; ni = 0; + lines = 0; + } + } + + public void DrawLine(float2 start, float2 end, Color startColor, Color endColor) + { + indices[ni++] = (ushort)nv; + + vertices[nv++] = new Vertex(start, + new float2(startColor.R / 255.0f, startColor.G / 255.0f), + new float2(startColor.B / 255.0f, startColor.A / 255.0f)); + + indices[ni++] = (ushort)nv; + + vertices[nv++] = new Vertex(end, + new float2(endColor.R / 255.0f, endColor.G / 255.0f), + new float2(endColor.B / 255.0f, endColor.A / 255.0f)); + + if (++lines >= linesPerBatch) + Flush(); + } + } +} diff --git a/OpenRa.Game/Graphics/Region.cs b/OpenRa.Game/Graphics/Region.cs index 0f66d54723..274833d624 100644 --- a/OpenRa.Game/Graphics/Region.cs +++ b/OpenRa.Game/Graphics/Region.cs @@ -14,6 +14,7 @@ namespace OpenRa.Game.Graphics get { return location + new int2( (int)viewport.Location.X, (int)viewport.Location.Y ); } // WTF HACK HACK HACK } + public int2 Position { get { return location; } } public readonly float2 Size; Action drawFunction; diff --git a/OpenRa.Game/Graphics/Renderer.cs b/OpenRa.Game/Graphics/Renderer.cs index b6d40272ee..47af610e6e 100644 --- a/OpenRa.Game/Graphics/Renderer.cs +++ b/OpenRa.Game/Graphics/Renderer.cs @@ -9,13 +9,12 @@ namespace OpenRa.Game.Graphics class Renderer { readonly GraphicsDevice device; - readonly Shader shader; - - const string shaderName = "diffuse.fx"; + public Shader SpriteShader { get; private set; } /* note: shared shader params */ + public Shader LineShader { get; private set; } public void SetPalette(HardwarePalette hp) { - shader.SetValue("Palette", hp.Texture); + SpriteShader.SetValue("Palette", hp.Texture); } public Renderer(Control host, Size resolution, bool windowed) @@ -24,8 +23,10 @@ namespace OpenRa.Game.Graphics device = GraphicsDevice.Create(host, resolution.Width, resolution.Height, windowed, false); - shader = new Shader(device, FileSystem.Open(shaderName)); - shader.Quality = ShaderQuality.Low; + SpriteShader = new Shader(device, FileSystem.Open("sprite.fx")); + SpriteShader.Quality = ShaderQuality.Low; + LineShader = new Shader(device, FileSystem.Open("line.fx")); + LineShader.Quality = ShaderQuality.High; } public GraphicsDevice Device { get { return device; } } @@ -34,9 +35,10 @@ namespace OpenRa.Game.Graphics { device.Begin(); - shader.SetValue("Scroll", scroll); - shader.SetValue("r1", r1); - shader.SetValue("r2", r2); + SpriteShader.SetValue("Scroll", scroll); + SpriteShader.SetValue("r1", r1); + SpriteShader.SetValue("r2", r2); + SpriteShader.Commit(); } public void EndFrame() @@ -45,24 +47,32 @@ namespace OpenRa.Game.Graphics device.Present(); } - public void DrawWithShader(ShaderQuality quality, Action task) - { - shader.Quality = quality; - shader.Render(() => task()); - } - public void DrawBatch(FvfVertexBuffer vertices, IndexBuffer indices, - Range vertexRange, Range indexRange, Texture texture) + Range vertexRange, Range indexRange, Texture texture, PrimitiveType type) where T : struct { - shader.SetValue("DiffuseTexture", texture); - shader.Commit(); + SpriteShader.SetValue("DiffuseTexture", texture); + SpriteShader.Commit(); vertices.Bind(0); indices.Bind(); - device.DrawIndexedPrimitives(PrimitiveType.TriangleList, + device.DrawIndexedPrimitives(type, vertexRange, indexRange); } + + public void DrawBatch(FvfVertexBuffer vertices, IndexBuffer indices, + int vertexPool, int numPrimitives, Texture texture, PrimitiveType type) + where T : struct + { + SpriteShader.SetValue("DiffuseTexture", texture); + SpriteShader.Commit(); + + vertices.Bind(0); + indices.Bind(); + + device.DrawIndexedPrimitives(type, + vertexPool, numPrimitives); + } } } diff --git a/OpenRa.Game/Graphics/SpriteRenderer.cs b/OpenRa.Game/Graphics/SpriteRenderer.cs index 8b3d3433c5..0b9ae75e2d 100644 --- a/OpenRa.Game/Graphics/SpriteRenderer.cs +++ b/OpenRa.Game/Graphics/SpriteRenderer.cs @@ -36,15 +36,16 @@ namespace OpenRa.Game.Graphics { if (sprites > 0) { - renderer.DrawWithShader(quality, () => - { - vertexBuffer.SetData(vertices); - indexBuffer.SetData(indices); - renderer.DrawBatch(vertexBuffer, indexBuffer, - new Range(0, nv), - new Range(0, ni), - currentSheet.Texture); - }); + renderer.SpriteShader.Quality = quality; + renderer.SpriteShader.Render(() => + { + vertexBuffer.SetData(vertices); + indexBuffer.SetData(indices); + renderer.DrawBatch(vertexBuffer, indexBuffer, + new Range(0, nv), + new Range(0, ni), + currentSheet.Texture, PrimitiveType.TriangleList); + }); nv = 0; ni = 0; currentSheet = null; diff --git a/OpenRa.Game/Graphics/TerrainRenderer.cs b/OpenRa.Game/Graphics/TerrainRenderer.cs index 079be6f0ce..c99896932d 100644 --- a/OpenRa.Game/Graphics/TerrainRenderer.cs +++ b/OpenRa.Game/Graphics/TerrainRenderer.cs @@ -16,10 +16,12 @@ namespace OpenRa.Game.Graphics Renderer renderer; Map map; + Viewport viewport; public TerrainRenderer(Renderer renderer, Map map, Viewport viewport) { this.renderer = renderer; + this.viewport = viewport; region = Region.Create(viewport, DockStyle.Left, viewport.Width - 128, Draw, null ); viewport.AddRegion(region); this.map = map; @@ -61,7 +63,7 @@ namespace OpenRa.Game.Graphics int visibleRows = (int)(region.Size.Y / 24.0f + 2); - int firstRow = (int)(region.Location.Y / 24.0f); + int firstRow = (int)((region.Position.Y + viewport.Location.Y) / 24.0f); int lastRow = firstRow + visibleRows; if (lastRow < 0 || firstRow > map.Height) @@ -70,11 +72,12 @@ namespace OpenRa.Game.Graphics if (firstRow < 0) firstRow = 0; if (lastRow > map.Height) lastRow = map.Height; - renderer.DrawWithShader(ShaderQuality.Low, () => - renderer.DrawBatch(vertexBuffer, indexBuffer, - new Range(verticesPerRow * firstRow, verticesPerRow * lastRow), - new Range(indicesPerRow * firstRow, indicesPerRow * lastRow), - terrainSheet.Texture)); + renderer.SpriteShader.Quality = ShaderQuality.Low; + renderer.SpriteShader.Render(() => + renderer.DrawBatch(vertexBuffer, indexBuffer, + new Range(verticesPerRow * firstRow, verticesPerRow * lastRow), + new Range(indicesPerRow * firstRow, indicesPerRow * lastRow), + terrainSheet.Texture, PrimitiveType.TriangleList)); } } } diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs index 8c610790bd..89619fc8d3 100644 --- a/OpenRa.Game/Graphics/WorldRenderer.cs +++ b/OpenRa.Game/Graphics/WorldRenderer.cs @@ -6,6 +6,7 @@ namespace OpenRa.Game.Graphics class WorldRenderer { public readonly SpriteRenderer spriteRenderer; + public readonly LineRenderer lineRenderer; public readonly World world; public readonly Region region; public readonly UiOverlay uiOverlay; @@ -21,13 +22,15 @@ namespace OpenRa.Game.Graphics world.game.viewport.AddRegion(region); spriteRenderer = new SpriteRenderer(renderer, true); + lineRenderer = new LineRenderer(renderer); uiOverlay = new UiOverlay(spriteRenderer, world.game); this.world = world; } public void Draw() { - var rect = new RectangleF(region.Location.ToPointF(), region.Size.ToSizeF()); + var rect = new RectangleF((region.Position + world.game.viewport.Location).ToPointF(), + region.Size.ToSizeF()); foreach (Actor a in world.Actors) { @@ -46,7 +49,33 @@ namespace OpenRa.Game.Graphics } } + uiOverlay.Draw(); + spriteRenderer.Flush(); + + var selectedUnit = world.game.controller.orderGenerator as Unit; + if (selectedUnit != null) + { + var center = selectedUnit.CenterLocation; + var size = selectedUnit.SelectedSize; + + var xy = center - 0.5f * size; + var XY = center + 0.5f * size; + var Xy = new float2( XY.X, xy.Y ); + var xY = new float2( xy.X, XY.Y ); + + lineRenderer.DrawLine(xy, xy + new float2(4, 0), Color.White, Color.White); + lineRenderer.DrawLine(xy, xy + new float2(0, 4), Color.White, Color.White); + lineRenderer.DrawLine(Xy, Xy + new float2(-4, 0), Color.White, Color.White); + lineRenderer.DrawLine(Xy, Xy + new float2(0, 4), Color.White, Color.White); + + lineRenderer.DrawLine(xY, xY + new float2(4, 0), Color.White, Color.White); + lineRenderer.DrawLine(xY, xY + new float2(0, -4), Color.White, Color.White); + lineRenderer.DrawLine(XY, XY + new float2(-4, 0), Color.White, Color.White); + lineRenderer.DrawLine(XY, XY + new float2(0, -4), Color.White, Color.White); + } + + lineRenderer.Flush(); } } } diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index fca1371b5b..5463fb671a 100644 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -40,7 +40,7 @@ namespace OpenRa.Game renderer = new Renderer(this, GetResolution(settings), windowed); SheetBuilder.Initialize( renderer ); - game = new Game( settings.GetValue( "map", "scg11eb.ini" ), renderer, new int2( ClientSize ) ); + game = new Game( settings.GetValue( "map", "scm12ea.ini" ), renderer, new int2( ClientSize ) ); SequenceProvider.ForcePrecache(); diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index a2318f6f1a..62bc5de560 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -75,6 +75,7 @@ + diff --git a/OpenRa.Game/Unit.cs b/OpenRa.Game/Unit.cs index 994429d0ec..32f2b2bed8 100644 --- a/OpenRa.Game/Unit.cs +++ b/OpenRa.Game/Unit.cs @@ -113,6 +113,8 @@ namespace OpenRa.Game var loc = location - 0.5f * s.size; return Pair.New( s, loc.Round() ); } + + public float2 SelectedSize { get { return this.CurrentImages.First().First.size; } } } class TurretedUnit : Unit @@ -129,12 +131,7 @@ namespace OpenRa.Game public override IEnumerable> CurrentImages { - get - { - foreach( var x in base.CurrentImages ) - yield return x; - yield return Centered( turretAnim.Image, CenterLocation ); - } + get { return base.CurrentImages.Concat(new[] { Centered(turretAnim.Image, CenterLocation) }); } } } } diff --git a/line.fx b/line.fx new file mode 100644 index 0000000000..d62fc27cf8 --- /dev/null +++ b/line.fx @@ -0,0 +1,54 @@ +// OpenRA gui lines shader +// Author: C. Forbes +//-------------------------------------------------------- + +shared float2 Scroll; + +shared float2 r1, r2; // matrix elements + +struct VertexIn { + float4 Position: POSITION; + float2 RG: TEXCOORD0; + float2 BA: TEXCOORD1; +}; + +struct VertexOut { + float4 Position: POSITION; + float4 Color: COLOR0; +}; + +struct FragmentIn { + float4 Color: COLOR0; +}; + +VertexOut Simple_vp(VertexIn v) { + VertexOut o; + float2 p = (v.Position.xy - Scroll.xy) * r1 + r2; + o.Position = float4(p.x,p.y,0,1); + o.Color.rg = v.RG.xy; + o.Color.ba = v.BA.xy; + o.Color.a = 1.0f; + return o; +} + +const float2 texelOffset = float2( 0, 1.0f/32.0f ); + +float4 Simple_fp(FragmentIn f) : COLOR0 { + return float4(1,1,1,1); + //return f.Color; +} + +technique high_quality { + pass p0 { + AlphaBlendEnable = false; + ZWriteEnable = false; + ZEnable = false; + CullMode = None; + FillMode = Wireframe; + VertexShader = compile vs_2_0 Simple_vp(); + PixelShader = compile ps_2_0 Simple_fp(); + + SrcBlend = SrcAlpha; + DestBlend = InvSrcAlpha; + } +} diff --git a/diffuse.fx b/sprite.fx similarity index 93% rename from diffuse.fx rename to sprite.fx index 074229581a..c11e8b88df 100644 --- a/diffuse.fx +++ b/sprite.fx @@ -77,6 +77,7 @@ technique low_quality { ZWriteEnable = false; ZEnable = false; CullMode = None; + FillMode = Solid; VertexShader = compile vs_2_0 Simple_vp(); PixelShader = compile ps_2_0 Palette_fp(); } @@ -88,6 +89,7 @@ technique high_quality { ZWriteEnable = false; ZEnable = false; CullMode = None; + FillMode = Solid; VertexShader = compile vs_2_0 Simple_vp(); PixelShader = compile ps_2_0 Palette_fp();