diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 01fa2ed2ba..c459f67846 100644 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -16,20 +16,20 @@ namespace OpenRa.Game class Tree : Actor { - public Tree( TreeReference r, TreeRenderer renderer, Map map ) + public Tree( TreeReference r, TreeCache renderer, Map map ) { location = new PointF(24 * (r.X - map.XOffset), 24 * (r.Y - map.YOffset)); currentImages = new SheetRectangle[] { renderer.GetImage( r.Image ) }; } } - class TreeRenderer + class TreeCache { Dictionary> trees = new Dictionary>(); public readonly Sheet sh; - public TreeRenderer(GraphicsDevice device, Map map, Package package, Palette pal) + public TreeCache(GraphicsDevice device, Map map, Package package, Palette pal) { Size pageSize = new Size( 1024, 512 ); List sheets = new List(); @@ -97,11 +97,12 @@ namespace OpenRa.Game // assumption: its not going to hurt, to draw *all* units. // in reality, 500 tanks is going to hurt our perf. - public void Draw() + public void Draw( Renderer renderer ) { int sprites = 0; List vertices = new List(); List indices = new List(); + Sheet sheet = null; foreach (Actor a in actors) { @@ -124,9 +125,11 @@ namespace OpenRa.Game indices.Add((ushort)(offset + 3)); indices.Add((ushort)(offset + 2)); + sheet = image.sheet; + if (++sprites >= spritesPerBatch) { - DrawBatch(vertices, indices); + DrawBatch(vertices, indices, renderer, sheet); vertices = new List(); indices = new List(); @@ -136,19 +139,22 @@ namespace OpenRa.Game } if (sprites > 0) - DrawBatch(vertices, indices); + DrawBatch(vertices, indices, renderer, sheet); } - void DrawBatch(List vertices, List indices) + void DrawBatch(List vertices, List indices, Renderer renderer, Sheet sheet) { vb.SetData(vertices.ToArray()); ib.SetData(indices.ToArray()); - vb.Bind(0); - ib.Bind(); - - device.DrawIndexedPrimitives(PrimitiveType.TriangleList, - vertices.Count, indices.Count / 3); + renderer.DrawWithShader(ShaderQuality.High, + delegate + { + renderer.DrawBatch(vb, ib, + new Range(0, vertices.Count), + new Range(0, indices.Count), + sheet.texture); + }); } static float U(SheetRectangle s, float u) diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index b3e60fdabf..065ac5398d 100644 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -12,7 +12,8 @@ namespace OpenRa.Game { class MainWindow : Form { - readonly GraphicsDevice device; + readonly Renderer renderer; + readonly Map map; readonly TileSet tileSet; @@ -21,7 +22,6 @@ namespace OpenRa.Game string TileSuffix; const string mapName = "scm12ea.ini"; - const string shaderName = "diffuse.fx"; Dictionary> tileMapping = new Dictionary>(); @@ -30,11 +30,8 @@ namespace OpenRa.Game Dictionary drawBatches = new Dictionary(); - Effect effect; - IntPtr texture, scroll, r1h, r2h; - World world; - TreeRenderer treeRenderer; + TreeCache treeRenderer; void LoadTextures() { @@ -68,10 +65,10 @@ namespace OpenRa.Game } foreach (Sheet s in tempSheets) - s.LoadTexture(device); + s.LoadTexture(renderer.Device); - world = new World(device); - treeRenderer = new TreeRenderer(device, map, TileMix, pal); + world = new World(renderer.Device); + treeRenderer = new TreeCache(renderer.Device, map, TileMix, pal); foreach (TreeReference treeReference in map.Trees) world.Add(new Tree(treeReference, treeRenderer, map)); @@ -123,12 +120,12 @@ namespace OpenRa.Game indexList.Add((ushort)(offset + 2)); } - vertexBuffer = new FvfVertexBuffer(device, vertices.Count, Vertex.Format); + vertexBuffer = new FvfVertexBuffer(renderer.Device, vertices.Count, Vertex.Format); vertexBuffer.SetData(vertices.ToArray()); foreach (KeyValuePair> p in indexMap) { - IndexBuffer indexBuffer = new IndexBuffer(device, p.Value.Count); + IndexBuffer indexBuffer = new IndexBuffer(renderer.Device, p.Value.Count); indexBuffer.SetData(p.Value.ToArray()); drawBatches.Add(p.Key, indexBuffer); } @@ -136,14 +133,9 @@ namespace OpenRa.Game public MainWindow() { - ClientSize = new Size(1280,800); - + renderer = new Renderer(this, new Size(1280, 800), false); Visible = true; - //device = GraphicsDevice.Create(this, ClientSize.Width, ClientSize.Height, true, false); - - device = GraphicsDevice.Create(this, 1280, 800, false, false); - IniFile mapFile = new IniFile(File.OpenRead("../../../" + mapName)); map = new Map(mapFile); @@ -153,13 +145,6 @@ namespace OpenRa.Game LoadTextures(); LoadVertexBuffer(); - - effect = new Effect(device, File.OpenRead("../../../" + shaderName)); - texture = effect.GetHandle("DiffuseTexture"); - scroll = effect.GetHandle("Scroll"); - - r1h = effect.GetHandle("r1"); - r2h = effect.GetHandle("r2"); } internal void Run() @@ -211,67 +196,39 @@ namespace OpenRa.Game PointF r1 = new PointF(2.0f / ClientSize.Width, -2.0f / ClientSize.Height); PointF r2 = new PointF(-1, 1); - device.Begin(); - device.Clear( 0, Surfaces.Color ); - - vertexBuffer.Bind(0); - - effect.Quality = ShaderQuality.Low; - effect.Begin(); - effect.BeginPass(0); - - effect.SetValue(scroll, scrollPos); - effect.SetValue(r1h, r1); - effect.SetValue(r2h, r2); + renderer.BeginFrame(r1, r2, scrollPos); foreach (KeyValuePair batch in drawBatches) + DrawTerrainBatch(batch); + + world.Draw(renderer); + + renderer.EndFrame(); + } + + void DrawTerrainBatch(KeyValuePair batch) + { + int indicesPerRow = map.Width * 6; + int verticesPerRow = map.Width * 4; + + int visibleRows = (int)(ClientSize.Height / 24.0f + 2); + + int firstRow = (int)(scrollPos.Y / 24.0f); + int lastRow = firstRow + visibleRows; + + if (firstRow < 0) firstRow = 0; + + if (lastRow < 0) lastRow = 0; + + if (lastRow > map.Height) lastRow = map.Height; + + Range indexRange = new Range(indicesPerRow * firstRow, indicesPerRow * lastRow); + Range vertexRange = new Range(verticesPerRow * firstRow, verticesPerRow * lastRow); + + renderer.DrawWithShader(ShaderQuality.Low, delegate { - effect.SetTexture(texture, batch.Key.texture); - effect.Commit(); - - batch.Value.Bind(); - - int indicesPerRow = map.Width * 6; - int verticesPerRow = map.Width * 4; - - int visibleRows = (int)(ClientSize.Height / 24.0f + 2); - - int firstRow = (int)(scrollPos.Y / 24.0f); - int lastRow = firstRow + visibleRows; - - if (firstRow < 0) - firstRow = 0; - - if (lastRow < 0) - lastRow = 0; - - if (lastRow > map.Height) - lastRow = map.Height; - - Range indexRange = new Range(indicesPerRow * firstRow, indicesPerRow * lastRow); - Range vertexRange = new Range(verticesPerRow * firstRow, verticesPerRow * lastRow); - - device.DrawIndexedPrimitives(PrimitiveType.TriangleList, - vertexRange, indexRange); - } - - effect.EndPass(); - effect.End(); - - effect.Quality = ShaderQuality.High; - effect.Begin(); - effect.BeginPass(0); - - effect.SetTexture(texture, treeRenderer.sh.texture); - effect.Commit(); - - world.Draw(); - - effect.EndPass(); - effect.End(); - - device.End(); - device.Present(); + renderer.DrawBatch(vertexBuffer, batch.Value, vertexRange, indexRange, batch.Key.texture); + }); } TileSet LoadTileSet(Map currentMap) diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index de2d1ba2a7..f3d6f6b791 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -43,6 +43,7 @@ + diff --git a/OpenRa.Game/Renderer.cs b/OpenRa.Game/Renderer.cs new file mode 100644 index 0000000000..46483c0495 --- /dev/null +++ b/OpenRa.Game/Renderer.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using BluntDirectX.Direct3D; +using System.IO; + +namespace OpenRa.Game +{ + class Renderer + { + readonly GraphicsDevice device; + readonly Effect shader; + + readonly IntPtr r1Handle, r2Handle, baseTextureHandle, scrollHandle; + + const string shaderName = "diffuse.fx"; + + public Renderer(Control host, Size resolution, bool windowed) + { + host.ClientSize = resolution; + device = GraphicsDevice.Create(host, + resolution.Width, resolution.Height, windowed, false); + + shader = new Effect(device, File.OpenRead("../../../" + shaderName)); + shader.Quality = ShaderQuality.Low; + + baseTextureHandle = shader.GetHandle("DiffuseTexture"); + scrollHandle = shader.GetHandle("Scroll"); + r1Handle = shader.GetHandle("r1"); + r2Handle = shader.GetHandle("r2"); + } + + public GraphicsDevice Device { get { return device; } } + + public void BeginFrame( PointF r1, PointF r2, PointF scroll ) + { + device.Begin(); + device.Clear(0, Surfaces.Color); + + shader.SetValue(scrollHandle, scroll); + shader.SetValue(r1Handle, r1); + shader.SetValue(r2Handle, r2); + } + + public void EndFrame() + { + device.End(); + device.Present(); + } + + public void DrawWithShader(ShaderQuality quality, MethodInvoker task) + { + shader.Quality = quality; + + int passes = shader.Begin(); + for (int pass = 0; pass < passes; pass++) + { + shader.BeginPass(pass); + task(); + shader.EndPass(); + } + + shader.End(); + } + + public void DrawBatch(FvfVertexBuffer vertices, IndexBuffer indices, + Range vertexRange, Range indexRange, Texture texture) + where T : struct + { + shader.SetTexture(baseTextureHandle, texture); + shader.Commit(); + + vertices.Bind(0); + indices.Bind(); + + device.DrawIndexedPrimitives(PrimitiveType.TriangleList, + vertexRange, indexRange); + } + } +}