Extract load screen sheet handling into a superclass.

This commit is contained in:
Paul Chote
2020-01-26 16:11:37 +00:00
committed by abcdefg30
parent 57a8cf7a59
commit 518450cd8a
5 changed files with 172 additions and 161 deletions

View File

@@ -10,108 +10,101 @@
#endregion #endregion
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.Common.LoadScreens; using OpenRA.Mods.Common.LoadScreens;
using OpenRA.Mods.Common.Widgets; using OpenRA.Mods.Common.Widgets;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Widgets;
namespace OpenRA.Mods.Cnc namespace OpenRA.Mods.Cnc
{ {
public sealed class CncLoadScreen : BlankLoadScreen public sealed class CncLoadScreen : SheetLoadScreen
{ {
readonly NullInputHandler nih = new NullInputHandler();
Dictionary<string, string> loadInfo;
Stopwatch loadTimer = Stopwatch.StartNew();
Sheet sheet;
Sprite[] border;
int loadTick; int loadTick;
float2 nodPos, gdiPos, evaPos;
Sprite nodLogo, gdiLogo, evaLogo, brightBlock, dimBlock; Sprite nodLogo, gdiLogo, evaLogo, brightBlock, dimBlock;
Sprite[] border;
float2 nodPos, gdiPos, evaPos;
Rectangle bounds; Rectangle bounds;
Renderer r;
SpriteFont loadingFont, versionFont;
string loadingText, versionText;
float2 loadingPos, versionPos;
Sheet lastSheet;
Size lastResolution;
IReadOnlyDictionary<string, SpriteFont> lastFonts;
public override void Init(ModData modData, Dictionary<string, string> info) public override void Init(ModData modData, Dictionary<string, string> info)
{ {
base.Init(modData, 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; versionText = modData.Manifest.Metadata.Version;
} }
object rendererFonts; public override void DisplayInner(Renderer r, Sheet s)
SpriteFont loadingFont, versionFont;
string loadingText, versionText;
float2 loadingPos, versionPos;
public override void Display()
{ {
if (r == null || loadTimer.Elapsed.TotalSeconds < 0.25) if (s != lastSheet)
return; {
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; loadTick = ++loadTick % 8;
r.BeginUI();
r.RgbaSpriteRenderer.DrawSprite(gdiLogo, gdiPos); r.RgbaSpriteRenderer.DrawSprite(gdiLogo, gdiPos);
r.RgbaSpriteRenderer.DrawSprite(nodLogo, nodPos); r.RgbaSpriteRenderer.DrawSprite(nodLogo, nodPos);
r.RgbaSpriteRenderer.DrawSprite(evaLogo, evaPos); r.RgbaSpriteRenderer.DrawSprite(evaLogo, evaPos);
WidgetUtils.DrawPanel(bounds, border); 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) if (loadingFont != null)
loadingFont.DrawText(loadingText, loadingPos, Color.Gray); loadingFont.DrawText(loadingText, loadingPos, Color.Gray);
if (versionFont != null) if (versionFont != null)
versionFont.DrawTextWithContrast(versionText, versionPos, Color.White, Color.Black, 2); versionFont.DrawTextWithContrast(versionText, versionPos, Color.White, Color.Black, 2);
@@ -123,16 +116,6 @@ namespace OpenRA.Mods.Cnc
r.RgbaSpriteRenderer.DrawSprite(block, r.RgbaSpriteRenderer.DrawSprite(block,
new float2(bounds.Width / 2 + 114 + i * 32 - 16, barY)); 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);
} }
} }
} }

View File

@@ -22,11 +22,11 @@ namespace OpenRA.Mods.Common.LoadScreens
public class BlankLoadScreen : ILoadScreen public class BlankLoadScreen : ILoadScreen
{ {
public LaunchArguments Launch; public LaunchArguments Launch;
ModData modData; protected ModData ModData { get; private set; }
public virtual void Init(ModData modData, Dictionary<string, string> info) public virtual void Init(ModData modData, Dictionary<string, string> info)
{ {
this.modData = modData; ModData = modData;
} }
public virtual void Display() public virtual void Display()
@@ -110,14 +110,14 @@ namespace OpenRA.Mods.Common.LoadScreens
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
public bool BeforeLoad() public virtual bool BeforeLoad()
{ {
// If a ModContent section is defined then we need to make sure that the // 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. // required content is installed or switch to the defined content installer.
if (!modData.Manifest.Contains<ModContent>()) if (!ModData.Manifest.Contains<ModContent>())
return true; return true;
var content = modData.Manifest.Get<ModContent>(); var content = ModData.Manifest.Get<ModContent>();
var contentInstalled = content.Packages var contentInstalled = content.Packages
.Where(p => p.Value.Required) .Where(p => p.Value.Required)
.All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f)))); .All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f))));
@@ -125,7 +125,7 @@ namespace OpenRA.Mods.Common.LoadScreens
if (contentInstalled) if (contentInstalled)
return true; 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; return false;
} }
} }

