diff --git a/OpenRA.Mods.Common/Terrain/DefaultTileCache.cs b/OpenRA.Mods.Common/Terrain/DefaultTileCache.cs index 9f07456973..5d110ff498 100644 --- a/OpenRA.Mods.Common/Terrain/DefaultTileCache.cs +++ b/OpenRA.Mods.Common/Terrain/DefaultTileCache.cs @@ -36,22 +36,13 @@ namespace OpenRA.Mods.Common.Terrain public sealed class DefaultTileCache : IDisposable { readonly Dictionary templates = new Dictionary(); - SheetBuilder sheetBuilder; + readonly Cache sheetBuilders; readonly Sprite missingTile; readonly MersenneTwister random; public DefaultTileCache(DefaultTerrain terrainInfo, Action onMissingImage = null) { - var allocated = false; - - Func allocate = () => - { - if (allocated) - throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); - allocated = true; - - return new Sheet(SheetType.Indexed, new Size(terrainInfo.SheetSize, terrainInfo.SheetSize)); - }; + sheetBuilders = new Cache(t => new SheetBuilder(t, terrainInfo.SheetSize)); random = new MersenneTwister(); @@ -99,25 +90,16 @@ namespace OpenRA.Mods.Common.Terrain var offset = new float3(f.Offset, zOffset); var type = SheetBuilder.FrameTypeToSheetType(f.Type); - // Defer SheetBuilder creation until we know what type of frames we are loading! - // TODO: Support mixed indexed and BGRA frames - if (sheetBuilder == null) - sheetBuilder = new SheetBuilder(SheetBuilder.FrameTypeToSheetType(f.Type), allocate); - else if (type != sheetBuilder.Type) - throw new YamlException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA."); - - var s = sheetBuilder.Allocate(f.Size, zRamp, offset); + var s = sheetBuilders[type].Allocate(f.Size, zRamp, offset); OpenRA.Graphics.Util.FastCopyIntoChannel(s, f.Data, f.Type); if (terrainInfo.EnableDepth) { var depthFrame = allFrames[j + frameCount]; - var ss = sheetBuilder.Allocate(f.Size, zRamp, offset); + var depthType = SheetBuilder.FrameTypeToSheetType(depthFrame.Type); + var ss = sheetBuilders[depthType].Allocate(depthFrame.Size, zRamp, offset); OpenRA.Graphics.Util.FastCopyIntoChannel(ss, depthFrame.Data, depthFrame.Type); - - // s and ss are guaranteed to use the same sheet - // because of the custom terrain sheet allocation - s = new SpriteWithSecondaryData(s, s.Sheet, ss.Bounds, ss.Channel); + s = new SpriteWithSecondaryData(s, ss.Sheet, ss.Bounds, ss.Channel); } return s; @@ -137,12 +119,22 @@ namespace OpenRA.Mods.Common.Terrain } // 1x1px transparent tile - if (sheetBuilder.Type == SheetType.BGRA) - missingTile = sheetBuilder.Add(new byte[4], SpriteFrameType.Bgra32, new Size(1, 1)); - else - missingTile = sheetBuilder.Add(new byte[1], SpriteFrameType.Indexed8, new Size(1, 1)); + var missingDataLength = 1; + var missingFrameType = SpriteFrameType.Indexed8; + var missingSheetType = SheetType.Indexed; - Sheet.ReleaseBuffer(); + // Avoid creating an indexed sheet if all tiles are BGRA + var missing = sheetBuilders.FirstOrDefault(); + if (missing.Value != null && missing.Key == SheetType.BGRA) + { + missingDataLength = 4; + missingFrameType = SpriteFrameType.Bgra32; + missingSheetType = SheetType.BGRA; + } + + missingTile = sheetBuilders[missingSheetType].Add(new byte[missingDataLength], missingFrameType, new Size(1, 1)); + foreach (var sb in sheetBuilders.Values) + sb.Current.ReleaseBuffer(); } public bool HasTileSprite(TerrainTile r, int? variant = null) @@ -162,11 +154,12 @@ namespace OpenRA.Mods.Common.Terrain return template.Sprites[start * template.Stride + r.Index]; } - public Sheet Sheet { get { return sheetBuilder.Current; } } + public Sprite MissingTile { get { return missingTile; } } public void Dispose() { - sheetBuilder.Dispose(); + foreach (var sb in sheetBuilders.Values) + sb.Dispose(); } } } diff --git a/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs b/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs index 5ee896e7ff..42d3cc2d33 100644 --- a/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs +++ b/OpenRA.Mods.Common/Traits/World/TerrainRenderer.cs @@ -80,9 +80,7 @@ namespace OpenRA.Mods.Common.Traits void IWorldLoaded.WorldLoaded(World world, WorldRenderer wr) { worldRenderer = wr; - var emptySprite = new Sprite(tileCache.Sheet, Rectangle.Empty, TextureChannel.Alpha); - spriteLayer = new TerrainSpriteLayer(world, wr, emptySprite, BlendMode.Alpha, world.Type != WorldType.Editor); - + spriteLayer = new TerrainSpriteLayer(world, wr, tileCache.MissingTile, BlendMode.Alpha, world.Type != WorldType.Editor); foreach (var cell in map.AllCells) UpdateCell(cell); @@ -124,7 +122,7 @@ namespace OpenRA.Mods.Common.Traits disposed = true; } - Sheet ITiledTerrainRenderer.Sheet { get { return tileCache.Sheet; } } + Sprite ITiledTerrainRenderer.MissingTile { get { return tileCache.MissingTile; } } Sprite ITiledTerrainRenderer.TileSprite(TerrainTile r, int? variant) { diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 51c483ffc1..7c6a11207e 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -654,7 +654,7 @@ namespace OpenRA.Mods.Common.Traits [RequireExplicitImplementation] public interface ITiledTerrainRenderer { - Sheet Sheet { get; } + Sprite MissingTile { get; } Sprite TileSprite(TerrainTile r, int? variant = null); Rectangle TemplateBounds(TerrainTemplateInfo template); IEnumerable RenderUIPreview(WorldRenderer wr, TerrainTemplateInfo template, int2 origin, float scale); diff --git a/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs b/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs index a0f4133d2e..f790337f32 100644 --- a/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs +++ b/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs @@ -13,7 +13,6 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.D2k.Traits @@ -52,8 +51,7 @@ namespace OpenRA.Mods.D2k.Traits void IWorldLoaded.WorldLoaded(World w, WorldRenderer wr) { - var emptySprite = new Sprite(terrainRenderer.Sheet, Rectangle.Empty, TextureChannel.Alpha); - render = new TerrainSpriteLayer(w, wr, emptySprite, BlendMode.Alpha, wr.World.Type != WorldType.Editor); + render = new TerrainSpriteLayer(w, wr, terrainRenderer.MissingTile, BlendMode.Alpha, wr.World.Type != WorldType.Editor); paletteReference = wr.Palette(info.Palette); }