diff --git a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs index e158321704..a739b61bb3 100644 --- a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs +++ b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs @@ -66,6 +66,16 @@ namespace OpenRA.Graphics dirtyRows.Add(row); } + public void Clear(CPos cell) + { + Update(cell, null); + } + + public void Update(CPos cell, ISpriteSequence sequence, int frame) + { + Update(cell, sequence.GetSprite(frame)); + } + public void Update(CPos cell, Sprite sprite) { var xyz = float3.Zero; diff --git a/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs index 35764119b1..e706ae2353 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs @@ -70,17 +70,18 @@ namespace OpenRA.Mods.Common.Traits var res = r; var layer = spriteLayers.GetOrAdd(r.Value.Palette, pal => { - var first = res.Value.Variants.First().Value.First(); + var first = res.Value.Variants.First().Value.GetSprite(0); return new TerrainSpriteLayer(w, wr, first.Sheet, first.BlendMode, pal, false); }); // Validate that sprites are compatible with this layer var sheet = layer.Sheet; - if (res.Value.Variants.Any(kv => kv.Value.Any(s => s.Sheet != sheet))) + var sprites = res.Value.Variants.Values.SelectMany(v => Exts.MakeArray(v.Length, x => v.GetSprite(x))); + if (sprites.Any(s => s.Sheet != sheet)) throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); var blendMode = layer.BlendMode; - if (res.Value.Variants.Any(kv => kv.Value.Any(s => s.BlendMode != blendMode))) + if (sprites.Any(s => s.BlendMode != blendMode)) throw new InvalidDataException("Resource sprites specify different blend modes. " + "Try using different palettes for resource types that use different blend modes."); } @@ -151,7 +152,7 @@ namespace OpenRA.Mods.Common.Traits // Empty tile if (type == null) { - t.Sprite = null; + t.Sequence = null; return t; } @@ -164,9 +165,8 @@ namespace OpenRA.Mods.Common.Traits NetWorth += (t.Density + 1) * type.Info.ValuePerUnit; - var sprites = type.Variants[t.Variant]; - var frame = int2.Lerp(0, sprites.Length - 1, t.Density, type.Info.MaxDensity); - t.Sprite = sprites[frame]; + t.Sequence = type.Variants[t.Variant]; + t.Frame = int2.Lerp(0, t.Sequence.Length - 1, t.Density, type.Info.MaxDensity); return t; } @@ -185,11 +185,11 @@ namespace OpenRA.Mods.Common.Traits foreach (var kv in spriteLayers) { - // resource.Type is meaningless (and may be null) if resource.Sprite is null - if (resource.Sprite != null && resource.Type.Palette == kv.Key) - kv.Value.Update(c, resource.Sprite); + // resource.Type is meaningless (and may be null) if resource.Sequence is null + if (resource.Sequence != null && resource.Type.Palette == kv.Key) + kv.Value.Update(c, resource.Sequence, resource.Frame); else - kv.Value.Update(c, null); + kv.Value.Clear(c); } } } @@ -220,6 +220,7 @@ namespace OpenRA.Mods.Common.Traits public ResourceType Type; public int Density; public string Variant; - public Sprite Sprite; + public ISpriteSequence Sequence; + public int Frame; } } diff --git a/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs b/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs index 4fc75f81d4..7482ab385d 100644 --- a/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs +++ b/OpenRA.Mods.Common/Traits/World/ResourceRenderer.cs @@ -64,17 +64,18 @@ namespace OpenRA.Mods.Common.Traits { var layer = spriteLayers.GetOrAdd(r.Value.Palette, pal => { - var first = r.Value.Variants.First().Value.First(); + var first = r.Value.Variants.First().Value.GetSprite(0); return new TerrainSpriteLayer(w, wr, first.Sheet, first.BlendMode, pal, wr.World.Type != WorldType.Editor); }); // Validate that sprites are compatible with this layer var sheet = layer.Sheet; - if (r.Value.Variants.Any(kv => kv.Value.Any(s => s.Sheet != sheet))) + var sprites = r.Value.Variants.Values.SelectMany(v => Exts.MakeArray(v.Length, x => v.GetSprite(x))); + if (sprites.Any(s => s.Sheet != sheet)) throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); var blendMode = layer.BlendMode; - if (r.Value.Variants.Any(kv => kv.Value.Any(s => s.BlendMode != blendMode))) + if (sprites.Any(s => s.BlendMode != blendMode)) throw new InvalidDataException("Resource sprites specify different blend modes. " + "Try using different palettes for resource types that use different blend modes."); } @@ -94,15 +95,15 @@ namespace OpenRA.Mods.Common.Traits } } - protected void UpdateSpriteLayers(CPos cell, Sprite sprite, PaletteReference palette) + protected void UpdateSpriteLayers(CPos cell, ISpriteSequence sequence, int frame, PaletteReference palette) { foreach (var kv in spriteLayers) { - // resource.Type is meaningless (and may be null) if resource.Sprite is null - if (sprite != null && palette == kv.Key) - kv.Value.Update(cell, sprite); + // resource.Type is meaningless (and may be null) if resource.Sequence is null + if (sequence != null && palette == kv.Key) + kv.Value.Update(cell, sequence, frame); else - kv.Value.Update(cell, null); + kv.Value.Clear(cell); } } @@ -162,10 +163,10 @@ namespace OpenRA.Mods.Common.Traits var maxDensity = type.Info.MaxDensity; var frame = int2.Lerp(0, sprites.Length - 1, density, maxDensity); - UpdateSpriteLayers(cell, sprites[frame], type.Palette); + UpdateSpriteLayers(cell, sprites, frame, type.Palette); } else - UpdateSpriteLayers(cell, null, null); + UpdateSpriteLayers(cell, null, 0, null); } bool disposed; diff --git a/OpenRA.Mods.Common/Traits/World/ResourceType.cs b/OpenRA.Mods.Common/Traits/World/ResourceType.cs index 5e81bd6860..7a46f39ab3 100644 --- a/OpenRA.Mods.Common/Traits/World/ResourceType.cs +++ b/OpenRA.Mods.Common/Traits/World/ResourceType.cs @@ -86,17 +86,16 @@ namespace OpenRA.Mods.Common.Traits { public readonly ResourceTypeInfo Info; public PaletteReference Palette { get; private set; } - public readonly Dictionary Variants; + public readonly Dictionary Variants; public ResourceType(ResourceTypeInfo info, World world) { Info = info; - Variants = new Dictionary(); + Variants = new Dictionary(); foreach (var v in info.Sequences) { var seq = world.Map.Rules.Sequences.GetSequence(Info.Image, v); - var sprites = Exts.MakeArray(seq.Length, x => seq.GetSprite(x)); - Variants.Add(v, sprites); + Variants.Add(v, seq); } } diff --git a/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs b/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs index e83cef6de5..d1790955bc 100644 --- a/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/SmudgeLayer.cs @@ -82,13 +82,13 @@ namespace OpenRA.Mods.Common.Traits { public string Type; public int Depth; - public Sprite Sprite; + public ISpriteSequence Sequence; } public readonly SmudgeLayerInfo Info; readonly Dictionary tiles = new Dictionary(); readonly Dictionary dirty = new Dictionary(); - readonly Dictionary smudges = new Dictionary(); + readonly Dictionary smudges = new Dictionary(); readonly World world; TerrainSpriteLayer render; @@ -102,22 +102,19 @@ namespace OpenRA.Mods.Common.Traits var sequenceProvider = world.Map.Rules.Sequences; var types = sequenceProvider.Sequences(Info.Sequence); foreach (var t in types) - { - var seq = sequenceProvider.GetSequence(Info.Sequence, t); - var sprites = Exts.MakeArray(seq.Length, x => seq.GetSprite(x)); - smudges.Add(t, sprites); - } + smudges.Add(t, sequenceProvider.GetSequence(Info.Sequence, t)); } public void WorldLoaded(World w, WorldRenderer wr) { - var first = smudges.First().Value.First(); - var sheet = first.Sheet; - if (smudges.Values.Any(sprites => sprites.Any(s => s.Sheet != sheet))) + var sprites = smudges.Values.SelectMany(v => Exts.MakeArray(v.Length, x => v.GetSprite(x))).ToList(); + var sheet = sprites[0].Sheet; + var blendMode = sprites[0].BlendMode; + + if (sprites.Any(s => s.Sheet != sheet)) throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); - var blendMode = first.BlendMode; - if (smudges.Values.Any(sprites => sprites.Any(s => s.BlendMode != blendMode))) + if (sprites.Any(s => s.BlendMode != blendMode)) throw new InvalidDataException("Smudges specify different blend modes. " + "Try using different smudge types for smudges that use different blend modes."); @@ -130,15 +127,16 @@ namespace OpenRA.Mods.Common.Traits if (!smudges.ContainsKey(s.Type)) continue; + var seq = smudges[s.Type]; var smudge = new Smudge { Type = s.Type, Depth = s.Depth, - Sprite = smudges[s.Type][s.Depth] + Sequence = seq }; tiles.Add(kv.Key, smudge); - render.Update(kv.Key, smudge.Sprite); + render.Update(kv.Key, seq, s.Depth); } } @@ -150,24 +148,21 @@ namespace OpenRA.Mods.Common.Traits if (Game.CosmeticRandom.Next(0, 100) <= Info.SmokePercentage) world.AddFrameEndTask(w => w.Add(new SpriteEffect(world.Map.CenterOfCell(loc), w, Info.SmokeType, Info.SmokeSequence, Info.SmokePalette))); - // A null Sprite indicates a deleted smudge. - if ((!dirty.ContainsKey(loc) || dirty[loc].Sprite == null) && !tiles.ContainsKey(loc)) + // A null Sequence indicates a deleted smudge. + if ((!dirty.ContainsKey(loc) || dirty[loc].Sequence == null) && !tiles.ContainsKey(loc)) { // No smudge; create a new one var st = smudges.Keys.Random(Game.CosmeticRandom); - dirty[loc] = new Smudge { Type = st, Depth = 0, Sprite = smudges[st][0] }; + dirty[loc] = new Smudge { Type = st, Depth = 0, Sequence = smudges[st] }; } else { // Existing smudge; make it deeper - // A null Sprite indicates a deleted smudge. - var tile = dirty.ContainsKey(loc) && dirty[loc].Sprite != null ? dirty[loc] : tiles[loc]; + // A null Sequence indicates a deleted smudge. + var tile = dirty.ContainsKey(loc) && dirty[loc].Sequence != null ? dirty[loc] : tiles[loc]; var maxDepth = smudges[tile.Type].Length; if (tile.Depth < maxDepth - 1) - { tile.Depth++; - tile.Sprite = smudges[tile.Type][tile.Depth]; - } dirty[loc] = tile; } @@ -180,8 +175,8 @@ namespace OpenRA.Mods.Common.Traits var tile = dirty.ContainsKey(loc) ? dirty[loc] : default(Smudge); - // Setting Sprite to null to indicate a deleted smudge. - tile.Sprite = null; + // Setting Sequence to null to indicate a deleted smudge. + tile.Sequence = null; dirty[loc] = tile; } @@ -192,12 +187,18 @@ namespace OpenRA.Mods.Common.Traits { if (!self.World.FogObscures(kv.Key)) { - // A null Sprite indicates a deleted smudge. - if (kv.Value.Sprite == null) + // A null Sequence + if (kv.Value.Sequence == null) + { tiles.Remove(kv.Key); + render.Clear(kv.Key); + } else - tiles[kv.Key] = kv.Value; - render.Update(kv.Key, kv.Value.Sprite); + { + var smudge = kv.Value; + tiles[kv.Key] = smudge; + render.Update(kv.Key, smudge.Sequence, smudge.Depth); + } remove.Add(kv.Key); } diff --git a/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs b/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs index 9988cb2401..e904307507 100644 --- a/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs +++ b/OpenRA.Mods.D2k/Traits/World/BuildableTerrainLayer.cs @@ -31,7 +31,7 @@ namespace OpenRA.Mods.D2k.Traits public class BuildableTerrainLayer : IRenderOverlay, IWorldLoaded, ITickRender, INotifyActorDisposing { readonly BuildableTerrainLayerInfo info; - readonly Dictionary dirty = new Dictionary(); + readonly Dictionary dirty = new Dictionary(); readonly Map map; readonly CellLayer strength; @@ -61,10 +61,7 @@ namespace OpenRA.Mods.D2k.Traits map.CustomTerrain[cell] = map.Rules.TileSet.GetTerrainIndex(tile); strength[cell] = info.MaxStrength; - - // Terrain tiles define their origin at the topleft - var s = theater.TileSprite(tile); - dirty[cell] = new Sprite(s.Sheet, s.Bounds, s.ZRamp, float2.Zero, s.Channel, s.BlendMode); + dirty[cell] = tile; } public void HitTile(CPos cell, int damage) @@ -94,7 +91,17 @@ namespace OpenRA.Mods.D2k.Traits { if (!self.World.FogObscures(kv.Key)) { - render.Update(kv.Key, kv.Value); + var tile = kv.Value; + if (tile.HasValue) + { + // Terrain tiles define their origin at the topleft + var s = theater.TileSprite(tile.Value); + var ss = new Sprite(s.Sheet, s.Bounds, s.ZRamp, float2.Zero, s.Channel, s.BlendMode); + render.Update(kv.Key, ss); + } + else + render.Clear(kv.Key); + remove.Add(kv.Key); } } diff --git a/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs b/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs index c94a8d2654..c023d86d2d 100644 --- a/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs +++ b/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs @@ -35,7 +35,7 @@ namespace OpenRA.Mods.D2k.Traits // Empty tile if (t.Type == null) { - t.Sprite = null; + t.Sequence = null; return t; } @@ -51,12 +51,16 @@ namespace OpenRA.Mods.D2k.Traits { var sprites = D2kResourceRenderer.Variants[t.Variant]; var frame = t.Density > t.Type.Info.MaxDensity / 2 ? 1 : 0; - t.Sprite = t.Type.Variants.First().Value[sprites[frame]]; + t.Sequence = t.Type.Variants.First().Value; + t.Frame = sprites[frame]; } else if (D2kResourceRenderer.SpriteMap.TryGetValue(clear, out index)) - t.Sprite = t.Type.Variants.First().Value[index]; + { + t.Sequence = t.Type.Variants.First().Value; + t.Frame = index; + } else - t.Sprite = null; + t.Sequence = null; return t; } diff --git a/OpenRA.Mods.D2k/Traits/World/D2kResourceRenderer.cs b/OpenRA.Mods.D2k/Traits/World/D2kResourceRenderer.cs index 28322deeed..6c6bb75089 100644 --- a/OpenRA.Mods.D2k/Traits/World/D2kResourceRenderer.cs +++ b/OpenRA.Mods.D2k/Traits/World/D2kResourceRenderer.cs @@ -173,17 +173,17 @@ namespace OpenRA.Mods.D2k.Traits var sprites = Variants[content.Variant]; var frame = density > ResourceLayer.GetMaxResourceDensity(cell) / 2 ? 1 : 0; - UpdateSpriteLayers(cell, renderType.Variants.First().Value[sprites[frame]], renderType.Palette); + UpdateSpriteLayers(cell, renderType.Variants.First().Value, sprites[frame], renderType.Palette); } else if (SpriteMap.TryGetValue(clear, out index)) { - UpdateSpriteLayers(cell, renderType.Variants.First().Value[index], renderType.Palette); + UpdateSpriteLayers(cell, renderType.Variants.First().Value, index, renderType.Palette); } else throw new InvalidOperationException("SpriteMap does not contain an index for ClearSides type '{0}'".F(clear)); } else - UpdateSpriteLayers(cell, null, null); + UpdateSpriteLayers(cell, null, 0, null); } protected override string ChooseRandomVariant(ResourceType t)