diff --git a/OpenRA.FileFormats/Map/TileSet.cs b/OpenRA.FileFormats/Map/TileSet.cs index 0e4d1422c4..18641428bf 100644 --- a/OpenRA.FileFormats/Map/TileSet.cs +++ b/OpenRA.FileFormats/Map/TileSet.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; +using System.Reflection; namespace OpenRA.FileFormats { @@ -33,6 +34,7 @@ namespace OpenRA.FileFormats public bool IsWater = false; public Color Color; + public TerrainTypeInfo() {} public TerrainTypeInfo(MiniYaml my) { FieldLoader.Load(this, my); } public MiniYaml Save() { return FieldSaver.Save(this); } } @@ -47,6 +49,7 @@ namespace OpenRA.FileFormats static List fields = new List() {"Id", "Image", "Size", "PickAny"}; + public TileTemplate() {} public TileTemplate(MiniYaml my) { FieldLoader.LoadFields(this, my.Nodes, fields); @@ -55,18 +58,38 @@ namespace OpenRA.FileFormats t => byte.Parse(t.Key), t => t.Value.Value); } + + public MiniYaml Save() + { + var root = new Dictionary(); + foreach (var field in fields) + { + FieldInfo f = this.GetType().GetField(field); + if (f.GetValue(this) == null) continue; + root.Add(field, new MiniYaml(FieldSaver.FormatValue(this, f), null)); + } + + root.Add("Tiles", + new MiniYaml(null, Tiles.ToDictionary( + p => p.Key.ToString(), + p => new MiniYaml(p.Value)))); + + return new MiniYaml(null, root); + } } public class TileSet { - public readonly string Name; - public readonly string Id; - public readonly string Palette; - public readonly string[] Extensions; - public readonly Dictionary Terrain = new Dictionary(); - public readonly Dictionary Tiles = new Dictionary(); - public readonly Dictionary Templates = new Dictionary(); - + public string Name; + public string Id; + public string Palette; + public string[] Extensions; + public Dictionary Terrain = new Dictionary(); + public Dictionary Tiles = new Dictionary(); + public Dictionary Templates = new Dictionary(); + static List fields = new List() {"Name", "Id", "Palette", "Extensions"}; + + public TileSet() {} public TileSet( string filepath ) { var yaml = MiniYaml.FromFile(filepath); @@ -92,6 +115,37 @@ namespace OpenRA.FileFormats Tiles.Add( t.Key, new Terrain( s ) ); } } + + public void Save(string filepath) + { + var root = new Dictionary(); + foreach (var field in fields) + { + FieldInfo f = this.GetType().GetField(field); + if (f.GetValue(this) == null) continue; + root.Add(field, new MiniYaml(FieldSaver.FormatValue(this, f), null)); + } + + var gen = new Dictionary(); + foreach (var field in fields) + { + FieldInfo f = this.GetType().GetField(field); + if (f.GetValue(this) == null) continue; + gen.Add(field, new MiniYaml(FieldSaver.FormatValue(this, f), null)); + } + root.Add("General", new MiniYaml(null, gen)); + + root.Add("Terrain", + new MiniYaml(null, Terrain.ToDictionary( + t => "TerrainType@{0}".F(t.Value.Type), + t => t.Value.Save()))); + + root.Add("Templates", + new MiniYaml(null, Templates.ToDictionary( + t => "Template@{0}".F(t.Value.Id), + t => t.Value.Save()))); + root.WriteToFile(filepath); + } public byte[] GetBytes(TileReference r) { diff --git a/OpenRA.TilesetBuilder/Form1.cs b/OpenRA.TilesetBuilder/Form1.cs index ff55d08279..2079cdf5a6 100644 --- a/OpenRA.TilesetBuilder/Form1.cs +++ b/OpenRA.TilesetBuilder/Form1.cs @@ -6,7 +6,7 @@ using System.IO; using System.Linq; using System.Windows.Forms; using System.Xml; - +using OpenRA.FileFormats; namespace OpenRA.TilesetBuilder { public partial class Form1 : Form @@ -104,31 +104,71 @@ namespace OpenRA.TilesetBuilder var dir = Path.Combine(Path.GetDirectoryName(srcfile), "output"); Directory.CreateDirectory(dir); + // Create a Tileset definition + // Todo: Pull this info from the gui + var tilesetFile = "tileset-arrakis.yaml"; + var tileset = new TileSet() + { + Name = "Arrakis", + Id = "ARRAKIS", + Palette = "arrakis.pal", + Extensions = new string[] {".arr", ".shp"} + }; + // export palette (use the embedded palette) var p = surface1.Image.Palette.Entries.ToList(); - while (p.Count < 256) p.Add(Color.Black); // pad the palette out with extra blacks - var paletteData = p.Take(256).SelectMany(c => new byte[] { (byte)(c.R >> 2), (byte)(c.G >> 2), (byte)(c.B >> 2) }).ToArray(); - File.WriteAllBytes(Path.Combine(dir, "terrain.pal"), paletteData); - - // todo: write out a TMP for each template + ExportPalette(p, Path.Combine(dir, tileset.Palette)); + + // Export tile artwork foreach (var t in surface1.Templates) - ExportTemplate(t, surface1.Templates.IndexOf(t), dir); + ExportTemplate(t, surface1.Templates.IndexOf(t), tileset.Extensions.First(), dir); + + // Add the terraintypes + // Todo: add support for multiple/different terraintypes + var terraintype = new TerrainTypeInfo() + { + Type = "clear", + Buildable = true, + AcceptSmudge = true, + IsWater = false, + Color = Color.White + }; + tileset.Terrain.Add("clear", terraintype); + + // Add the templates + ushort cur = 0; + foreach (var tp in surface1.Templates) + { + var template = new TileTemplate() + { + Id = cur, + Image = "t{0:00}".F(cur), + Size = new int2(tp.Width,tp.Height), + }; + + // Todo: add support for different terraintypes + // Todo: restrict cells? this doesn't work: .Where( c => surface1.TerrainTypes[c.Key.X, c.Key.Y] != 0 ) + foreach (var t in tp.Cells) + template.Tiles.Add((byte)((t.Key.X - tp.Left) + tp.Width * (t.Key.Y - tp.Top)), "clear"); - // todo: write out a tileset definition - var tileset = surface1.Templates.SelectMany((t, i) => new[] { ";", "A", "1", i.ToString("x4"), "t{0:00}".F(i), "" }).ToArray(); - File.WriteAllLines(Path.Combine(dir, "tileset.til"), tileset); - - // todo: write out a templates ini - var templates = surface1.Templates.SelectMany((t, i) => new[] { "[t{0:00}]".F(i), "Name=t{0:00}".F(i), "width={0}".F(t.Width), "height={0}".F(t.Height) } - .Concat( t.Cells.Where( c => surface1.TerrainTypes[c.Key.X, c.Key.Y] != 0 ) - .Select( c => "tiletype{0}={1}".F( (c.Key.X - t.Left) + t.Width * (c.Key.Y - t.Top), surface1.TerrainTypes[c.Key.X, c.Key.Y] ))) - .Concat(new[] { "" })).ToArray(); - File.WriteAllLines(Path.Combine(dir, "templates.ini"), templates); + tileset.Templates.Add(cur, template); + cur++; + } + + tileset.Save(Path.Combine(dir, tilesetFile)); + System.Console.WriteLine("Finished export"); + } + + void ExportPalette(List p, string file) + { + while (p.Count < 256) p.Add(Color.Black); // pad the palette out with extra blacks + var paletteData = p.Take(256).SelectMany(c => new byte[] { (byte)(c.R >> 2), (byte)(c.G >> 2), (byte)(c.B >> 2) }).ToArray(); + File.WriteAllBytes(file, paletteData); } - void ExportTemplate(Template t, int n, string dir) + void ExportTemplate(Template t, int n, string suffix, string dir) { - var filename = Path.Combine(dir, "t{0:00}.arr".F(n)); + var filename = Path.Combine(dir, "t{0:00}{1}".F(n, suffix)); var totalTiles = t.Width * t.Height; var ms = new MemoryStream();