diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs new file mode 100644 index 0000000000..01fa2ed2ba --- /dev/null +++ b/OpenRa.Game/Actor.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using OpenRa.FileFormats; +using BluntDirectX.Direct3D; +using System.Windows.Forms; + +namespace OpenRa.Game +{ + class Actor + { + public PointF location; + public SheetRectangle[] currentImages; + } + + class Tree : Actor + { + public Tree( TreeReference r, TreeRenderer 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 + { + Dictionary> trees = new Dictionary>(); + + public readonly Sheet sh; + + public TreeRenderer(GraphicsDevice device, Map map, Package package, Palette pal) + { + Size pageSize = new Size( 1024, 512 ); + List sheets = new List(); + + Provider sheetProvider = delegate + { + Sheet sheet = new Sheet(new Bitmap(pageSize.Width, pageSize.Height)); + sheets.Add(sheet); + return sheet; + }; + + TileSheetBuilder builder = new TileSheetBuilder(pageSize, sheetProvider); + + foreach (TreeReference r in map.Trees) + { + if (trees.ContainsKey( r.Image )) + continue; + + ShpReader reader = new ShpReader(package.GetContent(r.Image + "." + map.Theater.Substring(0,3))); + Bitmap bitmap = BitmapBuilder.FromBytes(reader[0].Image, reader.Width, reader.Height, pal); + + SheetRectangle rect = builder.AddImage(bitmap.Size); + using (Graphics g = Graphics.FromImage(rect.sheet.bitmap)) + g.DrawImage(bitmap, rect.origin); + + trees.Add(r.Image, rect); + } + + foreach (Sheet sheet in sheets) + sheet.LoadTexture(device); + + sh = sheets[0]; + } + + public SheetRectangle GetImage( string tree ) + { + return trees[tree]; + } + } + + class World + { + const int spritesPerBatch = 1024; + + List actors = new List(); + FvfVertexBuffer vb; + IndexBuffer ib; + GraphicsDevice device; + + public World(GraphicsDevice device) + { + this.device = device; + this.vb = new FvfVertexBuffer(device, spritesPerBatch * 4, Vertex.Format); + this.ib = new IndexBuffer(device, spritesPerBatch * 6); + } + + public void Add(Actor a) + { + actors.Add(a); //todo: protect from concurrent modification + } + + // assumption: there is only one sheet! + // some noob needs to fix this! + + // assumption: its not going to hurt, to draw *all* units. + // in reality, 500 tanks is going to hurt our perf. + + public void Draw() + { + int sprites = 0; + List vertices = new List(); + List indices = new List(); + + foreach (Actor a in actors) + { + if (a.currentImages == null) + continue; + + foreach (SheetRectangle image in a.currentImages) + { + int offset = vertices.Count; + vertices.Add(new Vertex(a.location.X, a.location.Y, 0, U(image, 0), V(image, 0))); + vertices.Add(new Vertex(a.location.X + image.size.Width, a.location.Y, 0, U(image, 1), V(image, 0))); + vertices.Add(new Vertex(a.location.X, a.location.Y + image.size.Height, 0, U(image, 0), V(image, 1))); + vertices.Add(new Vertex(a.location.X + image.size.Width, a.location.Y + image.size.Height, 0, U(image, 1), V(image, 1))); + + indices.Add((ushort)offset); + indices.Add((ushort)(offset + 1)); + indices.Add((ushort)(offset + 2)); + + indices.Add((ushort)(offset + 1)); + indices.Add((ushort)(offset + 3)); + indices.Add((ushort)(offset + 2)); + + if (++sprites >= spritesPerBatch) + { + DrawBatch(vertices, indices); + + vertices = new List(); + indices = new List(); + sprites = 0; + } + } + } + + if (sprites > 0) + DrawBatch(vertices, indices); + } + + void DrawBatch(List vertices, List indices) + { + vb.SetData(vertices.ToArray()); + ib.SetData(indices.ToArray()); + + vb.Bind(0); + ib.Bind(); + + device.DrawIndexedPrimitives(PrimitiveType.TriangleList, + vertices.Count, indices.Count / 3); + } + + static float U(SheetRectangle s, float u) + { + float u0 = (float)(s.origin.X + 0.5f) / (float)s.sheet.bitmap.Width; + float u1 = (float)(s.origin.X + s.size.Width) / (float)s.sheet.bitmap.Width; + + return (u > 0) ? u1 : u0;// (1 - u) * u0 + u * u1; + } + + static float V(SheetRectangle s, float v) + { + float v0 = (float)(s.origin.Y + 0.5f) / (float)s.sheet.bitmap.Height; + float v1 = (float)(s.origin.Y + s.size.Height) / (float)s.sheet.bitmap.Height; + + return (v > 0) ? v1 : v0;// return (1 - v) * v0 + v * v1; + } + } +} diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index d22402017f..b3e60fdabf 100644 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -20,7 +20,7 @@ namespace OpenRa.Game Package TileMix; string TileSuffix; - const string mapName = "scg11eb.ini"; + const string mapName = "scm12ea.ini"; const string shaderName = "diffuse.fx"; Dictionary> tileMapping = @@ -33,6 +33,9 @@ namespace OpenRa.Game Effect effect; IntPtr texture, scroll, r1h, r2h; + World world; + TreeRenderer treeRenderer; + void LoadTextures() { List tempSheets = new List(); @@ -66,6 +69,12 @@ namespace OpenRa.Game foreach (Sheet s in tempSheets) s.LoadTexture(device); + + world = new World(device); + treeRenderer = new TreeRenderer(device, map, TileMix, pal); + + foreach (TreeReference treeReference in map.Trees) + world.Add(new Tree(treeReference, treeRenderer, map)); } float U(SheetRectangle s, float u) @@ -127,7 +136,7 @@ namespace OpenRa.Game public MainWindow() { - ClientSize = new Size(1280, 800); + ClientSize = new Size(1280,800); Visible = true; @@ -249,6 +258,18 @@ namespace OpenRa.Game 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(); } diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 1d03239a76..de2d1ba2a7 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -36,6 +36,7 @@ + Form diff --git a/OpenRa.Game/Sheet.cs b/OpenRa.Game/Sheet.cs index a7f68558e7..35fd7555d0 100644 --- a/OpenRa.Game/Sheet.cs +++ b/OpenRa.Game/Sheet.cs @@ -17,7 +17,7 @@ namespace OpenRa.Game public void LoadTexture(GraphicsDevice device) { - string tempFile = string.Format("../../../block-cache-{0}.bmp", suffix++); + string tempFile = string.Format("../../../block-cache-{0}.png", suffix++); bitmap.Save(tempFile); using( Stream s = File.OpenRead(tempFile) ) diff --git a/diffuse.fx b/diffuse.fx index 7409eb09bf..bd61ce7f56 100644 --- a/diffuse.fx +++ b/diffuse.fx @@ -56,3 +56,17 @@ technique low_quality { PixelShader = compile ps_2_0 Simple_fp(); } } + +technique high_quality { + pass p0 { + AlphaBlendEnable = true; + ZWriteEnable = true; + ZEnable = false; + CullMode = None; + VertexShader = compile vs_2_0 Simple_vp(); + PixelShader = compile ps_2_0 Simple_fp(); + + SrcBlend = SrcAlpha; + DestBlend = InvSrcAlpha; + } +}