View File

@@ -9,68 +9,48 @@
*/ */
#endregion #endregion
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.Mods.Common.Widgets; using OpenRA.Mods.Common.Widgets;
using OpenRA.Primitives; using OpenRA.Primitives;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.LoadScreens namespace OpenRA.Mods.Common.LoadScreens
{ {
public sealed class LogoStripeLoadScreen : BlankLoadScreen public sealed class LogoStripeLoadScreen : SheetLoadScreen
{ {
Stopwatch lastUpdate = Stopwatch.StartNew();
Renderer r;
Rectangle stripeRect; Rectangle stripeRect;
float2 logoPos; float2 logoPos;
Sheet sheet;
Sprite stripe, logo; Sprite stripe, logo;
Sheet lastSheet;
Size lastResolution;
string[] messages = { "Loading..." }; string[] messages = { "Loading..." };
public override void Init(ModData modData, Dictionary<string, string> info) public override void Init(ModData modData, Dictionary<string, string> info)
{ {
base.Init(modData, 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")) if (info.ContainsKey("Text"))
messages = info["Text"].Split(','); 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) if (s != lastSheet)
return; {
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 (r.Resolution != lastResolution)
if (lastUpdate.Elapsed.TotalSeconds < 0.5) {
return; lastResolution = r.Resolution;
stripeRect = new Rectangle(0, lastResolution.Height / 2 - 128, lastResolution.Width, 256);
if (r.Fonts == null) logoPos = new float2(lastResolution.Width / 2 - 128, lastResolution.Height / 2 - 128);
return; }
lastUpdate.Restart();
var text = messages.Random(Game.CosmeticRandom);
var textSize = r.Fonts["Bold"].Measure(text);
r.BeginUI();
if (stripe != null) if (stripe != null)
WidgetUtils.FillRectWithSprite(stripeRect, stripe); WidgetUtils.FillRectWithSprite(stripeRect, stripe);
@@ -78,16 +58,12 @@ namespace OpenRA.Mods.Common.LoadScreens
if (logo != null) if (logo != null)
r.RgbaSpriteRenderer.DrawSprite(logo, logoPos); 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); if (r.Fonts != null)
r.EndFrame(new NullInputHandler()); {
} var text = messages.Random(Game.CosmeticRandom);
var textSize = r.Fonts["Bold"].Measure(text);
protected override void Dispose(bool disposing) r.Fonts["Bold"].DrawText(text, new float2(r.Resolution.Width - textSize.X - 20, r.Resolution.Height - textSize.Y - 20), Color.White);
{ }
if (disposing && sheet != null)
sheet.Dispose();
base.Dispose(disposing);
} }
} }
} }

View File

@@ -10,7 +10,6 @@
#endregion #endregion
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using OpenRA.Graphics; using OpenRA.Graphics;
@@ -20,35 +19,32 @@ using OpenRA.Widgets;
namespace OpenRA.Mods.Common.LoadScreens namespace OpenRA.Mods.Common.LoadScreens
{ {
public sealed class ModContentLoadScreen : ILoadScreen public sealed class ModContentLoadScreen : SheetLoadScreen
{ {
Sprite sprite; Sprite sprite;
Rectangle bounds; Rectangle bounds;
public void Init(ModData modData, Dictionary<string, string> info) Sheet lastSheet;
{ Size lastResolution;
var res = Game.Renderer.Resolution;
bounds = new Rectangle(0, 0, res.Width, res.Height);
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); lastSheet = s;
sprite = new Sprite(sheet, new Rectangle(0, 0, 1024, 480), TextureChannel.RGBA); sprite = new Sprite(s, new Rectangle(0, 0, 1024, 480), TextureChannel.RGBA);
} }
}
public void Display() if (r.Resolution != lastResolution)
{ {
var r = Game.Renderer; lastResolution = r.Resolution;
if (r == null) bounds = new Rectangle(0, 0, lastResolution.Width, lastResolution.Height);
return; }
r.BeginUI();
WidgetUtils.FillRectWithSprite(bounds, sprite); 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); var modId = args.GetValue("Content.Mod", null);
Manifest selectedMod; Manifest selectedMod;
@@ -90,13 +86,7 @@ namespace OpenRA.Mods.Common.LoadScreens
.All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f)))); .All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f))));
} }
public void Dispose() public override bool BeforeLoad()
{
if (sprite != null)
sprite.Sheet.Dispose();
}
public bool BeforeLoad()
{ {
return true; return true;
} }

View File

@@ -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<string, string> Info { get; private set; }
Sheet sheet;
public override void Init(ModData modData, Dictionary<string, string> 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);
}
}
}