using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Drawing; using BluntDirectX.Direct3D; using OpenRa.FileFormats; using System.IO; using System.Runtime.InteropServices; namespace OpenRa.Game { class MainWindow : Form { readonly GraphicsDevice device; readonly Map map; readonly TileSet tileSet; Palette pal; Package TileMix; string TileSuffix; const string mapName = "scm12ea.ini"; const string shaderName = "diffuse.fx"; Dictionary> tileMapping = new Dictionary>(); FvfVertexBuffer vertexBuffer; Dictionary drawBatches = new Dictionary(); Effect effect; IntPtr texture, scroll; SpriteHelper spriteHelper; FontHelper fontHelper; void LoadTextures() { List tempSheets = new List(); Provider sheetProvider = delegate { Sheet t = new Sheet( new Bitmap(256, 256)); tempSheets.Add(t); return t; }; TileSheetBuilder builder = new TileSheetBuilder( new Size(256,256), sheetProvider ); for( int i = 0; i < 128; i++ ) for (int j = 0; j < 128; j++) { TileReference tileRef = map.MapTiles[i, j]; if (!tileMapping.ContainsKey(tileRef)) { SheetRectangle rect = builder.AddImage(new Size(24, 24)); Bitmap srcImage = tileSet.tiles[ tileRef.tile ].GetTile( tileRef.image ); using (Graphics g = Graphics.FromImage(rect.sheet.bitmap)) g.DrawImage(srcImage, rect.origin); tileMapping.Add(tileRef, rect); } } foreach (Sheet s in tempSheets) s.LoadTexture(device); } float U(SheetRectangle s, float u) { float u0 = (float)s.origin.X / (float)s.sheet.bitmap.Width; float u1 = (float)(s.origin.X + s.size.Width) / (float)s.sheet.bitmap.Width; return (1 - u) * u0 + u * u1; } float V(SheetRectangle s, float v) { float v0 = (float)s.origin.Y / (float)s.sheet.bitmap.Height; float v1 = (float)(s.origin.Y + s.size.Height) / (float)s.sheet.bitmap.Height; return (1 - v) * v0 + v * v1; } void LoadVertexBuffer() { Dictionary> indexMap = new Dictionary>(); Vertex[] vertices = new Vertex[4 * 128 * 128];//map.Width * map.Height]; for( int i = 0; i < 128; i++ ) for (int j = 0; j < 128; j++) { SheetRectangle tile = tileMapping[map.MapTiles[i, j]]; ushort offset = (ushort)(4 * (i * 128 + j)); vertices[offset] = new Vertex(24 * i, 24 * j, 0, U(tile,0), V(tile,0)); vertices[offset + 1] = new Vertex(24 + 24 * i, 24 * j, 0, U(tile,1), V(tile,0)); vertices[offset + 2] = new Vertex(24 * i, 24 + 24 * j, 0, U(tile,0), V(tile,1)); vertices[offset + 3] = new Vertex(24 + 24 * i, 24 + 24 * j, 0, U(tile,1), V(tile,1)); List indexList; if (!indexMap.TryGetValue(tile.sheet, out indexList)) indexMap.Add(tile.sheet, indexList = new List()); indexList.Add(offset); indexList.Add((ushort)(offset + 1)); indexList.Add((ushort)(offset + 2)); indexList.Add((ushort)(offset + 1)); indexList.Add((ushort)(offset + 3)); indexList.Add((ushort)(offset + 2)); } vertexBuffer = new FvfVertexBuffer(device, vertices.Length, Vertex.Format); vertexBuffer.SetData(vertices); foreach (KeyValuePair> p in indexMap) { IndexBuffer indexBuffer = new IndexBuffer(device, p.Value.Count); indexBuffer.SetData(p.Value.ToArray()); drawBatches.Add(p.Key, indexBuffer); } } public MainWindow() { ClientSize = new Size(640, 480); Visible = true; device = GraphicsDevice.Create(this, ClientSize.Width, ClientSize.Height, true, false); IniFile mapFile = new IniFile(File.OpenRead("../../../" + mapName)); map = new Map(mapFile); Text = string.Format("OpenRA - {0} - {1}", map.Title, mapName); tileSet = LoadTileSet(map); LoadTextures(); LoadVertexBuffer(); effect = new Effect(device, File.OpenRead("../../../" + shaderName)); texture = effect.GetHandle("DiffuseTexture"); scroll = effect.GetHandle("Scroll"); spriteHelper = new SpriteHelper(device); fontHelper = new FontHelper(device, "Tahoma", 10, false); } internal void Run() { while (Created && Visible) { Frame(); Application.DoEvents(); } } PointF scrollPos = new PointF(1, 5); PointF oldPos; int x1,y1; protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); x1 = e.X; y1 = e.Y; oldPos = scrollPos; } protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (e.Button != 0) { int dx = x1 - e.X; int dy = y1 - e.Y; scrollPos = oldPos; scrollPos.X += (float)dx / 320.0f; scrollPos.Y += (float)dy / 240.0f; } } void Frame() { device.Begin(); device.Clear( Color.Red.ToArgb(), Surfaces.Color ); vertexBuffer.Bind(0); effect.Quality = ShaderQuality.Low; effect.Begin(); effect.BeginPass(0); effect.SetValue(scroll, scrollPos); foreach (KeyValuePair batch in drawBatches) { effect.SetTexture(texture, batch.Key.texture); effect.Commit(); batch.Value.Bind(); device.DrawIndexedPrimitives(PrimitiveType.TriangleList, vertexBuffer.Size, batch.Value.Size / 3); } effect.EndPass(); effect.End(); spriteHelper.Begin(); fontHelper.Draw(spriteHelper, "fps: 1337", 0, 0, Color.White.ToArgb()); spriteHelper.End(); device.End(); device.Present(); } TileSet LoadTileSet(Map currentMap) { switch (currentMap.Theater.ToLowerInvariant()) { case "temperate": pal = new Palette(File.OpenRead("../../../temperat.pal")); TileMix = new Package("../../../temperat.mix"); TileSuffix = ".tem"; break; case "snow": pal = new Palette(File.OpenRead("../../../snow.pal")); TileMix = new Package("../../../snow.mix"); TileSuffix = ".sno"; break; case "interior": pal = new Palette(File.OpenRead("../../../interior.pal")); TileMix = new Package("../../../interior.mix"); TileSuffix = ".int"; break; default: throw new NotImplementedException(); } return new TileSet(TileMix, TileSuffix, pal); } } }