From 089973280d540b8bf82366071867abef9bbf72a1 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 11 Dec 2013 08:58:46 +1300 Subject: [PATCH 1/4] Add Multiply blend mode for D2K move-flash and shroud. --- OpenRA.FileFormats/Graphics/IGraphicsDevice.cs | 2 +- OpenRA.Mods.D2k/PaletteFromR8.cs | 10 ++++++---- OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs | 6 ++++++ OpenRA.Renderer.SdlCommon/SdlGraphics.cs | 6 ++++++ mods/d2k/rules/system.yaml | 2 +- mods/d2k/sequences/misc.yaml | 2 +- 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs b/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs index 16f0b67d39..ae2a280816 100755 --- a/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs +++ b/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs @@ -31,7 +31,7 @@ namespace OpenRA.FileFormats.Graphics IGraphicsDevice Create( Size size, WindowMode windowMode ); } - public enum BlendMode { None, Alpha, Additive, Subtractive } + public enum BlendMode { None, Alpha, Additive, Subtractive, Multiply } public interface IGraphicsDevice { diff --git a/OpenRA.Mods.D2k/PaletteFromR8.cs b/OpenRA.Mods.D2k/PaletteFromR8.cs index 901fef682c..b60a26330b 100644 --- a/OpenRA.Mods.D2k/PaletteFromR8.cs +++ b/OpenRA.Mods.D2k/PaletteFromR8.cs @@ -10,8 +10,8 @@ using System.IO; using OpenRA.FileFormats; -using OpenRA.Traits; using OpenRA.Graphics; +using OpenRA.Traits; namespace OpenRA.Mods.RA { @@ -24,6 +24,7 @@ namespace OpenRA.Mods.RA [Desc("Palette byte offset")] public readonly long Offset = 0; public readonly bool AllowModifiers = true; + public readonly bool InvertColor = false; public object Create(ActorInitializer init) { return new PaletteFromR8(this); } } @@ -42,10 +43,11 @@ namespace OpenRA.Mods.RA for (var i = 0; i < 256; i++) { - // The custom palette is scaled into the range 0-128. - // This makes the move-flash match the original game, but may not be correct in other cases. var packed = s.ReadUInt16(); - colors[i] = (uint)((255 << 24) | ((packed & 0xF800) << 7) | ((packed & 0x7E0) << 4) | ((packed & 0x1f) << 2)); + colors[i] = (uint)((255 << 24) | ((packed & 0xF800) << 8) | ((packed & 0x7E0) << 5) | ((packed & 0x1f) << 3)); + + if (info.InvertColor) + colors[i] ^= 0x00FFFFFF; } } diff --git a/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs b/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs index ad5805f44f..5d49dccfa4 100755 --- a/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs +++ b/OpenRA.Renderer.Sdl2/Sdl2GraphicsDevice.cs @@ -177,6 +177,12 @@ namespace OpenRA.Renderer.Sdl2 ErrorHandler.CheckGlError(); Gl.glBlendEquation(Gl.GL_FUNC_REVERSE_SUBTRACT); break; + case BlendMode.Multiply: + Gl.glEnable(Gl.GL_BLEND); + ErrorHandler.CheckGlError(); + Gl.glBlendFuncSeparate(Gl.GL_DST_COLOR, Gl.GL_ZERO, Gl.GL_ONE, Gl.GL_ONE_MINUS_SRC_ALPHA); + ErrorHandler.CheckGlError(); + break; } ErrorHandler.CheckGlError(); diff --git a/OpenRA.Renderer.SdlCommon/SdlGraphics.cs b/OpenRA.Renderer.SdlCommon/SdlGraphics.cs index 8c8de209e3..ec87e0f8d9 100644 --- a/OpenRA.Renderer.SdlCommon/SdlGraphics.cs +++ b/OpenRA.Renderer.SdlCommon/SdlGraphics.cs @@ -179,6 +179,12 @@ namespace OpenRA.Renderer.SdlCommon ErrorHandler.CheckGlError(); Gl.glBlendEquation(Gl.GL_FUNC_REVERSE_SUBTRACT); break; + case BlendMode.Multiply: + Gl.glEnable(Gl.GL_BLEND); + ErrorHandler.CheckGlError(); + Gl.glBlendFuncSeparate(Gl.GL_DST_COLOR, Gl.GL_ZERO, Gl.GL_ONE, Gl.GL_ONE_MINUS_SRC_ALPHA); + ErrorHandler.CheckGlError(); + break; } ErrorHandler.CheckGlError(); } diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index 2dcf67d748..7b4a68f1ae 100644 --- a/mods/d2k/rules/system.yaml +++ b/mods/d2k/rules/system.yaml @@ -414,7 +414,7 @@ World: Name: moveflash Filename: DATA.R8 Offset: 2572352 - A: 64 + InvertColor: true PaletteFromRGBA@disabled: Name: disabled R: 0 diff --git a/mods/d2k/sequences/misc.yaml b/mods/d2k/sequences/misc.yaml index 5774d04056..df39400d6c 100644 --- a/mods/d2k/sequences/misc.yaml +++ b/mods/d2k/sequences/misc.yaml @@ -304,7 +304,7 @@ moveflsh: Start: 3621 Length: 5 Tick: 80 - BlendMode: Subtractive + BlendMode: Multiply resources: spice: BLOXBASE From 4e814a8c2ede4d17390937085ecc749a23d3b7a6 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Tue, 10 Dec 2013 16:58:35 +1300 Subject: [PATCH 2/4] Move ShroudRenderer into a trait. --- OpenRA.Game/Graphics/WorldRenderer.cs | 6 +++--- OpenRA.Game/OpenRA.Game.csproj | 1 - OpenRA.Game/Traits/TraitsInterfaces.cs | 1 + OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 + .../Graphics => OpenRA.Mods.RA}/ShroudRenderer.cs | 12 +++++++++--- mods/cnc/rules/system.yaml | 1 + mods/d2k/rules/system.yaml | 1 + mods/ra/rules/system.yaml | 1 + mods/ts/rules/system.yaml | 1 + 9 files changed, 18 insertions(+), 7 deletions(-) rename {OpenRA.Game/Graphics => OpenRA.Mods.RA}/ShroudRenderer.cs (95%) diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 2195bb7b24..c4a6c96679 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -37,7 +37,6 @@ namespace OpenRA.Graphics public Viewport Viewport { get; private set; } internal readonly TerrainRenderer terrainRenderer; - internal readonly ShroudRenderer shroudRenderer; internal readonly HardwarePalette palette; internal Cache palettes; Lazy devTrait; @@ -56,7 +55,6 @@ namespace OpenRA.Graphics Theater = new Theater(world.TileSet); terrainRenderer = new TerrainRenderer(world, this); - shroudRenderer = new ShroudRenderer(world); devTrait = Lazy.New(() => world.LocalPlayer != null ? world.LocalPlayer.PlayerActor.Trait() : null); } @@ -132,7 +130,9 @@ namespace OpenRA.Graphics world.OrderGenerator.RenderAfterWorld(this, world); var renderShroud = world.RenderPlayer != null ? world.RenderPlayer.Shroud : null; - shroudRenderer.Draw(this, renderShroud); + + foreach (var a in world.ActorsWithTrait()) + a.Trait.RenderShroud(this, renderShroud); if (devTrait.Value != null && devTrait.Value.ShowDebugGeometry) for (var i = 0; i < renderables.Count; i++) diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 4830545e52..71489dd06d 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -110,7 +110,6 @@ - diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index d0447ab2f6..c95ef77b3f 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -191,6 +191,7 @@ namespace OpenRA.Traits public interface IBlocksBullets { } public interface IPostRender { void RenderAfterWorld(WorldRenderer wr, Actor self); } + public interface IRenderShroud { void RenderShroud(WorldRenderer wr, Shroud shroud); } public interface IPostRenderSelection { void RenderAfterWorld(WorldRenderer wr); } public interface IBodyOrientation diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 224c878321..980c6a412b 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -482,6 +482,7 @@ + diff --git a/OpenRA.Game/Graphics/ShroudRenderer.cs b/OpenRA.Mods.RA/ShroudRenderer.cs similarity index 95% rename from OpenRA.Game/Graphics/ShroudRenderer.cs rename to OpenRA.Mods.RA/ShroudRenderer.cs index 66a1c0e418..966db7b62b 100644 --- a/OpenRA.Game/Graphics/ShroudRenderer.cs +++ b/OpenRA.Mods.RA/ShroudRenderer.cs @@ -10,10 +10,16 @@ using System.Drawing; using OpenRA.Traits; +using OpenRA.Graphics; -namespace OpenRA.Graphics +namespace OpenRA.Mods.RA { - public class ShroudRenderer + public class ShroudRendererInfo : ITraitInfo + { + public object Create(ActorInitializer init) { return new ShroudRenderer(init.world); } + } + + public class ShroudRenderer : IRenderShroud { World world; Map map; @@ -148,7 +154,7 @@ namespace OpenRA.Graphics } } - internal void Draw(WorldRenderer wr, Shroud shroud) + public void RenderShroud(WorldRenderer wr, Shroud shroud) { if (initializePalettes) { diff --git a/mods/cnc/rules/system.yaml b/mods/cnc/rules/system.yaml index b12ddf9188..9198f570b8 100644 --- a/mods/cnc/rules/system.yaml +++ b/mods/cnc/rules/system.yaml @@ -277,6 +277,7 @@ World: ShroudPalette@combined: Name: shroudfog Type: Combined + ShroudRenderer: Country@gdi: Name: GDI Race: gdi diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index 7b4a68f1ae..36356f78c1 100644 --- a/mods/d2k/rules/system.yaml +++ b/mods/d2k/rules/system.yaml @@ -429,6 +429,7 @@ World: ShroudPalette@combined: Name: shroudfog Type: Combined + ShroudRenderer: Country@Atreides: Name: Atreides Race: atreides diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml index 2e3af5b920..d18cbb0b48 100644 --- a/mods/ra/rules/system.yaml +++ b/mods/ra/rules/system.yaml @@ -620,6 +620,7 @@ World: ShroudPalette@combined: Name: shroudfog Type: Combined + ShroudRenderer: Country@0: Name: Allies Race: allies diff --git a/mods/ts/rules/system.yaml b/mods/ts/rules/system.yaml index cc14e72d5e..1116eb43c5 100644 --- a/mods/ts/rules/system.yaml +++ b/mods/ts/rules/system.yaml @@ -105,6 +105,7 @@ World: ShroudPalette@combined: Name: shroudfog Type: Combined + ShroudRenderer: VoxelNormalsPalette@normals: Name: normals Type: TiberianSun From 4d709960125d5ce273748318e9d9db975617e929 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Tue, 10 Dec 2013 19:28:45 +1300 Subject: [PATCH 3/4] New shroud renderer. Fixes #2162. Fixes #3024. Fixes #4034. Uses the original tile sprites in C&C and D2K and uses a smoother transition in all mods. --- OpenRA.Game/Traits/World/Shroud.cs | 4 +- OpenRA.Mods.D2k/FogPaletteFromR8.cs | 59 +++++ OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj | 1 + OpenRA.Mods.RA/ShroudPalette.cs | 27 +- OpenRA.Mods.RA/ShroudRenderer.cs | 331 ++++++++++++++----------- mods/cnc/bits/shadow.shp | Bin 6687 -> 0 bytes mods/cnc/rules/system.yaml | 6 +- mods/cnc/sequences/misc.yaml | 16 +- mods/d2k/bits/shadow.shp | Bin 50430 -> 0 bytes mods/d2k/rules/system.yaml | 20 +- mods/d2k/sequences/misc.yaml | 22 ++ mods/ra/rules/system.yaml | 7 +- mods/ra/sequences/misc.yaml | 4 + mods/ts/rules/system.yaml | 7 +- mods/ts/sequences/misc.yaml | 4 + 15 files changed, 325 insertions(+), 183 deletions(-) create mode 100644 OpenRA.Mods.D2k/FogPaletteFromR8.cs delete mode 100644 mods/cnc/bits/shadow.shp delete mode 100644 mods/d2k/bits/shadow.shp diff --git a/OpenRA.Game/Traits/World/Shroud.cs b/OpenRA.Game/Traits/World/Shroud.cs index d53f8eeaa7..cf86cfa312 100644 --- a/OpenRA.Game/Traits/World/Shroud.cs +++ b/OpenRA.Game/Traits/World/Shroud.cs @@ -263,9 +263,7 @@ namespace OpenRA.Traits public bool IsVisible(CPos xy) { return IsVisible(xy.X, xy.Y); } public bool IsVisible(int x, int y) { - // Visibility is allowed to extend beyond the map cordon so that - // the fog tiles are not visible at the edge of the world - if (x < 0 || x >= map.MapSize.X || y < 0 || y >= map.MapSize.Y) + if (!map.IsInMap(x, y)) return false; if (Disabled || !self.World.LobbyInfo.GlobalSettings.Fog) diff --git a/OpenRA.Mods.D2k/FogPaletteFromR8.cs b/OpenRA.Mods.D2k/FogPaletteFromR8.cs new file mode 100644 index 0000000000..ce3b6792c4 --- /dev/null +++ b/OpenRA.Mods.D2k/FogPaletteFromR8.cs @@ -0,0 +1,59 @@ +#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.IO; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + class FogPaletteFromR8Info : ITraitInfo + { + [Desc("Internal palette name")] + public readonly string Name = null; + [Desc("Filename to load")] + public readonly string Filename = null; + [Desc("Palette byte offset")] + public readonly long Offset = 0; + public readonly bool AllowModifiers = true; + public readonly bool InvertColor = false; + + public object Create(ActorInitializer init) { return new FogPaletteFromR8(this); } + } + + class FogPaletteFromR8 : IPalette + { + readonly FogPaletteFromR8Info info; + public FogPaletteFromR8(FogPaletteFromR8Info info) { this.info = info; } + + public void InitPalette(WorldRenderer wr) + { + var colors = new uint[256]; + using (var s = FileSystem.Open(info.Filename)) + { + s.Seek(info.Offset, SeekOrigin.Begin); + + for (var i = 0; i < 256; i++) + { + var packed = s.ReadUInt16(); + + // Fog is rendered with half opacity + colors[i] = (uint)((255 << 24) | ((packed & 0xF800) << 7) | ((packed & 0x7E0) << 4) | ((packed & 0x1f) << 2)); + + if (info.InvertColor) + colors[i] ^= 0x00FFFFFF; + } + } + + wr.AddPalette(info.Name, new Palette(colors), info.AllowModifiers); + } + } +} diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj index b6fa211885..3d78f92267 100644 --- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj +++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj @@ -80,6 +80,7 @@ + diff --git a/OpenRA.Mods.RA/ShroudPalette.cs b/OpenRA.Mods.RA/ShroudPalette.cs index 247a87986e..9f1c8daf6f 100644 --- a/OpenRA.Mods.RA/ShroudPalette.cs +++ b/OpenRA.Mods.RA/ShroudPalette.cs @@ -15,8 +15,6 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { - public enum ShroudPaletteType { Shroud, Fog, Combined }; - [Desc("Adds the hard-coded shroud palette to the game")] class ShroudPaletteInfo : ITraitInfo { @@ -24,7 +22,7 @@ namespace OpenRA.Mods.RA public readonly string Name = "shroud"; [Desc("Palette type")] - public readonly ShroudPaletteType Type = ShroudPaletteType.Combined; + public readonly bool Fog = false; public object Create(ActorInitializer init) { return new ShroudPalette(this); } } @@ -37,35 +35,24 @@ namespace OpenRA.Mods.RA public void InitPalette(WorldRenderer wr) { - var c = info.Type == ShroudPaletteType.Shroud ? Shroud : - info.Type == ShroudPaletteType.Fog ? Fog : Combined; - + var c = info.Fog ? Fog : Shroud; wr.AddPalette(info.Name, new Palette(Exts.MakeArray(256, i => (uint)c[i % 8].ToArgb())), false); } - static Color[] Shroud = new[] { - Color.Transparent, Color.Green, - Color.Blue, Color.Yellow, - Color.Black, - Color.FromArgb(128,0,0,0), - Color.Transparent, - Color.Transparent - }; - static Color[] Fog = new[] { Color.Transparent, Color.Green, Color.Blue, Color.Yellow, Color.FromArgb(128,0,0,0), - Color.FromArgb(128,0,0,0), - Color.FromArgb(128,0,0,0), - Color.FromArgb(64,0,0,0) + Color.FromArgb(96,0,0,0), + Color.FromArgb(64,0,0,0), + Color.FromArgb(32,0,0,0) }; - static Color[] Combined = new[] { + static Color[] Shroud = new[] { Color.Transparent, Color.Green, Color.Blue, Color.Yellow, Color.Black, - Color.FromArgb(192,0,0,0), + Color.FromArgb(160,0,0,0), Color.FromArgb(128,0,0,0), Color.FromArgb(64,0,0,0) }; diff --git a/OpenRA.Mods.RA/ShroudRenderer.cs b/OpenRA.Mods.RA/ShroudRenderer.cs index 966db7b62b..32ec15794c 100644 --- a/OpenRA.Mods.RA/ShroudRenderer.cs +++ b/OpenRA.Mods.RA/ShroudRenderer.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * 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, @@ -8,110 +8,204 @@ */ #endregion +using System; +using System.Collections.Generic; using System.Drawing; -using OpenRA.Traits; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.FileFormats.Graphics; using OpenRA.Graphics; +using OpenRA.Traits; namespace OpenRA.Mods.RA { public class ShroudRendererInfo : ITraitInfo { - public object Create(ActorInitializer init) { return new ShroudRenderer(init.world); } + public string Sequence = "shroud"; + public string[] Variants = new[] { "shroud" }; + + [Desc("Bitfield of shroud directions for each frame. Lower four bits are", + "corners clockwise from TL; upper four are edges clockwise from top")] + public int[] Index = new[] { 12, 9, 8, 3, 1, 6, 4, 2, 13, 11, 7, 14 }; + + [Desc("Use the upper four bits when calculating frame")] + public bool UseExtendedIndex = false; + + [Desc("Palette index for synthesized unexplored tile")] + public int ShroudColor = 12; + public BlendMode ShroudBlend = BlendMode.Alpha; + public object Create(ActorInitializer init) { return new ShroudRenderer(init.world, this); } } - public class ShroudRenderer : IRenderShroud + public class ShroudRenderer : IRenderShroud, IWorldLoaded { - World world; - Map map; - Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow"); - Sprite[,] sprites, fogSprites; + struct ShroudTile + { + public CPos Position; + public float2 ScreenPosition; + public int Variant; + + public Sprite Fog; + public Sprite Shroud; + } + + Sprite[] sprites; + Sprite unexploredTile; + int[] spriteMap; + + ShroudTile[] tiles; + int tileStride, variantStride; + int shroudHash; - - bool initializePalettes = true; PaletteReference fogPalette, shroudPalette; + Rectangle bounds; + bool useExtendedIndex; - static readonly byte[][] SpecialShroudTiles = + public ShroudRenderer(World world, ShroudRendererInfo info) { - new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, - new byte[] { 32, 32, 25, 25, 19, 19, 20, 20 }, - new byte[] { 33, 33, 33, 33, 26, 26, 26, 26, 21, 21, 21, 21, 23, 23, 23, 23 }, - new byte[] { 36, 36, 36, 36, 30, 30, 30, 30 }, - new byte[] { 34, 16, 34, 16, 34, 16, 34, 16, 27, 22, 27, 22, 27, 22, 27, 22 }, - new byte[] { 44 }, - new byte[] { 37, 37, 37, 37, 37, 37, 37, 37, 31, 31, 31, 31, 31, 31, 31, 31 }, - new byte[] { 40 }, - new byte[] { 35, 24, 17, 18 }, - new byte[] { 39, 39, 29, 29 }, - new byte[] { 45 }, - new byte[] { 43 }, - new byte[] { 38, 28 }, - new byte[] { 42 }, - new byte[] { 41 }, - new byte[] { 46 }, - }; + var map = world.Map; + bounds = map.Bounds; + useExtendedIndex = info.UseExtendedIndex; - public ShroudRenderer(World world) - { - this.world = world; - this.map = world.Map; - - sprites = new Sprite[map.MapSize.X, map.MapSize.Y]; - fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y]; + tiles = new ShroudTile[map.MapSize.X * map.MapSize.Y]; + tileStride = map.MapSize.X; // Force update on first render shroudHash = -1; + + // Load sprite variants + sprites = new Sprite[info.Variants.Length * info.Index.Length]; + variantStride = info.Index.Length; + for (var j = 0; j < info.Variants.Length; j++) + { + var seq = SequenceProvider.GetSequence(info.Sequence, info.Variants[j]); + for (var i = 0; i < info.Index.Length; i++) + sprites[j * variantStride + i] = seq.GetSprite(i); + } + + // Mapping of shrouded directions -> sprite index + spriteMap = new int[useExtendedIndex ? 256 : 16]; + for (var i = 0; i < info.Index.Length; i++) + spriteMap[info.Index[i]] = i; + + // Set individual tile variants to reduce tiling + for (var i = 0; i < tiles.Length; i++) + tiles[i].Variant = Game.CosmeticRandom.Next(info.Variants.Length); + + // Synthesize unexplored tile if it isn't defined + if (!info.Index.Contains(0)) + { + var size = new Size(Game.modData.Manifest.TileSize, Game.modData.Manifest.TileSize); + var data = Exts.MakeArray(size.Width * size.Height, _ => (byte)info.ShroudColor); + var s = Game.modData.SheetBuilder.Add(data, size); + unexploredTile = new Sprite(s.sheet, s.bounds, s.offset, s.channel, info.ShroudBlend); + } + else + unexploredTile = sprites[spriteMap[0]]; } - Sprite ChooseShroud(Shroud s, int i, int j) + static int FoggedEdges(Shroud s, CPos p, bool useExtendedIndex) { - if (!s.IsExplored(i, j)) - return shadowBits[0xf]; + if (!s.IsVisible(p.X, p.Y)) + return 15; - // bits are for unexploredness: up, right, down, left - var v = 0; - // bits are for unexploredness: TL, TR, BR, BL + // If a side is shrouded then we also count the corners var u = 0; + if (!s.IsVisible(p.X, p.Y - 1)) u |= 0x13; + if (!s.IsVisible(p.X + 1, p.Y)) u |= 0x26; + if (!s.IsVisible(p.X, p.Y + 1)) u |= 0x4C; + if (!s.IsVisible(p.X - 1, p.Y)) u |= 0x89; - if (!s.IsExplored(i, j - 1)) { v |= 1; u |= 3; } - if (!s.IsExplored(i + 1, j)) { v |= 2; u |= 6; } - if (!s.IsExplored(i, j + 1)) { v |= 4; u |= 12; } - if (!s.IsExplored(i - 1, j)) { v |= 8; u |= 9; } + var uside = u & 0x0F; + if (!s.IsVisible(p.X - 1, p.Y - 1)) u |= 0x01; + if (!s.IsVisible(p.X + 1, p.Y - 1)) u |= 0x02; + if (!s.IsVisible(p.X + 1, p.Y + 1)) u |= 0x04; + if (!s.IsVisible(p.X - 1, p.Y + 1)) u |= 0x08; - var uSides = u; - if (!s.IsExplored(i - 1, j - 1)) u |= 1; - if (!s.IsExplored(i + 1, j - 1)) u |= 2; - if (!s.IsExplored(i + 1, j + 1)) u |= 4; - if (!s.IsExplored(i - 1, j + 1)) u |= 8; - - return shadowBits[SpecialShroudTiles[u ^ uSides][v]]; + // RA provides a set of frames for tiles with shrouded + // corners but unshrouded edges. We want to detect this + // situation without breaking the edge -> corner enabling + // in other combinations. The XOR turns off the corner + // bits that are enabled twice, which gives the behavior + // we want here. + return useExtendedIndex ? u ^ uside : u & 0x0F; } - Sprite ChooseFog(Shroud s, int i, int j) + static int ShroudedEdges(Shroud s, CPos p, bool useExtendedIndex) { - if (!s.IsVisible(i, j)) return shadowBits[0xf]; - if (!s.IsExplored(i, j)) return shadowBits[0xf]; + if (!s.IsExplored(p.X, p.Y)) + return 15; - // bits are for unexploredness: up, right, down, left - var v = 0; - // bits are for unexploredness: TL, TR, BR, BL + // If a side is shrouded then we also count the corners var u = 0; + if (!s.IsExplored(p.X, p.Y - 1)) u |= 0x13; + if (!s.IsExplored(p.X + 1, p.Y)) u |= 0x26; + if (!s.IsExplored(p.X, p.Y + 1)) u |= 0x4C; + if (!s.IsExplored(p.X - 1, p.Y)) u |= 0x89; - if (!s.IsVisible(i, j - 1)) { v |= 1; u |= 3; } - if (!s.IsVisible(i + 1, j)) { v |= 2; u |= 6; } - if (!s.IsVisible(i, j + 1)) { v |= 4; u |= 12; } - if (!s.IsVisible(i - 1, j)) { v |= 8; u |= 9; } + var uside = u & 0x0F; + if (!s.IsExplored(p.X - 1, p.Y - 1)) u |= 0x01; + if (!s.IsExplored(p.X + 1, p.Y - 1)) u |= 0x02; + if (!s.IsExplored(p.X + 1, p.Y + 1)) u |= 0x04; + if (!s.IsExplored(p.X - 1, p.Y + 1)) u |= 0x08; - var uSides = u; - - if (!s.IsVisible(i - 1, j - 1)) u |= 1; - if (!s.IsVisible(i + 1, j - 1)) u |= 2; - if (!s.IsVisible(i + 1, j + 1)) u |= 4; - if (!s.IsVisible(i - 1, j + 1)) u |= 8; - - return shadowBits[SpecialShroudTiles[u ^ uSides][v]]; + // RA provides a set of frames for tiles with shrouded + // corners but unshrouded edges. We want to detect this + // situation without breaking the edge -> corner enabling + // in other combinations. The XOR turns off the corner + // bits that are enabled twice, which gives the behavior + // we want here. + return useExtendedIndex ? u ^ uside : u & 0x0F; } - void GenerateSprites(Shroud shroud) + static int ObserverShroudedEdges(CPos p, Rectangle bounds, bool useExtendedIndex) + { + var u = 0; + if (p.Y == bounds.Top) u |= 0x13; + if (p.X == bounds.Right - 1) u |= 0x26; + if (p.Y == bounds.Bottom - 1) u |= 0x4C; + if (p.X == bounds.Left) u |= 0x89; + + var uside = u & 0x0F; + if (p.X == bounds.Left && p.Y == bounds.Top) u |= 0x01; + if (p.X == bounds.Right - 1 && p.Y == bounds.Top) u |= 0x02; + if (p.X == bounds.Right - 1 && p.Y == bounds.Bottom - 1) u |= 0x04; + if (p.X == bounds.Left && p.Y == bounds.Bottom - 1) u |= 0x08; + + return useExtendedIndex ? u ^ uside : u & 0x0F; + } + + public void WorldLoaded(World w, WorldRenderer wr) + { + // Cache the tile positions to avoid unnecessary calculations + for (var i = bounds.Left; i < bounds.Right; i++) + { + for (var j = bounds.Top; j < bounds.Bottom; j++) + { + var k = j * tileStride + i; + tiles[k].Position = new CPos(i, j); + tiles[k].ScreenPosition = wr.ScreenPosition(tiles[k].Position.CenterPosition); + } + } + + if (w.LobbyInfo.GlobalSettings.Fog) + fogPalette = wr.Palette("fog"); + + shroudPalette = wr.Palette("shroud"); + } + + Sprite GetTile(int flags, int variant) + { + if (flags == 0) + return null; + + if (flags == 15) + return unexploredTile; + + return sprites[variant * variantStride + spriteMap[flags]]; + } + + void Update(Shroud shroud) { var hash = shroud != null ? shroud.Hash : 0; if (shroudHash == hash) @@ -121,95 +215,52 @@ namespace OpenRA.Mods.RA if (shroud == null) { // Players with no shroud see the whole map so we only need to set the edges - var b = map.Bounds; - for (int i = b.Left; i < b.Right; i++) - for (int j = b.Top; j < b.Bottom; j++) + for (var k = 0; k < tiles.Length; k++) { - var v = 0; - var u = 0; - - if (j == b.Top) { v |= 1; u |= 3; } - if (i == b.Right - 1) { v |= 2; u |= 6; } - if (j == b.Bottom - 1) { v |= 4; u |= 12; } - if (i == b.Left) { v |= 8; u |= 9; } - - var uSides = u; - if (i == b.Left && j == b.Top) u |= 1; - if (i == b.Right - 1 && j == b.Top) u |= 2; - if (i == b.Right - 1 && j == b.Bottom - 1) u |= 4; - if (i == b.Left && j == b.Bottom - 1) u |= 8; - - sprites[i, j] = fogSprites[i, j] = shadowBits[SpecialShroudTiles[u ^ uSides][v]]; + var shrouded = ObserverShroudedEdges(tiles[k].Position, bounds, useExtendedIndex); + tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant); + tiles[k].Fog = GetTile(shrouded, tiles[k].Variant); } } else { - for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - sprites[i, j] = ChooseShroud(shroud, i, j); + for (var k = 0; k < tiles.Length; k++) + { + var shrouded = ShroudedEdges(shroud, tiles[k].Position, useExtendedIndex); + var fogged = FoggedEdges(shroud, tiles[k].Position, useExtendedIndex); - for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - fogSprites[i, j] = ChooseFog(shroud, i, j); + tiles[k].Shroud = GetTile(shrouded, tiles[k].Variant); + tiles[k].Fog = GetTile(fogged, tiles[k].Variant); + } } } public void RenderShroud(WorldRenderer wr, Shroud shroud) { - if (initializePalettes) - { - if (world.LobbyInfo.GlobalSettings.Fog) - fogPalette = wr.Palette("fog"); + Update(shroud); - shroudPalette = world.LobbyInfo.GlobalSettings.Fog ? wr.Palette("shroud") : wr.Palette("shroudfog"); - initializePalettes = false; - } - - GenerateSprites(shroud); - - // We draw the shroud when disabled to hide the sharp map edges - var clipRect = wr.Viewport.CellBounds; - DrawShroud(wr, clipRect, sprites, shroudPalette); - - if (world.LobbyInfo.GlobalSettings.Fog) - DrawShroud(wr, clipRect, fogSprites, fogPalette); - } - - void DrawShroud(WorldRenderer wr, Rectangle clip, Sprite[,] s, PaletteReference pal) - { + var clip = wr.Viewport.CellBounds; + var width = clip.Width; for (var j = clip.Top; j < clip.Bottom; j++) { - var starti = clip.Left; - var last = shadowBits[0x0f]; - for (var i = clip.Left; i < clip.Right; i++) + var start = j * tileStride + clip.Left; + for (var k = 0; k < width; k++) { - if ((s[i, j] == shadowBits[0x0f] && last == shadowBits[0x0f]) - || (s[i, j] == shadowBits[0] && last == shadowBits[0])) - continue; + var s = tiles[start + k].Shroud; + var f = tiles[start + k].Fog; - if (starti != i) + if (s != null) { - // Stretch a solid black sprite over the rows above - // TODO: This doesn't make sense for isometric terrain - Game.Renderer.WorldSpriteRenderer.DrawSprite( - s[starti, j], - Game.CellSize * new float2(starti, j), - pal, - new float2(Game.CellSize * (i - starti), Game.CellSize)); - starti = i + 1; + var pos = tiles[start + k].ScreenPosition - 0.5f * s.size; + Game.Renderer.WorldSpriteRenderer.DrawSprite(s, pos, shroudPalette); } - Game.Renderer.WorldSpriteRenderer.DrawSprite(s[i, j], Game.CellSize * new float2(i, j), pal); - starti = i + 1; - last = s[i, j]; + if (f != null) + { + var pos = tiles[start + k].ScreenPosition - 0.5f * f.size; + Game.Renderer.WorldSpriteRenderer.DrawSprite(f, pos, fogPalette); + } } - - // Stretch a solid black sprite over the rows to the left - // TODO: This doesn't make sense for isometric terrain - if (starti < clip.Right) - Game.Renderer.WorldSpriteRenderer.DrawSprite(s[starti, j], - Game.CellSize * new float2(starti, j), pal, - new float2(Game.CellSize * (clip.Right - starti), Game.CellSize)); } } } diff --git a/mods/cnc/bits/shadow.shp b/mods/cnc/bits/shadow.shp deleted file mode 100644 index 8d7d7e76ca90c5430a45a6936924f8e41a09ec28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6687 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 NRLB4Q9QuEU{{sXehfDwf diff --git a/mods/cnc/rules/system.yaml b/mods/cnc/rules/system.yaml index 9198f570b8..ca3a0f8a1a 100644 --- a/mods/cnc/rules/system.yaml +++ b/mods/cnc/rules/system.yaml @@ -273,11 +273,9 @@ World: Type: Shroud ShroudPalette@fog: Name: fog - Type: Fog - ShroudPalette@combined: - Name: shroudfog - Type: Combined + Fog: true ShroudRenderer: + Variants: typea, typeb, typec, typed Country@gdi: Name: GDI Race: gdi diff --git a/mods/cnc/sequences/misc.yaml b/mods/cnc/sequences/misc.yaml index 06dbc7546a..ad893668bd 100644 --- a/mods/cnc/sequences/misc.yaml +++ b/mods/cnc/sequences/misc.yaml @@ -360,4 +360,18 @@ resources: bti11: bti11 Length: * bti12: bti12 - Length: * \ No newline at end of file + Length: * + +shroud: + typea: shadow + Start: 0 + Length: 12 + typeb: shadow + Start: 12 + Length: 12 + typec: shadow + Start: 24 + Length: 12 + typed: shadow + Start: 36 + Length: 12 \ No newline at end of file diff --git a/mods/d2k/bits/shadow.shp b/mods/d2k/bits/shadow.shp deleted file mode 100644 index 286da4a8f5aa657335d2ba61ac090701fa65c274..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50430 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 M$KHRBYoERSKUM^_Z2$lO diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index 36356f78c1..1079401928 100644 --- a/mods/d2k/rules/system.yaml +++ b/mods/d2k/rules/system.yaml @@ -421,15 +421,21 @@ World: G: 0 B: 0 A: 180 - ShroudPalette@shroud: - Type: Shroud - ShroudPalette@fog: + PaletteFromR8@shroud: + Name: shroud + Filename: DATA.R8 + Offset: 12007 + InvertColor: true + FogPaletteFromR8@fog: Name: fog - Type: Fog - ShroudPalette@combined: - Name: shroudfog - Type: Combined + Filename: DATA.R8 + Offset: 12007 + InvertColor: true ShroudRenderer: + Variants: typea, typeb, typec, typed + Index: 11, 3, 7, 9, 6, 13, 12, 14, 4, 8, 2, 1, 5, 10 + ShroudColor: 31 + ShroudBlend: Multiply Country@Atreides: Name: Atreides Race: atreides diff --git a/mods/d2k/sequences/misc.yaml b/mods/d2k/sequences/misc.yaml index df39400d6c..533476230d 100644 --- a/mods/d2k/sequences/misc.yaml +++ b/mods/d2k/sequences/misc.yaml @@ -311,3 +311,25 @@ resources: Frames: 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 300, 301, 320, 321 Length: 54 Offset: -16,-16 + +shroud: + typea: DATA + Start: 40 + Length: 14 + Offset: -16,-16 + BlendMode: Multiply + typeb: DATA + Start: 56 + Length: 14 + Offset: -16,-16 + BlendMode: Multiply + typec: DATA + Start: 72 + Length: 14 + Offset: -16,-16 + BlendMode: Multiply + typed: DATA + Start: 88 + Length: 14 + Offset: -16,-16 + BlendMode: Multiply diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml index d18cbb0b48..d125c58b59 100644 --- a/mods/ra/rules/system.yaml +++ b/mods/ra/rules/system.yaml @@ -616,11 +616,10 @@ World: Type: Shroud ShroudPalette@fog: Name: fog - Type: Fog - ShroudPalette@combined: - Name: shroudfog - Type: Combined + Fog: true ShroudRenderer: + Index: 255, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 20, 40, 56, 65, 97, 130, 148, 194, 24, 33, 66, 132, 28, 41, 67, 134, 1, 2, 4, 8, 3, 6, 12, 9, 7, 14, 13, 11, 5, 10, 15, 255 + UseExtendedIndex: true Country@0: Name: Allies Race: allies diff --git a/mods/ra/sequences/misc.yaml b/mods/ra/sequences/misc.yaml index 3016ebea10..5db38a16db 100644 --- a/mods/ra/sequences/misc.yaml +++ b/mods/ra/sequences/misc.yaml @@ -486,4 +486,8 @@ resources: gem03: gem03 Length: * gem04: gem04 + Length: * + +shroud: + shroud: shadow Length: * \ No newline at end of file diff --git a/mods/ts/rules/system.yaml b/mods/ts/rules/system.yaml index 1116eb43c5..81e8c48519 100644 --- a/mods/ts/rules/system.yaml +++ b/mods/ts/rules/system.yaml @@ -101,11 +101,10 @@ World: Type: Shroud ShroudPalette@fog: Name: fog - Type: Fog - ShroudPalette@combined: - Name: shroudfog - Type: Combined + Fog: true ShroudRenderer: + Index: 255, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 20, 40, 56, 65, 97, 130, 148, 194, 24, 33, 66, 132, 28, 41, 67, 134, 1, 2, 4, 8, 3, 6, 12, 9, 7, 14, 13, 11, 5, 10, 15, 255 + UseExtendedIndex: true VoxelNormalsPalette@normals: Name: normals Type: TiberianSun diff --git a/mods/ts/sequences/misc.yaml b/mods/ts/sequences/misc.yaml index b14c3c5006..d0b62f2f01 100644 --- a/mods/ts/sequences/misc.yaml +++ b/mods/ts/sequences/misc.yaml @@ -253,4 +253,8 @@ moveflsh: # TODO: placeholder resources: fake: shadow + Length: * + +shroud: + shroud: shadow Length: * \ No newline at end of file From 186cc55d6edbb95a4154868dd2bf699b9145c1a0 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 11 Dec 2013 20:54:40 +1300 Subject: [PATCH 4/4] Update CHANGELOG. --- CHANGELOG | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 80756395ff..6148371f7c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ NEW: Added a new hotkey to select all units on screen (default: CTRL + A). Added a new hotkey to jump to production buildings (default: TAB). Changed default hotkey (PageUp/Down) for build palette cycling and made reverse user configurable. + Improved shroud/fog rendering. Asset Browser: Fixed crashes when trying to load invalid filenames or sprites with just 1 frame. Added support for all sprite types. @@ -73,6 +74,7 @@ NEW: Disabled the main menu target reticle showing when a window is open. Added a display of the faction logos when the shellmap is disabled. Visceriods now heal on Tiberium and move faster there. + Implemented the original shroud artwork. Dune 2000: Added buildable concrete walls. Fixed some cliffs being passable. @@ -80,6 +82,7 @@ NEW: Fixed A* debug overlay. Fixed R8 offsets for sprites with embedded palettes. Implemented proper spice rendering. + Implemented the original shroud artwork. Engine: Replays are now saved in per-mod and per-version folders. Added password protection support for servers. @@ -99,6 +102,7 @@ NEW: Rewritten shp(ts) parser makes more efficient use of texture space. Added support for the dune 2 shp and pak formats. Map format 6 requires the RequiresMod to be defined. + Added a multiplicitive blend mode. Build system and packages: Added GeoIP to Makefile so it is installed properly. Added desktop shortcut creation support to the Makefile and Windows installer. @@ -137,7 +141,8 @@ NEW: Added OpenRA.Utility --map-upgrade for updating maps from format 5 to format 6. The map format has been changed. All user-installed maps will be upgraded on the first mod launch, or using OpenRA.Utility --map-upgrade. Unified sprite loading allows any sprite type to be used anywhere: shp can now be used for terrain, and tmp for units. - Harvestable resource definitions (ResourceTypes) have changed, and now specify their artwork using via sequences. + Harvestable resource definitions (ResourceTypes) have changed, and now specify their artwork using sequences. + Shroud definitions (ShroudRenderer / ShroudPalette) have changed, and now specifies its artwork using sequences. 20130915: All mods: