diff --git a/OpenRA.Mods.Cnc/CncLoadScreen.cs b/OpenRA.Mods.Cnc/CncLoadScreen.cs index 9ebbd54d7b..ba71435ad8 100644 --- a/OpenRA.Mods.Cnc/CncLoadScreen.cs +++ b/OpenRA.Mods.Cnc/CncLoadScreen.cs @@ -10,108 +10,101 @@ #endregion using System.Collections.Generic; -using System.Diagnostics; using OpenRA.Graphics; using OpenRA.Mods.Common.LoadScreens; using OpenRA.Mods.Common.Widgets; using OpenRA.Primitives; -using OpenRA.Widgets; namespace OpenRA.Mods.Cnc { - public sealed class CncLoadScreen : BlankLoadScreen + public sealed class CncLoadScreen : SheetLoadScreen { - readonly NullInputHandler nih = new NullInputHandler(); - - Dictionary loadInfo; - Stopwatch loadTimer = Stopwatch.StartNew(); - Sheet sheet; - Sprite[] border; int loadTick; - float2 nodPos, gdiPos, evaPos; + Sprite nodLogo, gdiLogo, evaLogo, brightBlock, dimBlock; + Sprite[] border; + float2 nodPos, gdiPos, evaPos; Rectangle bounds; - Renderer r; + + SpriteFont loadingFont, versionFont; + string loadingText, versionText; + float2 loadingPos, versionPos; + + Sheet lastSheet; + Size lastResolution; + IReadOnlyDictionary lastFonts; public override void Init(ModData modData, Dictionary info) { base.Init(modData, info); - loadInfo = info; - - // Avoid standard loading mechanisms so we - // can display loadscreen as early as possible - r = Game.Renderer; - if (r == null) return; - - using (var stream = modData.DefaultFileSystem.Open(info["Image"])) - sheet = new Sheet(SheetType.BGRA, stream); - - var res = r.Resolution; - bounds = new Rectangle(0, 0, res.Width, res.Height); - - border = new[] - { - new Sprite(sheet, new Rectangle(129, 129, 32, 32), TextureChannel.RGBA), - new Sprite(sheet, new Rectangle(161, 129, 62, 32), TextureChannel.RGBA), - new Sprite(sheet, new Rectangle(223, 129, 32, 32), TextureChannel.RGBA), - new Sprite(sheet, new Rectangle(129, 161, 32, 62), TextureChannel.RGBA), - null, - new Sprite(sheet, new Rectangle(223, 161, 32, 62), TextureChannel.RGBA), - new Sprite(sheet, new Rectangle(129, 223, 32, 32), TextureChannel.RGBA), - new Sprite(sheet, new Rectangle(161, 223, 62, 32), TextureChannel.RGBA), - new Sprite(sheet, new Rectangle(223, 223, 32, 32), TextureChannel.RGBA) - }; - - nodLogo = new Sprite(sheet, new Rectangle(0, 256, 256, 256), TextureChannel.RGBA); - gdiLogo = new Sprite(sheet, new Rectangle(256, 256, 256, 256), TextureChannel.RGBA); - evaLogo = new Sprite(sheet, new Rectangle(769, 320, 128, 64), TextureChannel.RGBA); - nodPos = new float2(bounds.Width / 2 - 384, bounds.Height / 2 - 128); - gdiPos = new float2(bounds.Width / 2 + 128, bounds.Height / 2 - 128); - evaPos = new float2(bounds.Width - 43 - 128, 43); - - brightBlock = new Sprite(sheet, new Rectangle(777, 385, 16, 35), TextureChannel.RGBA); - dimBlock = new Sprite(sheet, new Rectangle(794, 385, 16, 35), TextureChannel.RGBA); - versionText = modData.Manifest.Metadata.Version; } - object rendererFonts; - SpriteFont loadingFont, versionFont; - string loadingText, versionText; - float2 loadingPos, versionPos; - - public override void Display() + public override void DisplayInner(Renderer r, Sheet s) { - if (r == null || loadTimer.Elapsed.TotalSeconds < 0.25) - return; + if (s != lastSheet) + { + lastSheet = s; - loadTimer.Restart(); + border = new[] + { + new Sprite(s, new Rectangle(129, 129, 32, 32), TextureChannel.RGBA), + new Sprite(s, new Rectangle(161, 129, 62, 32), TextureChannel.RGBA), + new Sprite(s, new Rectangle(223, 129, 32, 32), TextureChannel.RGBA), + new Sprite(s, new Rectangle(129, 161, 32, 62), TextureChannel.RGBA), + null, + new Sprite(s, new Rectangle(223, 161, 32, 62), TextureChannel.RGBA), + new Sprite(s, new Rectangle(129, 223, 32, 32), TextureChannel.RGBA), + new Sprite(s, new Rectangle(161, 223, 62, 32), TextureChannel.RGBA), + new Sprite(s, new Rectangle(223, 223, 32, 32), TextureChannel.RGBA) + }; + + nodLogo = new Sprite(s, new Rectangle(0, 256, 256, 256), TextureChannel.RGBA); + gdiLogo = new Sprite(s, new Rectangle(256, 256, 256, 256), TextureChannel.RGBA); + evaLogo = new Sprite(s, new Rectangle(769, 320, 128, 64), TextureChannel.RGBA); + + brightBlock = new Sprite(s, new Rectangle(777, 385, 16, 35), TextureChannel.RGBA); + dimBlock = new Sprite(s, new Rectangle(794, 385, 16, 35), TextureChannel.RGBA); + } + + if (r.Resolution != lastResolution) + { + lastResolution = r.Resolution; + + bounds = new Rectangle(0, 0, lastResolution.Width, lastResolution.Height); + nodPos = new float2(bounds.Width / 2 - 384, bounds.Height / 2 - 128); + gdiPos = new float2(bounds.Width / 2 + 128, bounds.Height / 2 - 128); + evaPos = new float2(bounds.Width - 43 - 128, 43); + } + + var barY = bounds.Height - 78; + + // The fonts dictionary may change when switching between the mod and content installer + if (r.Fonts != lastFonts) + { + lastFonts = r.Fonts; + + loadingFont = lastFonts["BigBold"]; + loadingText = Info["Text"]; + loadingPos = new float2((bounds.Width - loadingFont.Measure(loadingText).X) / 2, barY); + + versionFont = lastFonts["Regular"]; + var versionSize = versionFont.Measure(versionText); + versionPos = new float2(bounds.Width - 107 - versionSize.X / 2, 115 - versionSize.Y / 2); + } loadTick = ++loadTick % 8; - r.BeginUI(); + r.RgbaSpriteRenderer.DrawSprite(gdiLogo, gdiPos); r.RgbaSpriteRenderer.DrawSprite(nodLogo, nodPos); r.RgbaSpriteRenderer.DrawSprite(evaLogo, evaPos); WidgetUtils.DrawPanel(bounds, border); - var barY = bounds.Height - 78; - - // The fonts dictionary may change when switching between the mod and content installer - if (r.Fonts != rendererFonts) - { - rendererFonts = r.Fonts; - loadingFont = r.Fonts["BigBold"]; - loadingText = loadInfo["Text"]; - loadingPos = new float2((bounds.Width - loadingFont.Measure(loadingText).X) / 2, barY); - - versionFont = r.Fonts["Regular"]; - var versionSize = versionFont.Measure(versionText); - versionPos = new float2(bounds.Width - 107 - versionSize.X / 2, 115 - versionSize.Y / 2); - } if (loadingFont != null) loadingFont.DrawText(loadingText, loadingPos, Color.Gray); + if (versionFont != null) versionFont.DrawTextWithContrast(versionText, versionPos, Color.White, Color.Black, 2); @@ -123,16 +116,6 @@ namespace OpenRA.Mods.Cnc r.RgbaSpriteRenderer.DrawSprite(block, new float2(bounds.Width / 2 + 114 + i * 32 - 16, barY)); } - - r.EndFrame(nih); - } - - protected override void Dispose(bool disposing) - { - if (disposing && sheet != null) - sheet.Dispose(); - - base.Dispose(disposing); } } } diff --git a/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs index dea6d16335..dd48dd178d 100644 --- a/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs @@ -22,11 +22,11 @@ namespace OpenRA.Mods.Common.LoadScreens public class BlankLoadScreen : ILoadScreen { public LaunchArguments Launch; - ModData modData; + protected ModData ModData { get; private set; } public virtual void Init(ModData modData, Dictionary info) { - this.modData = modData; + ModData = modData; } public virtual void Display() @@ -110,14 +110,14 @@ namespace OpenRA.Mods.Common.LoadScreens GC.SuppressFinalize(this); } - public bool BeforeLoad() + public virtual bool BeforeLoad() { // If a ModContent section is defined then we need to make sure that the // required content is installed or switch to the defined content installer. - if (!modData.Manifest.Contains()) + if (!ModData.Manifest.Contains()) return true; - var content = modData.Manifest.Get(); + var content = ModData.Manifest.Get(); var contentInstalled = content.Packages .Where(p => p.Value.Required) .All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f)))); @@ -125,7 +125,7 @@ namespace OpenRA.Mods.Common.LoadScreens if (contentInstalled) return true; - Game.InitializeMod(content.ContentInstallerMod, new Arguments(new[] { "Content.Mod=" + modData.Manifest.Id })); + Game.InitializeMod(content.ContentInstallerMod, new Arguments(new[] { "Content.Mod=" + ModData.Manifest.Id })); return false; } } diff --git a/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs index aa3331e592..b80dda18e0 100644 --- a/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/LogoStripeLoadScreen.cs @@ -9,68 +9,48 @@ */ #endregion +using System; using System.Collections.Generic; -using System.Diagnostics; using OpenRA.Graphics; using OpenRA.Mods.Common.Widgets; using OpenRA.Primitives; -using OpenRA.Widgets; namespace OpenRA.Mods.Common.LoadScreens { - public sealed class LogoStripeLoadScreen : BlankLoadScreen + public sealed class LogoStripeLoadScreen : SheetLoadScreen { - Stopwatch lastUpdate = Stopwatch.StartNew(); - Renderer r; - Rectangle stripeRect; float2 logoPos; - Sheet sheet; Sprite stripe, logo; + + Sheet lastSheet; + Size lastResolution; + string[] messages = { "Loading..." }; public override void Init(ModData modData, Dictionary info) { base.Init(modData, info); - // Avoid standard loading mechanisms so we - // can display the loadscreen as early as possible - r = Game.Renderer; - if (r == null) - return; - if (info.ContainsKey("Text")) messages = info["Text"].Split(','); - - if (info.ContainsKey("Image")) - { - using (var stream = modData.DefaultFileSystem.Open(info["Image"])) - sheet = new Sheet(SheetType.BGRA, stream); - - logo = new Sprite(sheet, new Rectangle(0, 0, 256, 256), TextureChannel.RGBA); - stripe = new Sprite(sheet, new Rectangle(258, 0, 253, 256), TextureChannel.RGBA); - stripeRect = new Rectangle(0, r.Resolution.Height / 2 - 128, r.Resolution.Width, 256); - logoPos = new float2(r.Resolution.Width / 2 - 128, r.Resolution.Height / 2 - 128); - } } - public override void Display() + public override void DisplayInner(Renderer r, Sheet s) { - if (r == null) - return; + if (s != lastSheet) + { + lastSheet = s; + logo = new Sprite(s, new Rectangle(0, 0, 256, 256), TextureChannel.RGBA); + stripe = new Sprite(s, new Rectangle(258, 0, 253, 256), TextureChannel.RGBA); + } - // Update text at most every 0.5 seconds - if (lastUpdate.Elapsed.TotalSeconds < 0.5) - return; - - if (r.Fonts == null) - return; - - lastUpdate.Restart(); - var text = messages.Random(Game.CosmeticRandom); - var textSize = r.Fonts["Bold"].Measure(text); - - r.BeginUI(); + if (r.Resolution != lastResolution) + { + lastResolution = r.Resolution; + stripeRect = new Rectangle(0, lastResolution.Height / 2 - 128, lastResolution.Width, 256); + logoPos = new float2(lastResolution.Width / 2 - 128, lastResolution.Height / 2 - 128); + } if (stripe != null) WidgetUtils.FillRectWithSprite(stripeRect, stripe); @@ -78,16 +58,12 @@ namespace OpenRA.Mods.Common.LoadScreens if (logo != null) r.RgbaSpriteRenderer.DrawSprite(logo, logoPos); - r.Fonts["Bold"].DrawText(text, new float2(r.Resolution.Width - textSize.X - 20, r.Resolution.Height - textSize.Y - 20), Color.White); - r.EndFrame(new NullInputHandler()); - } - - protected override void Dispose(bool disposing) - { - if (disposing && sheet != null) - sheet.Dispose(); - - base.Dispose(disposing); + if (r.Fonts != null) + { + var text = messages.Random(Game.CosmeticRandom); + var textSize = r.Fonts["Bold"].Measure(text); + r.Fonts["Bold"].DrawText(text, new float2(r.Resolution.Width - textSize.X - 20, r.Resolution.Height - textSize.Y - 20), Color.White); + } } } } diff --git a/OpenRA.Mods.Common/LoadScreens/ModContentLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/ModContentLoadScreen.cs index 6ccf6f508e..e9e5027465 100644 --- a/OpenRA.Mods.Common/LoadScreens/ModContentLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/ModContentLoadScreen.cs @@ -10,7 +10,6 @@ #endregion using System; -using System.Collections.Generic; using System.IO; using System.Linq; using OpenRA.Graphics; @@ -20,35 +19,32 @@ using OpenRA.Widgets; namespace OpenRA.Mods.Common.LoadScreens { - public sealed class ModContentLoadScreen : ILoadScreen + public sealed class ModContentLoadScreen : SheetLoadScreen { Sprite sprite; Rectangle bounds; - public void Init(ModData modData, Dictionary info) - { - var res = Game.Renderer.Resolution; - bounds = new Rectangle(0, 0, res.Width, res.Height); + Sheet lastSheet; + Size lastResolution; - using (var stream = modData.DefaultFileSystem.Open(info["Image"])) + public override void DisplayInner(Renderer r, Sheet s) + { + if (s != lastSheet) { - var sheet = new Sheet(SheetType.BGRA, stream); - sprite = new Sprite(sheet, new Rectangle(0, 0, 1024, 480), TextureChannel.RGBA); + lastSheet = s; + sprite = new Sprite(s, new Rectangle(0, 0, 1024, 480), TextureChannel.RGBA); } - } - public void Display() - { - var r = Game.Renderer; - if (r == null) - return; + if (r.Resolution != lastResolution) + { + lastResolution = r.Resolution; + bounds = new Rectangle(0, 0, lastResolution.Width, lastResolution.Height); + } - r.BeginUI(); WidgetUtils.FillRectWithSprite(bounds, sprite); - r.EndFrame(new NullInputHandler()); } - public void StartGame(Arguments args) + public override void StartGame(Arguments args) { var modId = args.GetValue("Content.Mod", null); Manifest selectedMod; @@ -90,13 +86,7 @@ namespace OpenRA.Mods.Common.LoadScreens .All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f)))); } - public void Dispose() - { - if (sprite != null) - sprite.Sheet.Dispose(); - } - - public bool BeforeLoad() + public override bool BeforeLoad() { return true; } diff --git a/OpenRA.Mods.Common/LoadScreens/SheetLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/SheetLoadScreen.cs new file mode 100644 index 0000000000..6d276c340d --- /dev/null +++ b/OpenRA.Mods.Common/LoadScreens/SheetLoadScreen.cs @@ -0,0 +1,62 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Diagnostics; +using OpenRA.Graphics; + +namespace OpenRA.Mods.Common.LoadScreens +{ + public abstract class SheetLoadScreen : BlankLoadScreen + { + Stopwatch lastUpdate; + + protected Dictionary Info { get; private set; } + Sheet sheet; + + public override void Init(ModData modData, Dictionary info) + { + base.Init(modData, info); + Info = info; + } + + public abstract void DisplayInner(Renderer r, Sheet s); + + public override void Display() + { + // Limit load screens to at most 5 FPS + if (Game.Renderer == null || (lastUpdate != null && lastUpdate.Elapsed.TotalSeconds < 0.2)) + return; + + // Start the timer on the first render + if (lastUpdate == null) + lastUpdate = Stopwatch.StartNew(); + + if (sheet == null && Info.ContainsKey("Image")) + using (var stream = ModData.DefaultFileSystem.Open(Info["Image"])) + sheet = new Sheet(SheetType.BGRA, stream); + + Game.Renderer.BeginUI(); + DisplayInner(Game.Renderer, sheet); + Game.Renderer.EndFrame(new NullInputHandler()); + + lastUpdate.Restart(); + } + + protected override void Dispose(bool disposing) + { + if (disposing && sheet != null) + sheet.Dispose(); + + base.Dispose(disposing); + } + } +}