diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 054197916e..417ae00db1 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -386,32 +386,6 @@ namespace OpenRA Log.AddChannel("nat", "nat.log"); Log.AddChannel("client", "client.log"); - var platforms = new[] { Settings.Game.Platform, "Default", null }; - foreach (var p in platforms) - { - if (p == null) - throw new InvalidOperationException("Failed to initialize platform-integration library. Check graphics.log for details."); - - Settings.Game.Platform = p; - try - { - var platform = CreatePlatform(p); - Renderer = new Renderer(platform, Settings.Graphics); - Sound = new Sound(platform, Settings.Sound); - - break; - } - catch (Exception e) - { - Log.Write("graphics", $"{e}"); - Console.WriteLine("Renderer initialization failed. Check graphics.log for details."); - - Renderer?.Dispose(); - - Sound?.Dispose(); - } - } - Nat.Initialize(); var modSearchArg = args.GetValue("Engine.ModSearchPaths", null); @@ -454,6 +428,32 @@ namespace OpenRA foreach (var mod in ExternalMods) Console.WriteLine($"\t{mod.Key} ({mod.Value.Version})"); + var platforms = new[] { Settings.Game.Platform, "Default", null }; + foreach (var p in platforms) + { + if (p == null) + throw new InvalidOperationException("Failed to initialize platform-integration library. Check graphics.log for details."); + + Settings.Game.Platform = p; + try + { + var platform = CreatePlatform(p); + Renderer = new Renderer(platform, Settings.Graphics, manifest.RendererConstants.VertexBatchSize); + Sound = new Sound(platform, Settings.Sound); + + break; + } + catch (Exception e) + { + Log.Write("graphics", $"{e}"); + Console.WriteLine("Renderer initialization failed. Check graphics.log for details."); + + Renderer?.Dispose(); + + Sound?.Dispose(); + } + } + InitializeMod(manifest, args); } diff --git a/OpenRA.Game/Graphics/CursorManager.cs b/OpenRA.Game/Graphics/CursorManager.cs index 5054a8be15..bffef53ba9 100644 --- a/OpenRA.Game/Graphics/CursorManager.cs +++ b/OpenRA.Game/Graphics/CursorManager.cs @@ -42,10 +42,9 @@ namespace OpenRA.Graphics public CursorManager(ModData modData) { - hardwareCursorsDisabled = Game.Settings.Graphics.DisableHardwareCursors; - graphicSettings = Game.Settings.Graphics; - SheetBuilder = new SheetBuilder(SheetType.BGRA, modData.Manifest.CursorSheetSize); + hardwareCursorsDisabled = graphicSettings.DisableHardwareCursors; + SheetBuilder = new SheetBuilder(SheetType.BGRA, modData.Manifest.RendererConstants.CursorSheetSize); // Overwrite previous definitions if there are duplicates var pals = new Dictionary(); diff --git a/OpenRA.Game/Graphics/SequenceSet.cs b/OpenRA.Game/Graphics/SequenceSet.cs index 9730b74b50..dbf249404b 100644 --- a/OpenRA.Game/Graphics/SequenceSet.cs +++ b/OpenRA.Game/Graphics/SequenceSet.cs @@ -37,8 +37,6 @@ namespace OpenRA.Graphics public interface ISpriteSequenceLoader { - int BgraSheetSize { get; } - int IndexedSheetSize { get; } IReadOnlyDictionary ParseSequences(ModData modData, string tileSet, SpriteCache cache, MiniYamlNode node); } @@ -53,7 +51,9 @@ namespace OpenRA.Graphics { this.modData = modData; TileSet = tileSet; - SpriteCache = new SpriteCache(fileSystem, modData.SpriteLoaders, modData.SpriteSequenceLoader.BgraSheetSize, modData.SpriteSequenceLoader.IndexedSheetSize); + + var rc = modData.Manifest.RendererConstants; + SpriteCache = new SpriteCache(fileSystem, modData.SpriteLoaders, rc.SequenceBgraSheetSize, rc.SequenceIndexedSheetSize); using (new Support.PerfTimer("LoadSequences")) images = Load(fileSystem, additionalSequences); } diff --git a/OpenRA.Game/Graphics/SheetBuilder.cs b/OpenRA.Game/Graphics/SheetBuilder.cs index a420f85859..04ea1afdff 100644 --- a/OpenRA.Game/Graphics/SheetBuilder.cs +++ b/OpenRA.Game/Graphics/SheetBuilder.cs @@ -65,9 +65,6 @@ namespace OpenRA.Graphics } } - public SheetBuilder(SheetType t) - : this(t, Game.Settings.Graphics.SheetSize) { } - public SheetBuilder(SheetType t, int sheetSize, int margin = 1) : this(t, () => AllocateSheet(t, sheetSize), margin) { } diff --git a/OpenRA.Game/Manifest.cs b/OpenRA.Game/Manifest.cs index adee445e74..afb8162bb6 100644 --- a/OpenRA.Game/Manifest.cs +++ b/OpenRA.Game/Manifest.cs @@ -64,6 +64,16 @@ namespace OpenRA public string WindowTitleTranslated => WindowTitle != null ? FluentProvider.GetMessage(WindowTitle) : null; } + public class RendererConstants + { + public readonly int FontSheetSize = 512; + public readonly int CursorSheetSize = 512; + public readonly int MapPreviewSheetSize = 2048; + public readonly int SequenceBgraSheetSize = 2048; + public readonly int SequenceIndexedSheetSize = 2048; + public readonly int VertexBatchSize = 8192; + } + /// Describes what is to be loaded in order to run a mod. public sealed class Manifest : IDisposable { @@ -80,14 +90,13 @@ namespace OpenRA public readonly MiniYaml FileSystem; public readonly MiniYaml LoadScreen; public readonly string DefaultOrderGenerator; + public readonly RendererConstants RendererConstants; public readonly ImmutableArray Assemblies = []; public readonly ImmutableArray SoundFormats = []; public readonly ImmutableArray SpriteFormats = []; public readonly ImmutableArray PackageFormats = []; public readonly ImmutableArray VideoFormats = []; - public readonly int FontSheetSize = 512; - public readonly int CursorSheetSize = 512; // TODO: This should be controlled by a user-selected translation bundle! public readonly string FluentCulture = "en"; @@ -99,7 +108,7 @@ namespace OpenRA "Sequences", "ModelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons", "Voices", "Notifications", "Music", "FluentMessages", "TileSets", "ChromeMetrics", "Missions", "Hotkeys", "ServerTraits", "LoadScreen", "DefaultOrderGenerator", "SupportsMapsFrom", "SoundFormats", "SpriteFormats", "VideoFormats", - "RequiresMods", "PackageFormats", "AllowUnusedFluentMessagesInExternalPackages", "FontSheetSize", "CursorSheetSize" + "RequiresMods", "PackageFormats", "AllowUnusedFluentMessagesInExternalPackages", "RendererConstants" }.ToFrozenSet(); readonly TypeDictionary modules = []; @@ -191,11 +200,10 @@ namespace OpenRA AllowUnusedFluentMessagesInExternalPackages = FieldLoader.GetValue("AllowUnusedFluentMessagesInExternalPackages", entry.Value); - if (yaml.TryGetValue("FontSheetSize", out entry)) - FontSheetSize = FieldLoader.GetValue("FontSheetSize", entry.Value); - - if (yaml.TryGetValue("CursorSheetSize", out entry)) - CursorSheetSize = FieldLoader.GetValue("CursorSheetSize", entry.Value); + if (yaml.TryGetValue("RendererConstants", out entry)) + RendererConstants = FieldLoader.Load(entry); + else + RendererConstants = new RendererConstants(); } public void LoadCustomData(ObjectCreator oc) diff --git a/OpenRA.Game/Map/MapCache.cs b/OpenRA.Game/Map/MapCache.cs index 404f25ff73..c790bd4a81 100644 --- a/OpenRA.Game/Map/MapCache.cs +++ b/OpenRA.Game/Map/MapCache.cs @@ -73,7 +73,7 @@ namespace OpenRA var gridType = Exts.Lazy(() => modData.Manifest.Get().Type); previews = new Cache(uid => new MapPreview(modData, uid, gridType.Value, this)); - sheetBuilder = new SheetBuilder(SheetType.BGRA); + sheetBuilder = new SheetBuilder(SheetType.BGRA, modData.Manifest.RendererConstants.MapPreviewSheetSize); } public void UpdateMaps() diff --git a/OpenRA.Game/Renderer.cs b/OpenRA.Game/Renderer.cs index 1994d7fa56..d7c713aeba 100644 --- a/OpenRA.Game/Renderer.cs +++ b/OpenRA.Game/Renderer.cs @@ -40,7 +40,6 @@ namespace OpenRA internal IPlatformWindow Window { get; } internal IGraphicsContext Context { get; } - internal int SheetSize { get; } internal int TempVertexBufferSize { get; } internal int TempIndexBufferSize { get; } @@ -84,12 +83,12 @@ namespace OpenRA IBatchRenderer currentBatchRenderer; RenderType renderType = RenderType.None; - public Renderer(IPlatform platform, GraphicSettings graphicSettings) + public Renderer(IPlatform platform, GraphicSettings graphicSettings, int vertexBatchSize) { this.platform = platform; var resolution = GetResolution(graphicSettings); - TempVertexBufferSize = graphicSettings.BatchSize - graphicSettings.BatchSize % 4; + TempVertexBufferSize = vertexBatchSize - vertexBatchSize % 4; TempIndexBufferSize = TempVertexBufferSize / 4 * 6; Window = platform.CreateWindow(new Size(resolution.Width, resolution.Height), @@ -98,8 +97,6 @@ namespace OpenRA Context = Window.Context; - SheetSize = graphicSettings.SheetSize; - var combinedBindings = new CombinedShaderBindings(); WorldSpriteRenderer = new SpriteRenderer(this, Context.CreateShader(combinedBindings)); WorldRgbaSpriteRenderer = new RgbaSpriteRenderer(WorldSpriteRenderer); @@ -134,7 +131,7 @@ namespace OpenRA using (new PerfTimer("SpriteFonts")) { fontSheetBuilder?.Dispose(); - fontSheetBuilder = new SheetBuilder(SheetType.BGRA, modData.Manifest.FontSheetSize); + fontSheetBuilder = new SheetBuilder(SheetType.BGRA, modData.Manifest.RendererConstants.FontSheetSize); Fonts = modData.Manifest.Get().FontList.ToDictionary(x => x.Key, x => new SpriteFont( platform, x.Value.Font, modData.DefaultFileSystem.Open(x.Value.Font).ReadAllBytes(), diff --git a/OpenRA.Game/Settings.cs b/OpenRA.Game/Settings.cs index 59ddadf429..fd0f7b20af 100644 --- a/OpenRA.Game/Settings.cs +++ b/OpenRA.Game/Settings.cs @@ -226,9 +226,6 @@ namespace OpenRA "Legacy: OpenGL 2.1 with framebuffer_object extension (requires DisableLegacyGL: False)", "Automatic: Use the first supported profile.")] public GLProfile GLProfile = GLProfile.Automatic; - - public int BatchSize = 8192; - public int SheetSize = 2048; } public class SoundSettings diff --git a/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs b/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs index 7626d6a1ac..351afd3f6d 100644 --- a/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs +++ b/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs @@ -26,13 +26,14 @@ namespace OpenRA.Mods.Cnc.Graphics readonly List vertices = []; readonly Cache<(string, string), Voxel> voxels; readonly IReadOnlyFileSystem fileSystem; + readonly int sheetSize; IVertexBuffer vertexBuffer; int totalVertexCount; int cachedVertexCount; SheetBuilder sheetBuilder; - static SheetBuilder CreateSheetBuilder() + SheetBuilder CreateSheetBuilder() { var allocated = false; Sheet Allocate() @@ -40,15 +41,16 @@ namespace OpenRA.Mods.Cnc.Graphics if (allocated) throw new SheetOverflowException(""); allocated = true; - return SheetBuilder.AllocateSheet(SheetType.Indexed, Game.Settings.Graphics.SheetSize); + return SheetBuilder.AllocateSheet(SheetType.Indexed, sheetSize); } return new SheetBuilder(SheetType.Indexed, Allocate); } - public VoxelLoader(IReadOnlyFileSystem fileSystem) + public VoxelLoader(IReadOnlyFileSystem fileSystem, int sheetSize) { this.fileSystem = fileSystem; + this.sheetSize = sheetSize; voxels = new Cache<(string, string), Voxel>(LoadFile); vertices = []; totalVertexCount = 0; diff --git a/OpenRA.Mods.Cnc/Traits/World/ModelRenderer.cs b/OpenRA.Mods.Cnc/Traits/World/ModelRenderer.cs index 4acbe7b789..15ce49499a 100644 --- a/OpenRA.Mods.Cnc/Traits/World/ModelRenderer.cs +++ b/OpenRA.Mods.Cnc/Traits/World/ModelRenderer.cs @@ -39,6 +39,7 @@ namespace OpenRA.Mods.Cnc.Traits [Desc("Render voxels")] public class ModelRendererInfo : TraitInfo, Requires { + public readonly int RenderBufferSize = 2048; public override object Create(ActorInitializer init) { return new ModelRenderer(this, init.Self); } } @@ -80,7 +81,7 @@ namespace OpenRA.Mods.Cnc.Traits ModelCache = self.Trait(); - sheetSize = Game.Settings.Graphics.SheetSize; + sheetSize = info.RenderBufferSize; var a = 2f / sheetSize; var view = new[] { diff --git a/OpenRA.Mods.Cnc/Traits/World/VoxelCache.cs b/OpenRA.Mods.Cnc/Traits/World/VoxelCache.cs index 6893c94e6b..f0cd51147c 100644 --- a/OpenRA.Mods.Cnc/Traits/World/VoxelCache.cs +++ b/OpenRA.Mods.Cnc/Traits/World/VoxelCache.cs @@ -22,6 +22,7 @@ namespace OpenRA.Mods.Cnc.Traits [Desc("Loads voxel models.")] public sealed class VoxelCacheInfo : TraitInfo, IModelCacheInfo { + public readonly int SheetSize = 2048; public override object Create(ActorInitializer init) { return new VoxelCache(this, init.Self); } } @@ -33,7 +34,7 @@ namespace OpenRA.Mods.Cnc.Traits public VoxelCache(VoxelCacheInfo info, Actor self) { var map = self.World.Map; - loader = new VoxelLoader(map); + loader = new VoxelLoader(map, info.SheetSize); foreach (var kv in map.Rules.ModelSequences) { Game.ModData.LoadScreen.Display(); diff --git a/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs b/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs index 3fd863217f..815b9f5211 100644 --- a/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs +++ b/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs @@ -22,20 +22,9 @@ namespace OpenRA.Mods.Common.Graphics { public class DefaultSpriteSequenceLoader : ISpriteSequenceLoader { - public readonly int BgraSheetSize = 2048; - public readonly int IndexedSheetSize = 2048; - static readonly MiniYaml NoData = new(null); - public DefaultSpriteSequenceLoader(ModData modData) - { - var metadata = modData.Manifest.Get().Metadata; - if (metadata.TryGetValue("BgraSheetSize", out var yaml)) - BgraSheetSize = FieldLoader.GetValue("BgraSheetSize", yaml.Value); - - if (metadata.TryGetValue("IndexedSheetSize", out yaml)) - IndexedSheetSize = FieldLoader.GetValue("IndexedSheetSize", yaml.Value); - } + public DefaultSpriteSequenceLoader(ModData modData) { } public virtual ISpriteSequence CreateSequence( ModData modData, string tileset, SpriteCache cache, string image, string sequence, MiniYaml data, MiniYaml defaults) @@ -43,9 +32,6 @@ namespace OpenRA.Mods.Common.Graphics return new DefaultSpriteSequence(cache, this, image, sequence, data, defaults); } - int ISpriteSequenceLoader.BgraSheetSize => BgraSheetSize; - int ISpriteSequenceLoader.IndexedSheetSize => IndexedSheetSize; - IReadOnlyDictionary ISpriteSequenceLoader.ParseSequences( ModData modData, string tileset, SpriteCache cache, MiniYamlNode imageNode) { diff --git a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs index d9f7c6ce6f..72204722cc 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs @@ -58,7 +58,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic readonly ScrollPanelWidget assetList; readonly ScrollItemWidget template; - readonly Cache sheetBuilders; + readonly Dictionary sheetBuilders; readonly Cache spriteCache; IReadOnlyPackage assetSource = null; @@ -86,7 +86,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic [ObjectCreator.UseCtor] public AssetBrowserLogic(Widget widget, Action onExit, ModData modData, WorldRenderer worldRenderer) { - sheetBuilders = new Cache(t => new SheetBuilder(t)); + var rc = modData.Manifest.RendererConstants; + sheetBuilders = new Dictionary + { + { SheetType.Indexed, new SheetBuilder(SheetType.Indexed, rc.SequenceIndexedSheetSize) }, + { SheetType.BGRA, new SheetBuilder(SheetType.BGRA, rc.SequenceBgraSheetSize) } + }; + spriteCache = new Cache( filename => FrameLoader.GetFrames(modData.DefaultFileSystem, filename, modData.SpriteLoaders, out _) .Select(f => sheetBuilders[SheetBuilder.FrameTypeToSheetType(f.Type)].Add(f)) diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 27a7f73895..f46a8476dc 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -239,7 +239,9 @@ VideoFormats: Vqa TerrainFormat: DefaultTerrain SpriteSequenceFormat: D2kSpriteSequence - IndexedSheetSize: 512 + +RendererConstants: + SequenceIndexedSheetSize: 512 AssetBrowser: SpriteExtensions: .shp, .r8, .r16, .tmp, .png