From 387ac04d9f6876b1a6ee597d1c5687ecbf85cbff Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 14 Aug 2013 20:28:41 +1200 Subject: [PATCH 01/10] Split tileset artwork loading out of TileSet. This simplifies terrain loading and allows for non-square tiles in game. The editor still relies on the old code for now. --- OpenRA.FileFormats/Map/Terrain.cs | 15 +++-- OpenRA.FileFormats/Map/TileSet.cs | 19 +----- OpenRA.Game/Graphics/TerrainRenderer.cs | 22 +------ OpenRA.Game/Graphics/Theater.cs | 73 +++++++++++++++++++++++ OpenRA.Game/Graphics/WorldRenderer.cs | 3 + OpenRA.Game/OpenRA.Game.csproj | 1 + OpenRA.Mods.RA/Bridge.cs | 79 +++++++++++-------------- 7 files changed, 122 insertions(+), 90 deletions(-) create mode 100644 OpenRA.Game/Graphics/Theater.cs diff --git a/OpenRA.FileFormats/Map/Terrain.cs b/OpenRA.FileFormats/Map/Terrain.cs index 4e5f1326c4..5bb4989b88 100644 --- a/OpenRA.FileFormats/Map/Terrain.cs +++ b/OpenRA.FileFormats/Map/Terrain.cs @@ -16,16 +16,15 @@ namespace OpenRA.FileFormats public class Terrain { public readonly List TileBitmapBytes = new List(); + public readonly int Width; + public readonly int Height; - public Terrain( Stream stream, int size ) + public Terrain(Stream stream) { // Try loading as a cnc .tem BinaryReader reader = new BinaryReader( stream ); - int Width = reader.ReadUInt16(); - int Height = reader.ReadUInt16(); - - if( Width != size || Height != size ) - throw new InvalidDataException( "{0}x{1} != {2}x{2}".F(Width, Height, size ) ); + Width = reader.ReadUInt16(); + Height = reader.ReadUInt16(); /*NumTiles = */reader.ReadUInt16(); /*Zero1 = */reader.ReadUInt16(); @@ -65,8 +64,8 @@ namespace OpenRA.FileFormats { if (b != 255) { - stream.Position = ImgStart + b * size * size; - TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(size * size)); + stream.Position = ImgStart + b * Width * Height; + TileBitmapBytes.Add(new BinaryReader(stream).ReadBytes(Width * Height)); } else TileBitmapBytes.Add(null); diff --git a/OpenRA.FileFormats/Map/TileSet.cs b/OpenRA.FileFormats/Map/TileSet.cs index 0cec68450e..7fe1145459 100644 --- a/OpenRA.FileFormats/Map/TileSet.cs +++ b/OpenRA.FileFormats/Map/TileSet.cs @@ -113,7 +113,7 @@ namespace OpenRA.FileFormats foreach (var t in Templates) if (t.Value.Data == null) using (var s = FileSystem.OpenWithExts(t.Value.Image, Extensions)) - t.Value.Data = new Terrain(s, TileSize); + t.Value.Data = new Terrain(s); } public void Save(string filepath) @@ -144,23 +144,6 @@ namespace OpenRA.FileFormats root.WriteToFile(filepath); } - public byte[] GetBytes(TileReference r) - { - TileTemplate tile; - if (Templates.TryGetValue(r.type, out tile)) - { - var data = tile.Data.TileBitmapBytes[r.index]; - if (data != null) - return data; - } - - byte[] missingTile = new byte[TileSize*TileSize]; - for (var i = 0; i < missingTile.Length; i++) - missingTile[i] = 0x00; - - return missingTile; - } - public string GetTerrainType(TileReference r) { var tt = Templates[r.type].Tiles; diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index 240bceca21..cc092e2b6f 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -18,7 +18,6 @@ namespace OpenRA.Graphics { class TerrainRenderer { - SheetBuilder sheetBuilder; IVertexBuffer vertexBuffer; World world; @@ -29,23 +28,6 @@ namespace OpenRA.Graphics this.world = world; this.map = world.Map; - var allocated = false; - Func allocate = () => - { - if (allocated) - throw new SheetOverflowException("Terrain sheet overflow"); - allocated = true; - - // TODO: Use a fixed sheet size specified in the tileset yaml - return SheetBuilder.AllocateSheet(); - }; - - sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); - - var tileSize = new Size(Game.CellSize, Game.CellSize); - var tileMapping = new Cache, Sprite>( - x => sheetBuilder.Add(world.TileSet.GetBytes(x), tileSize)); - var terrainPalette = wr.Palette("terrain").Index; var vertices = new Vertex[4 * map.Bounds.Height * map.Bounds.Width]; int nv = 0; @@ -53,7 +35,7 @@ namespace OpenRA.Graphics for (var j = map.Bounds.Top; j < map.Bounds.Bottom; j++) for (var i = map.Bounds.Left; i < map.Bounds.Right; i++) { - var tile = tileMapping[map.MapTiles.Value[i, j]]; + var tile = wr.Theater.TileSprite(map.MapTiles.Value[i, j]); Util.FastCreateQuad(vertices, Game.CellSize * new float2(i, j), tile, terrainPalette, nv, tile.size); nv += 4; } @@ -96,7 +78,7 @@ namespace OpenRA.Graphics Game.Renderer.WorldSpriteRenderer.DrawVertexBuffer( vertexBuffer, verticesPerRow * firstRow, verticesPerRow * (lastRow - firstRow), - PrimitiveType.QuadList, sheetBuilder.Current); + PrimitiveType.QuadList, wr.Theater.Sheet); foreach (var r in world.WorldActor.TraitsImplementing()) r.Render(wr); diff --git a/OpenRA.Game/Graphics/Theater.cs b/OpenRA.Game/Graphics/Theater.cs new file mode 100644 index 0000000000..4ef7f0ef81 --- /dev/null +++ b/OpenRA.Game/Graphics/Theater.cs @@ -0,0 +1,73 @@ +#region Copyright & License Information +/* + * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.FileFormats.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Graphics +{ + public class Theater + { + SheetBuilder sheetBuilder; + Dictionary templates; + Sprite missingTile; + + Sprite[] LoadTemplate(string filename, string[] exts) + { + using (var s = FileSystem.OpenWithExts(filename, exts)) + { + var t = new Terrain(s); + return t.TileBitmapBytes + .Select(b => b != null ? sheetBuilder.Add(b, new Size(t.Width, t.Height)) : null) + .ToArray(); + } + } + + public Theater(TileSet tileset) + { + var allocated = false; + Func allocate = () => + { + if (allocated) + throw new SheetOverflowException("Terrain sheet overflow"); + allocated = true; + + // TODO: Use a fixed sheet size specified in the tileset yaml + return SheetBuilder.AllocateSheet(); + }; + + templates = new Dictionary(); + sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); + foreach (var t in tileset.Templates) + templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions)); + + // 1x1px transparent tile + missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); + } + + public Sprite TileSprite(TileReference r) + { + Sprite[] template; + if (templates.TryGetValue(r.type, out template)) + if (template.Length > r.index && template[r.index] != null) + return template[r.index]; + + return missingTile; + } + + public Sheet Sheet { get { return sheetBuilder.Current; } } + } +} diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index bfd1a91990..cf0773c0aa 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -33,6 +33,8 @@ namespace OpenRA.Graphics public class WorldRenderer { public readonly World world; + public readonly Theater Theater; + internal readonly TerrainRenderer terrainRenderer; internal readonly ShroudRenderer shroudRenderer; internal readonly HardwarePalette palette; @@ -50,6 +52,7 @@ namespace OpenRA.Graphics palette.Initialize(); + Theater = new Theater(world.TileSet); terrainRenderer = new TerrainRenderer(world, this); shroudRenderer = new ShroudRenderer(world); diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index e44917e4c5..e15a4185e7 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -235,6 +235,7 @@ + diff --git a/OpenRA.Mods.RA/Bridge.cs b/OpenRA.Mods.RA/Bridge.cs index 8a13908a43..8a8b72d410 100644 --- a/OpenRA.Mods.RA/Bridge.cs +++ b/OpenRA.Mods.RA/Bridge.cs @@ -69,12 +69,8 @@ namespace OpenRA.Mods.RA class Bridge: IRenderAsTerrain, INotifyDamageStateChanged { - static string cachedTileset; - static Cache, Sprite> sprites; - - Dictionary> TileSprites = new Dictionary>(); - Dictionary Templates = new Dictionary(); - ushort currentTemplate; + ushort template; + Dictionary footprint; Actor self; BridgeInfo Info; @@ -91,38 +87,21 @@ namespace OpenRA.Mods.RA this.Type = self.Info.Name; } - public void Create(ushort template, Dictionary subtiles) + public void Create(ushort template, Dictionary footprint) { - currentTemplate = template; - - // Create a new cache to store the tile data - if (cachedTileset != self.World.Map.Tileset) - { - cachedTileset = self.World.Map.Tileset; - var tileSize = new Size(Game.CellSize, Game.CellSize); - sprites = new Cache, Sprite>( - x => Game.modData.SheetBuilder.Add(self.World.TileSet.GetBytes(x), tileSize)); - } - - // Cache templates and tiles for the different states - foreach (var t in Info.Templates) - { - Templates.Add(t.First,self.World.TileSet.Templates[t.First]); - TileSprites.Add(t.First, subtiles.ToDictionary( - a => a.Key, - a => sprites[new TileReference(t.First, (byte)a.Value)])); - } + this.template = template; + this.footprint = footprint; // Set the initial custom terrain types - foreach (var c in TileSprites[currentTemplate].Keys) + foreach (var c in footprint.Keys) self.World.Map.CustomTerrain[c.X, c.Y] = GetTerrainType(c); } - public string GetTerrainType(CPos cell) + string GetTerrainType(CPos cell) { var dx = cell - self.Location; - var index = dx.X + Templates[currentTemplate].Size.X * dx.Y; - return self.World.TileSet.GetTerrainType(new TileReference(currentTemplate,(byte)index)); + var index = dx.X + self.World.TileSet.Templates[template].Size.X * dx.Y; + return self.World.TileSet.GetTerrainType(new TileReference(template, (byte)index)); } public void LinkNeighbouringBridges(World world, BridgeLayer bridges) @@ -136,27 +115,39 @@ namespace OpenRA.Mods.RA public Bridge GetNeighbor(int[] offset, BridgeLayer bridges) { - if (offset == null) return null; + if (offset == null) + return null; + return bridges.GetBridge(self.Location + new CVec(offset[0], offset[1])); } - bool initializePalettes = true; - PaletteReference terrainPalette; + IRenderable[] TemplateRenderables(WorldRenderer wr, PaletteReference palette, ushort template) + { + return footprint.Select(c => (IRenderable)(new SpriteRenderable( + wr.Theater.TileSprite(new TileReference(template, c.Value)), + c.Key.CenterPosition, WVec.Zero, 0, palette, 1f, true))).ToArray(); + } + + bool initialized; + Dictionary renderables; public IEnumerable RenderAsTerrain(WorldRenderer wr, Actor self) { - if (initializePalettes) + if (!initialized) { - terrainPalette = wr.Palette("terrain"); - initializePalettes = false; + var palette = wr.Palette("terrain"); + renderables = new Dictionary(); + foreach (var t in Info.Templates) + renderables.Add(t.First, TemplateRenderables(wr, palette, t.First)); + + initialized = true; } - foreach (var t in TileSprites[currentTemplate]) - yield return new SpriteRenderable(t.Value, t.Key.CenterPosition, WVec.Zero, 0, terrainPalette, 1f, true); + return renderables[template]; } void KillUnitsOnBridge() { - foreach (var c in TileSprites[currentTemplate].Keys) + foreach (var c in footprint.Keys) foreach (var a in self.World.ActorMap.GetUnitsAt(c)) if (a.HasTrait() && !a.Trait().CanEnterCell(c)) a.Kill(self); @@ -208,21 +199,21 @@ namespace OpenRA.Mods.RA bool killedUnits = false; void UpdateState() { - var oldTemplate = currentTemplate; + var oldTemplate = template; - currentTemplate = ChooseTemplate(); - if (currentTemplate == oldTemplate) + template = ChooseTemplate(); + if (template == oldTemplate) return; // Update map - foreach (var c in TileSprites[currentTemplate].Keys) + foreach (var c in footprint.Keys) self.World.Map.CustomTerrain[c.X, c.Y] = GetTerrainType(c); // If this bridge repair operation connects two pathfinding domains, // update the domain index. var domainIndex = self.World.WorldActor.TraitOrDefault(); if (domainIndex != null) - domainIndex.UpdateCells(self.World, TileSprites[currentTemplate].Keys); + domainIndex.UpdateCells(self.World, footprint.Keys); if (LongBridgeSegmentIsDead() && !killedUnits) { From 5bea8fd4ccc34e6634e67adc1f8d497c3529c550 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 14 Aug 2013 22:43:33 +1200 Subject: [PATCH 02/10] Introduce TileSetRenderer for editor and utility. --- .../Graphics/TileSetRenderer.cs | 82 +++++++++++++++++++ OpenRA.FileFormats/OpenRA.FileFormats.csproj | 1 + 2 files changed, 83 insertions(+) create mode 100644 OpenRA.FileFormats/Graphics/TileSetRenderer.cs diff --git a/OpenRA.FileFormats/Graphics/TileSetRenderer.cs b/OpenRA.FileFormats/Graphics/TileSetRenderer.cs new file mode 100644 index 0000000000..0431b362e7 --- /dev/null +++ b/OpenRA.FileFormats/Graphics/TileSetRenderer.cs @@ -0,0 +1,82 @@ +#region Copyright & License Information +/* + * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace OpenRA.FileFormats +{ + public class TileSetRenderer + { + public TileSet TileSet; + Dictionary> templates; + Size tileSize; + + public TileSetRenderer(TileSet tileset, Size tileSize) + { + this.TileSet = tileset; + this.tileSize = tileSize; + + templates = new Dictionary>(); + + foreach (var t in TileSet.Templates) + using (var s = FileSystem.OpenWithExts(t.Value.Image, tileset.Extensions)) + templates.Add(t.Key, new Terrain(s).TileBitmapBytes); + } + + public Bitmap RenderTemplate(ushort id, Palette p) + { + var template = TileSet.Templates[id]; + var templateData = templates[id]; + + var bitmap = new Bitmap(tileSize.Width * template.Size.X, tileSize.Height * template.Size.Y, + PixelFormat.Format8bppIndexed); + + bitmap.Palette = p.AsSystemPalette(); + + var data = bitmap.LockBits(bitmap.Bounds(), + ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); + + unsafe + { + var q = (byte*)data.Scan0.ToPointer(); + var stride = data.Stride; + + for (var u = 0; u < template.Size.X; u++) + for (var v = 0; v < template.Size.Y; v++) + if (templateData[u + v * template.Size.X] != null) + { + var rawImage = templateData[u + v * template.Size.X]; + for (var i = 0; i < tileSize.Width; i++) + for (var j = 0; j < tileSize.Height; j++) + q[(v * tileSize.Width + j) * stride + u * tileSize.Width + i] = rawImage[i + tileSize.Width * j]; + } + else + { + for (var i = 0; i < tileSize.Width; i++) + for (var j = 0; j < tileSize.Height; j++) + q[(v * tileSize.Width + j) * stride + u * tileSize.Width + i] = 0; + } + } + + bitmap.UnlockBits(data); + return bitmap; + } + + public List Data(ushort id) + { + return templates[id]; + } + } +} diff --git a/OpenRA.FileFormats/OpenRA.FileFormats.csproj b/OpenRA.FileFormats/OpenRA.FileFormats.csproj index 2716feb184..02c58d7291 100644 --- a/OpenRA.FileFormats/OpenRA.FileFormats.csproj +++ b/OpenRA.FileFormats/OpenRA.FileFormats.csproj @@ -146,6 +146,7 @@ + From 70580b27b96dc86513d43192df7161cc6eb1a19b Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 14 Aug 2013 22:43:47 +1200 Subject: [PATCH 03/10] Use TileSetRenderer for utility --tmp-png. --- OpenRA.Utility/Command.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index 4ff823c9e3..84834e3594 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -341,6 +341,7 @@ namespace OpenRA.Utility if (tileset == null) throw new InvalidOperationException("No theater named '{0}'".F(theater)); + var renderer = new TileSetRenderer(tileset, new Size(manifest.TileSize, manifest.TileSize)); tileset.LoadTiles(); var palette = new Palette(FileSystem.Open(tileset.Palette), shadowIndex); @@ -350,7 +351,7 @@ namespace OpenRA.Utility if (template.Value == null) throw new InvalidOperationException("No such template '{0}'".F(templateName)); - using (var image = tileset.RenderTemplate(template.Value.Id, palette)) + using (var image = renderer.RenderTemplate(template.Value.Id, palette)) image.Save(Path.ChangeExtension(templateName, ".png")); } } From 18759e01cf4510c7a50c69ca467a940dc387b006 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 14 Aug 2013 22:57:19 +1200 Subject: [PATCH 04/10] Use TileSetRenderer in the editor. --- OpenRA.Editor/BrushTool.cs | 4 ++-- OpenRA.Editor/Form1.cs | 13 +++++++------ OpenRA.Editor/Surface.cs | 10 ++++++---- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/OpenRA.Editor/BrushTool.cs b/OpenRA.Editor/BrushTool.cs index c940252a59..d71aa470cc 100644 --- a/OpenRA.Editor/BrushTool.cs +++ b/OpenRA.Editor/BrushTool.cs @@ -27,7 +27,7 @@ namespace OpenRA.Editor { // change the bits in the map var template = surface.TileSet.Templates[brushTemplate.N]; - var tile = template.Data; + var tile = surface.TileSetRenderer.Data(brushTemplate.N); var pos = surface.GetBrushLocation(); if (surface.GetModifiers() == Keys.Shift) @@ -42,7 +42,7 @@ namespace OpenRA.Editor if (surface.Map.IsInMap(new CVec(u, v) + pos)) { var z = u + v * template.Size.X; - if (tile.TileBitmapBytes[z] != null) + if (tile[z] != null) surface.Map.MapTiles.Value[u + pos.X, v + pos.Y] = new TileReference { diff --git a/OpenRA.Editor/Form1.cs b/OpenRA.Editor/Form1.cs index 2efa448bf1..c94da5686a 100755 --- a/OpenRA.Editor/Form1.cs +++ b/OpenRA.Editor/Form1.cs @@ -42,7 +42,7 @@ namespace OpenRA.Editor tilePalette.ResumeLayout(); actorPalette.ResumeLayout(); resourcePalette.ResumeLayout(); - surface1.Bind(null, null, null, null); + surface1.Bind(null, null, null, null, null); miniMapBox.Image = null; currentMod = toolStripComboBox1.SelectedItem as string; @@ -101,6 +101,7 @@ namespace OpenRA.Editor string loadedMapName; string currentMod = "ra"; TileSet tileset; + TileSetRenderer tilesetRenderer; bool dirty = false; void LoadMap(string mapname) @@ -144,6 +145,7 @@ namespace OpenRA.Editor { Rules.LoadRules(manifest, map); tileset = Rules.TileSets[map.Tileset]; + tilesetRenderer = new TileSetRenderer(tileset, new Size(manifest.TileSize, manifest.TileSize)); tileset.LoadTiles(); var shadowIndex = new int[] { 3, 4 }; var palette = new Palette(FileSystem.Open(tileset.Palette), shadowIndex); @@ -152,7 +154,7 @@ namespace OpenRA.Editor var playerPalette = tileset.PlayerPalette ?? tileset.Palette; var shadowedPalette = new Palette(FileSystem.Open(playerPalette), shadowIndex); - surface1.Bind(map, tileset, palette, shadowedPalette); + surface1.Bind(map, tileset, tilesetRenderer, palette, shadowedPalette); // construct the palette of tiles var palettes = new[] { tilePalette, actorPalette, resourcePalette }; @@ -185,7 +187,7 @@ namespace OpenRA.Editor { try { - var bitmap = tileset.RenderTemplate((ushort)t.Key, palette); + var bitmap = tilesetRenderer.RenderTemplate((ushort)t.Key, palette); var ibox = new PictureBox { Image = bitmap, @@ -329,7 +331,7 @@ namespace OpenRA.Editor if ((int)rd.MapWidth.Value != surface1.Map.MapSize.X || (int)rd.MapHeight.Value != surface1.Map.MapSize.Y) { surface1.Map.Resize((int)rd.MapWidth.Value, (int)rd.MapHeight.Value); - surface1.Bind(surface1.Map, surface1.TileSet, surface1.Palette, surface1.PlayerPalette); // rebind it to invalidate all caches + surface1.Bind(surface1.Map, surface1.TileSet, surface1.TileSetRenderer, surface1.Palette, surface1.PlayerPalette); // rebind it to invalidate all caches } surface1.Invalidate(); @@ -519,8 +521,7 @@ namespace OpenRA.Editor { var tr = surface1.Map.MapTiles.Value[i, j]; if (tr.type == 0xff || tr.type == 0xffff || tr.type == 1 || tr.type == 2) - tr.index = (byte)r.Next(0, - Rules.TileSets[surface1.Map.Tileset].Templates[tr.type].Data.TileBitmapBytes.Count); + tr.index = (byte)r.Next(0, surface1.TileSetRenderer.Data(tr.type).Count); surface1.Map.MapTiles.Value[i, j] = tr; } diff --git a/OpenRA.Editor/Surface.cs b/OpenRA.Editor/Surface.cs index 933f525998..ca0f8cd5e0 100755 --- a/OpenRA.Editor/Surface.cs +++ b/OpenRA.Editor/Surface.cs @@ -43,6 +43,7 @@ namespace OpenRA.Editor { public Map Map { get; private set; } public TileSet TileSet { get; private set; } + public TileSetRenderer TileSetRenderer { get; private set; } public Palette Palette { get; private set; } public Palette PlayerPalette { get; private set; } public int2 Offset; @@ -79,10 +80,11 @@ namespace OpenRA.Editor public Keys GetModifiers() { return ModifierKeys; } - public void Bind(Map m, TileSet ts, Palette p, Palette pp) + public void Bind(Map m, TileSet ts, TileSetRenderer tsr, Palette p, Palette pp) { Map = m; TileSet = ts; + TileSetRenderer = tsr; Palette = p; PlayerPalette = pp; playerPalettes = null; @@ -270,9 +272,9 @@ namespace OpenRA.Editor for (var j = 0; j < ChunkSize; j++) { var tr = Map.MapTiles.Value[u * ChunkSize + i, v * ChunkSize + j]; - var tile = TileSet.Templates[tr.type].Data; - var index = (tr.index < tile.TileBitmapBytes.Count) ? tr.index : (byte)0; - var rawImage = tile.TileBitmapBytes[index]; + var tile = TileSetRenderer.Data(tr.type); + var index = (tr.index < tile.Count) ? tr.index : (byte)0; + var rawImage = tile[index]; for (var x = 0; x < TileSet.TileSize; x++) for (var y = 0; y < TileSet.TileSize; y++) p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb(); From f6d0ea4b0fd4d388867fcd5fe9f2f504af21fb78 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 14 Aug 2013 22:58:54 +1200 Subject: [PATCH 05/10] Remove TileSet rendering code. --- OpenRA.Editor/Form1.cs | 1 - OpenRA.FileFormats/Map/TileSet.cs | 48 ------------------------------- OpenRA.Game/World.cs | 2 -- OpenRA.Utility/Command.cs | 1 - 4 files changed, 52 deletions(-) diff --git a/OpenRA.Editor/Form1.cs b/OpenRA.Editor/Form1.cs index c94da5686a..14645aff0b 100755 --- a/OpenRA.Editor/Form1.cs +++ b/OpenRA.Editor/Form1.cs @@ -146,7 +146,6 @@ namespace OpenRA.Editor Rules.LoadRules(manifest, map); tileset = Rules.TileSets[map.Tileset]; tilesetRenderer = new TileSetRenderer(tileset, new Size(manifest.TileSize, manifest.TileSize)); - tileset.LoadTiles(); var shadowIndex = new int[] { 3, 4 }; var palette = new Palette(FileSystem.Open(tileset.Palette), shadowIndex); diff --git a/OpenRA.FileFormats/Map/TileSet.cs b/OpenRA.FileFormats/Map/TileSet.cs index 7fe1145459..788f696094 100644 --- a/OpenRA.FileFormats/Map/TileSet.cs +++ b/OpenRA.FileFormats/Map/TileSet.cs @@ -71,8 +71,6 @@ namespace OpenRA.FileFormats return new MiniYaml(null, root); } - - public Terrain Data; } public class TileSet @@ -108,14 +106,6 @@ namespace OpenRA.FileFormats .Select(y => new TileTemplate(y)).ToDictionary(t => t.Id); } - public void LoadTiles() - { - foreach (var t in Templates) - if (t.Value.Data == null) - using (var s = FileSystem.OpenWithExts(t.Value.Image, Extensions)) - t.Value.Data = new Terrain(s); - } - public void Save(string filepath) { var root = new List(); @@ -153,43 +143,5 @@ namespace OpenRA.FileFormats return ret; } - - public Bitmap RenderTemplate(ushort n, Palette p) - { - var template = Templates[n]; - - var bitmap = new Bitmap(TileSize * template.Size.X, TileSize * template.Size.Y, - PixelFormat.Format8bppIndexed); - - bitmap.Palette = p.AsSystemPalette(); - - var data = bitmap.LockBits(bitmap.Bounds(), - ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - - unsafe - { - byte* q = (byte*)data.Scan0.ToPointer(); - var stride = data.Stride; - - for (var u = 0; u < template.Size.X; u++) - for (var v = 0; v < template.Size.Y; v++) - if (template.Data.TileBitmapBytes[u + v * template.Size.X] != null) - { - var rawImage = template.Data.TileBitmapBytes[u + v * template.Size.X]; - for (var i = 0; i < TileSize; i++) - for (var j = 0; j < TileSize; j++) - q[(v * TileSize + j) * stride + u * TileSize + i] = rawImage[i + TileSize * j]; - } - else - { - for (var i = 0; i < TileSize; i++) - for (var j = 0; j < TileSize; j++) - q[(v * TileSize + j) * stride + u * TileSize + i] = 0; - } - } - - bitmap.UnlockBits(data); - return bitmap; - } } } diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index fe07516552..1ba2aa50e0 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -119,8 +119,6 @@ namespace OpenRA Map = map; TileSet = Rules.TileSets[Map.Tileset]; - TileSet.LoadTiles(); - SharedRandom = new XRandom(orderManager.LobbyInfo.GlobalSettings.RandomSeed); WorldActor = CreateActor( "World", new TypeDictionary() ); diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index 84834e3594..9669609ebd 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -342,7 +342,6 @@ namespace OpenRA.Utility throw new InvalidOperationException("No theater named '{0}'".F(theater)); var renderer = new TileSetRenderer(tileset, new Size(manifest.TileSize, manifest.TileSize)); - tileset.LoadTiles(); var palette = new Palette(FileSystem.Open(tileset.Palette), shadowIndex); foreach (var templateName in templateNames) From f83ad88d2a484384bb49691467e32b8076fc87bf Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 14 Aug 2013 23:04:47 +1200 Subject: [PATCH 06/10] Use Manifest.TileSize everywhere. --- OpenRA.Editor/BrushTool.cs | 4 +- OpenRA.Editor/Surface.cs | 64 +++++++++---------- .../Graphics/TileSetRenderer.cs | 18 +++--- OpenRA.FileFormats/Map/TileSet.cs | 1 - OpenRA.TilesetBuilder/FormBuilder.cs | 1 - mods/d2k/tilesets/arrakis.yaml | 1 - 6 files changed, 43 insertions(+), 46 deletions(-) diff --git a/OpenRA.Editor/BrushTool.cs b/OpenRA.Editor/BrushTool.cs index d71aa470cc..c679c9e5b5 100644 --- a/OpenRA.Editor/BrushTool.cs +++ b/OpenRA.Editor/BrushTool.cs @@ -63,8 +63,8 @@ namespace OpenRA.Editor public void Preview(Surface surface, SGraphics g) { g.DrawImage(brushTemplate.Bitmap, - surface.TileSet.TileSize * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X, - surface.TileSet.TileSize * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y, + surface.TileSetRenderer.TileSize.Width * surface.GetBrushLocation().X * surface.Zoom + surface.GetOffset().X, + surface.TileSetRenderer.TileSize.Height * surface.GetBrushLocation().Y * surface.Zoom + surface.GetOffset().Y, brushTemplate.Bitmap.Width * surface.Zoom, brushTemplate.Bitmap.Height * surface.Zoom); } diff --git a/OpenRA.Editor/Surface.cs b/OpenRA.Editor/Surface.cs index ca0f8cd5e0..4794c78651 100755 --- a/OpenRA.Editor/Surface.cs +++ b/OpenRA.Editor/Surface.cs @@ -258,7 +258,7 @@ namespace OpenRA.Editor Bitmap RenderChunk(int u, int v) { - var bitmap = new Bitmap(ChunkSize * TileSet.TileSize, ChunkSize * TileSet.TileSize); + var bitmap = new Bitmap(ChunkSize * TileSetRenderer.TileSize.Width, ChunkSize * TileSetRenderer.TileSize.Height); var data = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); @@ -275,9 +275,9 @@ namespace OpenRA.Editor var tile = TileSetRenderer.Data(tr.type); var index = (tr.index < tile.Count) ? tr.index : (byte)0; var rawImage = tile[index]; - for (var x = 0; x < TileSet.TileSize; x++) - for (var y = 0; y < TileSet.TileSize; y++) - p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb(); + for (var x = 0; x < TileSetRenderer.TileSize.Width; x++) + for (var y = 0; y < TileSetRenderer.TileSize.Height; y++) + p[(j * TileSetRenderer.TileSize.Width + y) * stride + i * TileSetRenderer.TileSize.Width + x] = Palette.GetColor(rawImage[x + TileSetRenderer.TileSize.Width * y]).ToArgb(); if (Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type != 0) { @@ -288,12 +288,12 @@ namespace OpenRA.Editor int* q = (int*)srcdata.Scan0.ToPointer(); var srcstride = srcdata.Stride >> 2; - for (var x = 0; x < TileSet.TileSize; x++) - for (var y = 0; y < TileSet.TileSize; y++) + for (var x = 0; x < TileSetRenderer.TileSize.Width; x++) + for (var y = 0; y < TileSetRenderer.TileSize.Height; y++) { var c = q[y * srcstride + x]; if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */ - p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = c; + p[(j * TileSetRenderer.TileSize.Width + y) * stride + i * TileSetRenderer.TileSize.Width + x] = c; } resourceImage.UnlockBits(srcdata); @@ -319,15 +319,15 @@ namespace OpenRA.Editor { var vX = (int)Math.Floor((mousePos.X - Offset.X) / Zoom); var vY = (int)Math.Floor((mousePos.Y - Offset.Y) / Zoom); - return new CPos(vX / TileSet.TileSize, vY / TileSet.TileSize); + return new CPos(vX / TileSetRenderer.TileSize.Width, vY / TileSetRenderer.TileSize.Height); } public CPos GetBrushLocationBR() { var vX = (int)Math.Floor((mousePos.X - Offset.X) / Zoom); var vY = (int)Math.Floor((mousePos.Y - Offset.Y) / Zoom); - return new CPos((vX + TileSet.TileSize - 1) / TileSet.TileSize, - (vY + TileSet.TileSize - 1) / TileSet.TileSize); + return new CPos((vX + TileSetRenderer.TileSize.Width - 1) / TileSetRenderer.TileSize.Width, + (vY + TileSetRenderer.TileSize.Height - 1) / TileSetRenderer.TileSize.Height); } public void DrawActor(SGraphics g, CPos p, ActorTemplate t, ColorPalette cp) @@ -341,11 +341,11 @@ namespace OpenRA.Editor float2 GetDrawPosition(CPos location, Bitmap bmp, bool centered) { - float offsetX = centered ? bmp.Width / 2 - TileSet.TileSize / 2 : 0; - float drawX = TileSet.TileSize * location.X * Zoom + Offset.X - offsetX; + float offsetX = centered ? bmp.Width / 2 - TileSetRenderer.TileSize.Width / 2 : 0; + float drawX = TileSetRenderer.TileSize.Width * location.X * Zoom + Offset.X - offsetX; - float offsetY = centered ? bmp.Height / 2 - TileSet.TileSize / 2 : 0; - float drawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - offsetY; + float offsetY = centered ? bmp.Height / 2 - TileSetRenderer.TileSize.Height / 2 : 0; + float drawY = TileSetRenderer.TileSize.Height * location.Y * Zoom + Offset.Y - offsetY; return new float2(drawX, drawY); } @@ -413,24 +413,24 @@ namespace OpenRA.Editor var bmp = Chunks[x]; - var drawX = TileSet.TileSize * (float)ChunkSize * (float)x.X * Zoom + Offset.X; - var drawY = TileSet.TileSize * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y; + var drawX = TileSetRenderer.TileSize.Width * (float)ChunkSize * (float)x.X * Zoom + Offset.X; + var drawY = TileSetRenderer.TileSize.Height * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y; RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height); RectangleF destRect = new RectangleF(drawX, drawY, bmp.Width * Zoom, bmp.Height * Zoom); e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel); } e.Graphics.DrawRectangle(CordonPen, - Map.Bounds.Left * TileSet.TileSize * Zoom + Offset.X, - Map.Bounds.Top * TileSet.TileSize * Zoom + Offset.Y, - Map.Bounds.Width * TileSet.TileSize * Zoom, - Map.Bounds.Height * TileSet.TileSize * Zoom); + Map.Bounds.Left * TileSetRenderer.TileSize.Width * Zoom + Offset.X, + Map.Bounds.Top * TileSetRenderer.TileSize.Height * Zoom + Offset.Y, + Map.Bounds.Width * TileSetRenderer.TileSize.Width * Zoom, + Map.Bounds.Height * TileSetRenderer.TileSize.Height * Zoom); e.Graphics.DrawRectangle(SelectionPen, - (SelectionStart.X * TileSet.TileSize * Zoom) + Offset.X, - (SelectionStart.Y * TileSet.TileSize * Zoom) + Offset.Y, - (SelectionEnd - SelectionStart).X * TileSet.TileSize * Zoom, - (SelectionEnd - SelectionStart).Y * TileSet.TileSize * Zoom); + (SelectionStart.X * TileSetRenderer.TileSize.Width * Zoom) + Offset.X, + (SelectionStart.Y * TileSetRenderer.TileSize.Height * Zoom) + Offset.Y, + (SelectionEnd - SelectionStart).X * TileSetRenderer.TileSize.Width * Zoom, + (SelectionEnd - SelectionStart).Y * TileSetRenderer.TileSize.Height * Zoom); if (IsPaste) { @@ -439,10 +439,10 @@ namespace OpenRA.Editor var height = Math.Abs((SelectionStart - SelectionEnd).Y); e.Graphics.DrawRectangle(PastePen, - (loc.X * TileSet.TileSize * Zoom) + Offset.X, - (loc.Y * TileSet.TileSize * Zoom) + Offset.Y, - width * (TileSet.TileSize * Zoom), - height * (TileSet.TileSize * Zoom)); + (loc.X * TileSetRenderer.TileSize.Width * Zoom) + Offset.X, + (loc.Y * TileSetRenderer.TileSize.Height * Zoom) + Offset.Y, + width * (TileSetRenderer.TileSize.Width * Zoom), + height * (TileSetRenderer.TileSize.Height * Zoom)); } foreach (var ar in Map.Actors.Value) @@ -458,8 +458,8 @@ namespace OpenRA.Editor foreach (var ar in Map.Actors.Value) if (!ar.Key.StartsWith("Actor")) // if it has a custom name e.Graphics.DrawStringContrast(Font, ar.Key, - (int)(ar.Value.Location().X * TileSet.TileSize * Zoom + Offset.X), - (int)(ar.Value.Location().Y * TileSet.TileSize * Zoom + Offset.Y), + (int)(ar.Value.Location().X * TileSetRenderer.TileSize.Width * Zoom + Offset.X), + (int)(ar.Value.Location().Y * TileSetRenderer.TileSize.Height * Zoom + Offset.Y), Brushes.White, Brushes.Black); @@ -469,7 +469,7 @@ namespace OpenRA.Editor { if (i % 8 == 0) { - PointF point = new PointF(i * TileSet.TileSize * Zoom + Offset.X, (Map.Bounds.Top - 8) * TileSet.TileSize * Zoom + Offset.Y); + PointF point = new PointF(i * TileSetRenderer.TileSize.Width * Zoom + Offset.X, (Map.Bounds.Top - 8) * TileSetRenderer.TileSize.Height * Zoom + Offset.Y); e.Graphics.DrawString((i - Map.Bounds.Left).ToString(), MarkerFont, TextBrush, point); } } @@ -478,7 +478,7 @@ namespace OpenRA.Editor { if (i % 8 == 0) { - PointF point = new PointF((Map.Bounds.Left - 8) * TileSet.TileSize * Zoom + Offset.X, i * TileSet.TileSize * Zoom + Offset.Y); + PointF point = new PointF((Map.Bounds.Left - 8) * TileSetRenderer.TileSize.Width * Zoom + Offset.X, i * TileSetRenderer.TileSize.Height * Zoom + Offset.Y); e.Graphics.DrawString((i - Map.Bounds.Left).ToString(), MarkerFont, TextBrush, point); } } diff --git a/OpenRA.FileFormats/Graphics/TileSetRenderer.cs b/OpenRA.FileFormats/Graphics/TileSetRenderer.cs index 0431b362e7..24d47b2558 100644 --- a/OpenRA.FileFormats/Graphics/TileSetRenderer.cs +++ b/OpenRA.FileFormats/Graphics/TileSetRenderer.cs @@ -21,12 +21,12 @@ namespace OpenRA.FileFormats { public TileSet TileSet; Dictionary> templates; - Size tileSize; + public Size TileSize; public TileSetRenderer(TileSet tileset, Size tileSize) { this.TileSet = tileset; - this.tileSize = tileSize; + this.TileSize = tileSize; templates = new Dictionary>(); @@ -40,7 +40,7 @@ namespace OpenRA.FileFormats var template = TileSet.Templates[id]; var templateData = templates[id]; - var bitmap = new Bitmap(tileSize.Width * template.Size.X, tileSize.Height * template.Size.Y, + var bitmap = new Bitmap(TileSize.Width * template.Size.X, TileSize.Height * template.Size.Y, PixelFormat.Format8bppIndexed); bitmap.Palette = p.AsSystemPalette(); @@ -58,15 +58,15 @@ namespace OpenRA.FileFormats if (templateData[u + v * template.Size.X] != null) { var rawImage = templateData[u + v * template.Size.X]; - for (var i = 0; i < tileSize.Width; i++) - for (var j = 0; j < tileSize.Height; j++) - q[(v * tileSize.Width + j) * stride + u * tileSize.Width + i] = rawImage[i + tileSize.Width * j]; + for (var i = 0; i < TileSize.Width; i++) + for (var j = 0; j < TileSize.Height; j++) + q[(v * TileSize.Width + j) * stride + u * TileSize.Width + i] = rawImage[i + TileSize.Width * j]; } else { - for (var i = 0; i < tileSize.Width; i++) - for (var j = 0; j < tileSize.Height; j++) - q[(v * tileSize.Width + j) * stride + u * tileSize.Width + i] = 0; + for (var i = 0; i < TileSize.Width; i++) + for (var j = 0; j < TileSize.Height; j++) + q[(v * TileSize.Width + j) * stride + u * TileSize.Width + i] = 0; } } diff --git a/OpenRA.FileFormats/Map/TileSet.cs b/OpenRA.FileFormats/Map/TileSet.cs index 788f696094..3ea082473d 100644 --- a/OpenRA.FileFormats/Map/TileSet.cs +++ b/OpenRA.FileFormats/Map/TileSet.cs @@ -79,7 +79,6 @@ namespace OpenRA.FileFormats public string Id; public string Palette; public string PlayerPalette; - public int TileSize = 24; public string[] Extensions; public int WaterPaletteRotationBase = 0x60; public Dictionary Terrain = new Dictionary(); diff --git a/OpenRA.TilesetBuilder/FormBuilder.cs b/OpenRA.TilesetBuilder/FormBuilder.cs index f988d3fbde..34404072ed 100644 --- a/OpenRA.TilesetBuilder/FormBuilder.cs +++ b/OpenRA.TilesetBuilder/FormBuilder.cs @@ -366,7 +366,6 @@ namespace OpenRA.TilesetBuilder { Name = tilesetName, Id = tilesetID.ToUpper(), - TileSize = size, Palette = tilesetPalette.ToLower(), Extensions = new string[] { ext[0], ext[1] } }; diff --git a/mods/d2k/tilesets/arrakis.yaml b/mods/d2k/tilesets/arrakis.yaml index 217e1606d5..bb522a7027 100644 --- a/mods/d2k/tilesets/arrakis.yaml +++ b/mods/d2k/tilesets/arrakis.yaml @@ -1,6 +1,5 @@ General: Name: Arrakis - TileSize: 32 Id: ARRAKIS Palette: d2k.pal Extensions: .bas,.bat,.bgb,.ice,.tre,.was,.ext,.shp From 7278739e45c526747f1fa3c42dd358440f235afe Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 15 Aug 2013 18:05:34 +1200 Subject: [PATCH 07/10] Allow tilesets to specify their sheet size. Decreased the default size from 4096 to 512. --- OpenRA.FileFormats/Map/TileSet.cs | 3 ++- OpenRA.Game/Graphics/Theater.cs | 5 ++--- mods/d2k/tilesets/arrakis.yaml | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/OpenRA.FileFormats/Map/TileSet.cs b/OpenRA.FileFormats/Map/TileSet.cs index 3ea082473d..29639db9b8 100644 --- a/OpenRA.FileFormats/Map/TileSet.cs +++ b/OpenRA.FileFormats/Map/TileSet.cs @@ -77,6 +77,7 @@ namespace OpenRA.FileFormats { public string Name; public string Id; + public int SheetSize = 512; public string Palette; public string PlayerPalette; public string[] Extensions; @@ -85,7 +86,7 @@ namespace OpenRA.FileFormats public Dictionary Templates = new Dictionary(); public string[] EditorTemplateOrder; - static readonly string[] fields = {"Name", "TileSize", "Id", "Palette", "Extensions"}; + static readonly string[] fields = {"Name", "TileSize", "Id", "SheetSize", "Palette", "Extensions"}; public TileSet() {} diff --git a/OpenRA.Game/Graphics/Theater.cs b/OpenRA.Game/Graphics/Theater.cs index 4ef7f0ef81..e509a02b24 100644 --- a/OpenRA.Game/Graphics/Theater.cs +++ b/OpenRA.Game/Graphics/Theater.cs @@ -42,11 +42,10 @@ namespace OpenRA.Graphics Func allocate = () => { if (allocated) - throw new SheetOverflowException("Terrain sheet overflow"); + throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); allocated = true; - // TODO: Use a fixed sheet size specified in the tileset yaml - return SheetBuilder.AllocateSheet(); + return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize)); }; templates = new Dictionary(); diff --git a/mods/d2k/tilesets/arrakis.yaml b/mods/d2k/tilesets/arrakis.yaml index bb522a7027..0327fbe592 100644 --- a/mods/d2k/tilesets/arrakis.yaml +++ b/mods/d2k/tilesets/arrakis.yaml @@ -1,6 +1,7 @@ General: Name: Arrakis Id: ARRAKIS + SheetSize: 1024 Palette: d2k.pal Extensions: .bas,.bat,.bgb,.ice,.tre,.was,.ext,.shp From b6a033eef580ccdf196b322c809e7ff478f7e3bc Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 15 Aug 2013 18:11:04 +1200 Subject: [PATCH 08/10] Remove obsolete IRenderAsTerrain. This removes the technical limitation preventing FrozenUnderFog on bridges. --- OpenRA.Game/Graphics/WorldRenderer.cs | 4 ---- OpenRA.Game/Traits/TraitsInterfaces.cs | 1 - OpenRA.Mods.RA/Bridge.cs | 6 +++--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index cf0773c0aa..ea6b61a1d0 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -120,10 +120,6 @@ namespace OpenRA.Graphics Game.Renderer.EnableScissor(bounds.Left, bounds.Top, bounds.Width, bounds.Height); terrainRenderer.Draw(this, Game.viewport); - foreach (var a in world.traitDict.ActorsWithTraitMultiple(world)) - foreach (var r in a.Trait.RenderAsTerrain(this, a.Actor)) - r.Render(this); - Game.Renderer.Flush(); for (var i = 0; i < renderables.Count; i++) diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 6b434464e7..62cb04cb45 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -192,7 +192,6 @@ namespace OpenRA.Traits public interface IPostRender { void RenderAfterWorld(WorldRenderer wr, Actor self); } public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr); } - public interface IRenderAsTerrain { IEnumerable RenderAsTerrain(WorldRenderer wr, Actor self); } public interface IBodyOrientation { WAngle CameraPitch { get; } diff --git a/OpenRA.Mods.RA/Bridge.cs b/OpenRA.Mods.RA/Bridge.cs index 8a8b72d410..26c1bdd34d 100644 --- a/OpenRA.Mods.RA/Bridge.cs +++ b/OpenRA.Mods.RA/Bridge.cs @@ -67,7 +67,7 @@ namespace OpenRA.Mods.RA } } - class Bridge: IRenderAsTerrain, INotifyDamageStateChanged + class Bridge: IRender, INotifyDamageStateChanged { ushort template; Dictionary footprint; @@ -125,12 +125,12 @@ namespace OpenRA.Mods.RA { return footprint.Select(c => (IRenderable)(new SpriteRenderable( wr.Theater.TileSprite(new TileReference(template, c.Value)), - c.Key.CenterPosition, WVec.Zero, 0, palette, 1f, true))).ToArray(); + c.Key.CenterPosition, WVec.Zero, -512, palette, 1f, true))).ToArray(); } bool initialized; Dictionary renderables; - public IEnumerable RenderAsTerrain(WorldRenderer wr, Actor self) + public IEnumerable Render(Actor self, WorldRenderer wr) { if (!initialized) { From 608ca31f6d0820a12e4a7ec9a77fe4952476ca57 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 15 Aug 2013 19:17:00 +1200 Subject: [PATCH 09/10] Support .r8 tileset artwork. --- .../Graphics/TileSetRenderer.cs | 21 ++++++++++++++++--- OpenRA.FileFormats/Map/TileSet.cs | 3 ++- OpenRA.Game/Graphics/Theater.cs | 17 +++++++++++++-- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/OpenRA.FileFormats/Graphics/TileSetRenderer.cs b/OpenRA.FileFormats/Graphics/TileSetRenderer.cs index 24d47b2558..2850c991f2 100644 --- a/OpenRA.FileFormats/Graphics/TileSetRenderer.cs +++ b/OpenRA.FileFormats/Graphics/TileSetRenderer.cs @@ -23,16 +23,31 @@ namespace OpenRA.FileFormats Dictionary> templates; public Size TileSize; + List LoadTemplate(string filename, string[] exts, Cache r8Cache, int[] frames) + { + if (exts.Contains(".r8") && FileSystem.Exists(filename+".r8")) + { + var data = new List(); + + foreach (var f in frames) + data.Add(f >= 0 ? r8Cache[filename][f].Image : null); + + return data; + } + + using (var s = FileSystem.OpenWithExts(filename, exts)) + return new Terrain(s).TileBitmapBytes; + } + public TileSetRenderer(TileSet tileset, Size tileSize) { this.TileSet = tileset; this.TileSize = tileSize; templates = new Dictionary>(); - + var r8Cache = new Cache(s => new R8Reader(FileSystem.OpenWithExts(s, ".r8"))); foreach (var t in TileSet.Templates) - using (var s = FileSystem.OpenWithExts(t.Value.Image, tileset.Extensions)) - templates.Add(t.Key, new Terrain(s).TileBitmapBytes); + templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, r8Cache, t.Value.Frames)); } public Bitmap RenderTemplate(ushort id, Palette p) diff --git a/OpenRA.FileFormats/Map/TileSet.cs b/OpenRA.FileFormats/Map/TileSet.cs index 29639db9b8..fcb95ea9b2 100644 --- a/OpenRA.FileFormats/Map/TileSet.cs +++ b/OpenRA.FileFormats/Map/TileSet.cs @@ -35,6 +35,7 @@ namespace OpenRA.FileFormats { public ushort Id; public string Image; + public int[] Frames; public int2 Size; public bool PickAny; public string Category; @@ -52,7 +53,7 @@ namespace OpenRA.FileFormats t => t.Value.Value); } - static readonly string[] Fields = { "Id", "Image", "Size", "PickAny" }; + static readonly string[] Fields = { "Id", "Image", "Frames", "Size", "PickAny" }; public MiniYaml Save() { diff --git a/OpenRA.Game/Graphics/Theater.cs b/OpenRA.Game/Graphics/Theater.cs index e509a02b24..1ff13f4dcf 100644 --- a/OpenRA.Game/Graphics/Theater.cs +++ b/OpenRA.Game/Graphics/Theater.cs @@ -25,8 +25,20 @@ namespace OpenRA.Graphics Dictionary templates; Sprite missingTile; - Sprite[] LoadTemplate(string filename, string[] exts) + Sprite[] LoadTemplate(string filename, string[] exts, Cache r8Cache, int[] frames) { + if (exts.Contains(".r8") && FileSystem.Exists(filename+".r8")) + { + return frames.Select(f => + { + if (f < 0) + return null; + + var image = r8Cache[filename][f]; + return sheetBuilder.Add(image.Image, new Size(image.Size.Width, image.Size.Height)); + }).ToArray(); + } + using (var s = FileSystem.OpenWithExts(filename, exts)) { var t = new Terrain(s); @@ -48,10 +60,11 @@ namespace OpenRA.Graphics return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize)); }; + var r8Cache = new Cache(s => new R8Reader(FileSystem.OpenWithExts(s, ".r8"))); templates = new Dictionary(); sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); foreach (var t in tileset.Templates) - templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions)); + templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, r8Cache, t.Value.Frames)); // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); From 5cb79283be855ffb426b3a73bfb17341de0d6542 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 17 Aug 2013 20:01:24 +1200 Subject: [PATCH 10/10] Use uppercase extensions to support case-sensitive filesystems. --- OpenRA.FileFormats/Graphics/TileSetRenderer.cs | 4 ++-- OpenRA.Game/Graphics/Theater.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenRA.FileFormats/Graphics/TileSetRenderer.cs b/OpenRA.FileFormats/Graphics/TileSetRenderer.cs index 2850c991f2..b83bb7e1c2 100644 --- a/OpenRA.FileFormats/Graphics/TileSetRenderer.cs +++ b/OpenRA.FileFormats/Graphics/TileSetRenderer.cs @@ -25,7 +25,7 @@ namespace OpenRA.FileFormats List LoadTemplate(string filename, string[] exts, Cache r8Cache, int[] frames) { - if (exts.Contains(".r8") && FileSystem.Exists(filename+".r8")) + if (exts.Contains(".R8") && FileSystem.Exists(filename+".R8")) { var data = new List(); @@ -45,7 +45,7 @@ namespace OpenRA.FileFormats this.TileSize = tileSize; templates = new Dictionary>(); - var r8Cache = new Cache(s => new R8Reader(FileSystem.OpenWithExts(s, ".r8"))); + var r8Cache = new Cache(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8"))); foreach (var t in TileSet.Templates) templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, r8Cache, t.Value.Frames)); } diff --git a/OpenRA.Game/Graphics/Theater.cs b/OpenRA.Game/Graphics/Theater.cs index 1ff13f4dcf..6efe0095bd 100644 --- a/OpenRA.Game/Graphics/Theater.cs +++ b/OpenRA.Game/Graphics/Theater.cs @@ -27,7 +27,7 @@ namespace OpenRA.Graphics Sprite[] LoadTemplate(string filename, string[] exts, Cache r8Cache, int[] frames) { - if (exts.Contains(".r8") && FileSystem.Exists(filename+".r8")) + if (exts.Contains(".R8") && FileSystem.Exists(filename+".R8")) { return frames.Select(f => { @@ -60,7 +60,7 @@ namespace OpenRA.Graphics return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize)); }; - var r8Cache = new Cache(s => new R8Reader(FileSystem.OpenWithExts(s, ".r8"))); + var r8Cache = new Cache(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8"))); templates = new Dictionary(); sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); foreach (var t in tileset.Templates)