From f0f02dff5c2a29661f19f2e37ea64ef2c278e0a1 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Fri, 24 Oct 2014 18:21:30 +0100 Subject: [PATCH 1/3] Dispose of graphics resources deterministically. Textures, FrameBuffers and VertexBuffers allocated by the Sdl2 Renderer were only being released via finalizers. This could lead to OpenGL out of memory errors since resources may not be cleaned up in a timely manner. To avoid this, IDisposable has been implemented and transitively applied to classes that use these resources. As a side-effect some static state is no longer static, particularly in Renderer, in order to facilitate this change and just for nicer design in general. Also dispose some bitmaps. --- OpenRA.Game/Game.cs | 23 ++++++--- OpenRA.Game/GameRules/RulesetCache.cs | 9 +++- OpenRA.Game/Graphics/ChromeProvider.cs | 13 +++++ OpenRA.Game/Graphics/CursorProvider.cs | 14 ++++-- OpenRA.Game/Graphics/HardwarePalette.cs | 7 ++- OpenRA.Game/Graphics/IGraphicsDevice.cs | 7 +-- OpenRA.Game/Graphics/LineRenderer.cs | 7 +-- OpenRA.Game/Graphics/Minimap.cs | 4 +- OpenRA.Game/Graphics/QuadRenderer.cs | 7 +-- OpenRA.Game/Graphics/Renderer.cs | 49 ++++++++++++------- OpenRA.Game/Graphics/SequenceProvider.cs | 8 ++- OpenRA.Game/Graphics/Sheet.cs | 8 ++- OpenRA.Game/Graphics/SheetBuilder.cs | 23 +++++++-- OpenRA.Game/Graphics/SpriteRenderer.cs | 13 ++--- OpenRA.Game/Graphics/TerrainRenderer.cs | 8 ++- OpenRA.Game/Graphics/Theater.cs | 7 ++- OpenRA.Game/Graphics/VoxelLoader.cs | 13 ++++- OpenRA.Game/Graphics/VoxelRenderer.cs | 22 +++++++-- OpenRA.Game/Graphics/WorldRenderer.cs | 9 +++- OpenRA.Game/Map/MapCache.cs | 25 ++++++++-- OpenRA.Game/ModData.cs | 35 ++++++++++--- OpenRA.Lint/YamlChecker.cs | 3 ++ OpenRA.Mods.Cnc/CncLoadScreen.cs | 37 ++++++++------ .../LoadScreens/DefaultLoadScreen.cs | 15 ++++-- .../LoadScreens/ModChooserLoadScreen.cs | 8 ++- .../LoadScreens/NullLoadScreen.cs | 8 ++- .../Widgets/Logic/ModBrowserLogic.cs | 22 ++++----- OpenRA.Renderer.Null/NullGraphicsDevice.cs | 9 ++-- OpenRA.Renderer.Sdl2/FrameBuffer.cs | 37 +++++++++----- OpenRA.Renderer.Sdl2/Texture.cs | 26 ++++++++-- OpenRA.Renderer.Sdl2/VertexBuffer.cs | 23 +++++++-- 31 files changed, 371 insertions(+), 128 deletions(-) diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 54925f95c4..506ad986e6 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -140,7 +140,10 @@ namespace OpenRA orderManager.World = new World(map, orderManager, isShellmap); orderManager.World.Timestep = Timestep; } + if (worldRenderer != null) + worldRenderer.Dispose(); worldRenderer = new WorldRenderer(orderManager.World); + using (new PerfTimer("LoadComplete")) orderManager.World.LoadComplete(worldRenderer); @@ -215,7 +218,7 @@ namespace OpenRA Settings.Graphics.Renderer = r; try { - Renderer.Initialize(Settings.Graphics.Mode); + Renderer = new Renderer(Settings.Graphics, Settings.Server); break; } catch (Exception e) @@ -225,8 +228,6 @@ namespace OpenRA } } - Renderer = new Renderer(); - try { Sound.Create(Settings.Sound.Engine); @@ -257,12 +258,18 @@ namespace OpenRA BeforeGameStart = () => { }; Ui.ResetAll(); + if (worldRenderer != null) + worldRenderer.Dispose(); worldRenderer = null; if (server != null) server.Shutdown(); if (orderManager != null) orderManager.Dispose(); + if (modData != null) + modData.Dispose(); + modData = null; + // Fall back to default if the mod doesn't exist if (!ModMetadata.AllMods.ContainsKey(mod)) mod = new GameSettings().Mod; @@ -274,7 +281,7 @@ namespace OpenRA Sound.StopVideo(); Sound.Initialize(); - modData = new ModData(mod); + modData = new ModData(mod, true); Renderer.InitializeFonts(modData.Manifest); modData.InitializeLoaders(); using (new PerfTimer("LoadMaps")) @@ -632,8 +639,12 @@ namespace OpenRA if (orderManager != null) orderManager.Dispose(); } - - Renderer.Device.Dispose(); + + if (worldRenderer != null) + worldRenderer.Dispose(); + modData.Dispose(); + ChromeProvider.Deinitialize(); + Renderer.Dispose(); OnQuit(); diff --git a/OpenRA.Game/GameRules/RulesetCache.cs b/OpenRA.Game/GameRules/RulesetCache.cs index 8dccd262b3..0ceecde102 100755 --- a/OpenRA.Game/GameRules/RulesetCache.cs +++ b/OpenRA.Game/GameRules/RulesetCache.cs @@ -17,7 +17,7 @@ using OpenRA.Support; namespace OpenRA { - public class RulesetCache + public sealed class RulesetCache : IDisposable { readonly ModData modData; @@ -137,5 +137,12 @@ namespace OpenRA return items; } + + public void Dispose() + { + foreach (var cache in sequenceCaches.Values) + cache.Dispose(); + sequenceCaches.Clear(); + } } } diff --git a/OpenRA.Game/Graphics/ChromeProvider.cs b/OpenRA.Game/Graphics/ChromeProvider.cs index 0d6fbf66db..f3c665386c 100644 --- a/OpenRA.Game/Graphics/ChromeProvider.cs +++ b/OpenRA.Game/Graphics/ChromeProvider.cs @@ -27,6 +27,8 @@ namespace OpenRA.Graphics public static void Initialize(IEnumerable chromeFiles) { + Deinitialize(); + collections = new Dictionary(); cachedSheets = new Dictionary(); cachedSprites = new Dictionary>(); @@ -37,6 +39,17 @@ namespace OpenRA.Graphics LoadCollection(c.Key, c.Value); } + public static void Deinitialize() + { + if (cachedSheets != null) + foreach (var sheet in cachedSheets.Values) + sheet.Dispose(); + + collections = null; + cachedSheets = null; + cachedSprites = null; + } + public static void Save(string file) { var root = new List(); diff --git a/OpenRA.Game/Graphics/CursorProvider.cs b/OpenRA.Game/Graphics/CursorProvider.cs index 7dd832e4e1..15ca48db5c 100644 --- a/OpenRA.Game/Graphics/CursorProvider.cs +++ b/OpenRA.Game/Graphics/CursorProvider.cs @@ -16,11 +16,12 @@ using OpenRA.Primitives; namespace OpenRA.Graphics { - public class CursorProvider + public sealed class CursorProvider : IDisposable { HardwarePalette palette; Dictionary cursors; Cache palettes; + readonly SheetBuilder sheetBuilder; public static bool CursorViewportZoomed { get { return Game.Settings.Graphics.CursorDouble && Game.Settings.Graphics.PixelDouble; } } @@ -45,10 +46,11 @@ namespace OpenRA.Graphics foreach (var p in nodesDict["Palettes"].Nodes) palette.AddPalette(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false); - var spriteCache = new SpriteCache(modData.SpriteLoaders, new string[0], new SheetBuilder(SheetType.Indexed)); + sheetBuilder = new SheetBuilder(SheetType.Indexed); + var spriteCache = new SpriteCache(modData.SpriteLoaders, new string[0], sheetBuilder); foreach (var s in nodesDict["Cursors"].Nodes) LoadSequencesForCursor(spriteCache, s.Key, s.Value); - spriteCache.SheetBuilder.Current.ReleaseBuffer(); + sheetBuilder.Current.ReleaseBuffer(); palette.Initialize(); } @@ -95,5 +97,11 @@ namespace OpenRA.Graphics throw new InvalidOperationException("Cursor does not have a sequence `{0}`".F(cursor)); } } + + public void Dispose() + { + palette.Dispose(); + sheetBuilder.Dispose(); + } } } diff --git a/OpenRA.Game/Graphics/HardwarePalette.cs b/OpenRA.Game/Graphics/HardwarePalette.cs index 4695d62d04..df10a17b24 100644 --- a/OpenRA.Game/Graphics/HardwarePalette.cs +++ b/OpenRA.Game/Graphics/HardwarePalette.cs @@ -14,7 +14,7 @@ using OpenRA.Traits; namespace OpenRA.Graphics { - public class HardwarePalette + public sealed class HardwarePalette : IDisposable { public const int MaxPalettes = 256; @@ -111,5 +111,10 @@ namespace OpenRA.Graphics modifiedPalette.SetFromPalette(originalPalette); } } + + public void Dispose() + { + Texture.Dispose(); + } } } diff --git a/OpenRA.Game/Graphics/IGraphicsDevice.cs b/OpenRA.Game/Graphics/IGraphicsDevice.cs index 07b78c5085..c3ec766649 100755 --- a/OpenRA.Game/Graphics/IGraphicsDevice.cs +++ b/OpenRA.Game/Graphics/IGraphicsDevice.cs @@ -63,7 +63,7 @@ namespace OpenRA void ReleaseWindowMouseFocus(); } - public interface IVertexBuffer + public interface IVertexBuffer : IDisposable { void Bind(); void SetData(T[] vertices, int length); @@ -80,7 +80,8 @@ namespace OpenRA } public enum TextureScaleFilter { Nearest, Linear } - public interface ITexture + + public interface ITexture : IDisposable { void SetData(Bitmap bitmap); void SetData(uint[,] colors); @@ -90,7 +91,7 @@ namespace OpenRA TextureScaleFilter ScaleFilter { get; set; } } - public interface IFrameBuffer + public interface IFrameBuffer : IDisposable { void Bind(); void Unbind(); diff --git a/OpenRA.Game/Graphics/LineRenderer.cs b/OpenRA.Game/Graphics/LineRenderer.cs index 4c7f240942..6bc4b93323 100644 --- a/OpenRA.Game/Graphics/LineRenderer.cs +++ b/OpenRA.Game/Graphics/LineRenderer.cs @@ -20,13 +20,14 @@ namespace OpenRA.Graphics Renderer renderer; IShader shader; - Vertex[] vertices = new Vertex[Renderer.TempBufferSize]; + readonly Vertex[] vertices; int nv = 0; public LineRenderer(Renderer renderer, IShader shader) { this.renderer = renderer; this.shader = shader; + vertices = new Vertex[renderer.TempBufferSize]; } @@ -71,9 +72,9 @@ namespace OpenRA.Graphics public void DrawLine(float2 start, float2 end, Color startColor, Color endColor) { - Renderer.CurrentBatchRenderer = this; + renderer.CurrentBatchRenderer = this; - if (nv + 2 > Renderer.TempBufferSize) + if (nv + 2 > renderer.TempBufferSize) Flush(); vertices[nv++] = new Vertex(start + offset, diff --git a/OpenRA.Game/Graphics/Minimap.cs b/OpenRA.Game/Graphics/Minimap.cs index 62fdcdaacd..d87eef5a2e 100644 --- a/OpenRA.Game/Graphics/Minimap.cs +++ b/OpenRA.Game/Graphics/Minimap.cs @@ -203,8 +203,8 @@ namespace OpenRA.Graphics public static Bitmap RenderMapPreview(TileSet tileset, Map map, Ruleset resourceRules, bool actualSize) { - var terrain = TerrainBitmap(tileset, map, actualSize); - return AddStaticResources(tileset, map, resourceRules, terrain); + using (var terrain = TerrainBitmap(tileset, map, actualSize)) + return AddStaticResources(tileset, map, resourceRules, terrain); } } } diff --git a/OpenRA.Game/Graphics/QuadRenderer.cs b/OpenRA.Game/Graphics/QuadRenderer.cs index 21a48d3dc0..254064c714 100644 --- a/OpenRA.Game/Graphics/QuadRenderer.cs +++ b/OpenRA.Game/Graphics/QuadRenderer.cs @@ -17,13 +17,14 @@ namespace OpenRA.Graphics Renderer renderer; IShader shader; - Vertex[] vertices = new Vertex[Renderer.TempBufferSize]; + readonly Vertex[] vertices; int nv = 0; public QuadRenderer(Renderer renderer, IShader shader) { this.renderer = renderer; this.shader = shader; + vertices = new Vertex[renderer.TempBufferSize]; } public void Flush() @@ -45,9 +46,9 @@ namespace OpenRA.Graphics public void FillRect(RectangleF rect, Color color) { - Renderer.CurrentBatchRenderer = this; + renderer.CurrentBatchRenderer = this; - if (nv + 4 > Renderer.TempBufferSize) + if (nv + 4 > renderer.TempBufferSize) Flush(); var r = color.R / 255.0f; diff --git a/OpenRA.Game/Graphics/Renderer.cs b/OpenRA.Game/Graphics/Renderer.cs index 8a99aef2fb..d6818475d2 100644 --- a/OpenRA.Game/Graphics/Renderer.cs +++ b/OpenRA.Game/Graphics/Renderer.cs @@ -18,11 +18,11 @@ using OpenRA.Support; namespace OpenRA.Graphics { - public class Renderer + public sealed class Renderer : IDisposable { - internal static int SheetSize; - internal static int TempBufferSize; - internal static int TempBufferCount; + internal int SheetSize { get; private set; } + internal int TempBufferSize { get; private set; } + internal int TempBufferCount { get; private set; } public SpriteRenderer WorldSpriteRenderer { get; private set; } public SpriteRenderer WorldRgbaSpriteRenderer { get; private set; } @@ -38,11 +38,13 @@ namespace OpenRA.Graphics public Dictionary Fonts; Stack scissorState; - public Renderer() + public Renderer(GraphicSettings graphicSettings, ServerSettings serverSettings) { - TempBufferSize = Game.Settings.Graphics.BatchSize; - TempBufferCount = Game.Settings.Graphics.NumTempBuffers; - SheetSize = Game.Settings.Graphics.SheetSize; + Initialize(graphicSettings, serverSettings); + + TempBufferSize = graphicSettings.BatchSize; + TempBufferCount = graphicSettings.NumTempBuffers; + SheetSize = graphicSettings.SheetSize; scissorState = new Stack(); WorldSpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp")); @@ -142,21 +144,21 @@ namespace OpenRA.Graphics public Size Resolution { get { return device.WindowSize; } } - internal static void Initialize(WindowMode windowMode) + void Initialize(GraphicSettings graphicSettings, ServerSettings serverSettings) { - var resolution = GetResolution(windowMode); + var resolution = GetResolution(graphicSettings); - var renderer = Game.Settings.Server.Dedicated ? "Null" : Game.Settings.Graphics.Renderer; - var rendererPath = Platform.ResolvePath(".", "OpenRA.Renderer." + renderer + ".dll"); + var rendererName = serverSettings.Dedicated ? "Null" : graphicSettings.Renderer; + var rendererPath = Platform.ResolvePath(".", "OpenRA.Renderer." + rendererName + ".dll"); - device = CreateDevice(Assembly.LoadFile(rendererPath), resolution.Width, resolution.Height, windowMode); + device = CreateDevice(Assembly.LoadFile(rendererPath), resolution.Width, resolution.Height, graphicSettings.Mode); } - static Size GetResolution(WindowMode windowmode) + static Size GetResolution(GraphicSettings graphicsSettings) { - var size = (windowmode == WindowMode.Windowed) - ? Game.Settings.Graphics.WindowedSize - : Game.Settings.Graphics.FullscreenSize; + var size = (graphicsSettings.Mode == WindowMode.Windowed) + ? graphicsSettings.WindowedSize + : graphicsSettings.FullscreenSize; return new Size(size.X, size.Y); } @@ -180,8 +182,8 @@ namespace OpenRA.Graphics public interface IBatchRenderer { void Flush(); } - static IBatchRenderer currentBatchRenderer; - public static IBatchRenderer CurrentBatchRenderer + IBatchRenderer currentBatchRenderer; + public IBatchRenderer CurrentBatchRenderer { get { return currentBatchRenderer; } set @@ -240,5 +242,14 @@ namespace OpenRA.Graphics { device.ReleaseWindowMouseFocus(); } + + public void Dispose() + { + Device.Dispose(); + WorldVoxelRenderer.Dispose(); + foreach (var buffer in tempBuffers) + buffer.Dispose(); + tempBuffers.Clear(); + } } } diff --git a/OpenRA.Game/Graphics/SequenceProvider.cs b/OpenRA.Game/Graphics/SequenceProvider.cs index dd250c5fa3..b89559ab52 100644 --- a/OpenRA.Game/Graphics/SequenceProvider.cs +++ b/OpenRA.Game/Graphics/SequenceProvider.cs @@ -69,7 +69,7 @@ namespace OpenRA.Graphics } } - public class SequenceCache + public sealed class SequenceCache : IDisposable { readonly ModData modData; readonly Lazy spriteCache; @@ -141,5 +141,11 @@ namespace OpenRA.Graphics return new ReadOnlyDictionary(unitSequences); } + + public void Dispose() + { + if (spriteCache.IsValueCreated) + spriteCache.Value.SheetBuilder.Dispose(); + } } } diff --git a/OpenRA.Game/Graphics/Sheet.cs b/OpenRA.Game/Graphics/Sheet.cs index 6a69824bc1..a04db289c7 100644 --- a/OpenRA.Game/Graphics/Sheet.cs +++ b/OpenRA.Game/Graphics/Sheet.cs @@ -16,7 +16,7 @@ using OpenRA.FileSystem; namespace OpenRA.Graphics { - public class Sheet + public sealed class Sheet : IDisposable { readonly object textureLock = new object(); bool dirty; @@ -178,5 +178,11 @@ namespace OpenRA.Graphics releaseBufferOnCommit = true; } } + + public void Dispose() + { + if (texture != null) + texture.Dispose(); + } } } diff --git a/OpenRA.Game/Graphics/SheetBuilder.cs b/OpenRA.Game/Graphics/SheetBuilder.cs index eb1049f65f..4a1ff5dce6 100644 --- a/OpenRA.Game/Graphics/SheetBuilder.cs +++ b/OpenRA.Game/Graphics/SheetBuilder.cs @@ -9,7 +9,9 @@ #endregion using System; +using System.Collections.Generic; using System.Drawing; +using System.Linq; namespace OpenRA.Graphics { @@ -27,8 +29,9 @@ namespace OpenRA.Graphics BGRA = 4, } - public class SheetBuilder + public sealed class SheetBuilder : IDisposable { + readonly List sheets = new List(); Sheet current; TextureChannel channel; SheetType type; @@ -36,19 +39,23 @@ namespace OpenRA.Graphics Point p; Func allocateSheet; - public static Sheet AllocateSheet() + public static Sheet AllocateSheet(int sheetSize) { - return new Sheet(new Size(Renderer.SheetSize, Renderer.SheetSize)); + return new Sheet(new Size(sheetSize, sheetSize)); } public SheetBuilder(SheetType t) - : this(t, AllocateSheet) { } + : this(t, Game.Renderer.SheetSize) { } + + public SheetBuilder(SheetType t, int sheetSize) + : this(t, () => AllocateSheet(sheetSize)) { } public SheetBuilder(SheetType t, Func allocateSheet) { channel = TextureChannel.Red; type = t; current = allocateSheet(); + sheets.Add(current); this.allocateSheet = allocateSheet; } @@ -111,6 +118,7 @@ namespace OpenRA.Graphics { current.ReleaseBuffer(); current = allocateSheet(); + sheets.Add(current); channel = TextureChannel.Red; } else @@ -127,5 +135,12 @@ namespace OpenRA.Graphics } public Sheet Current { get { return current; } } + + public void Dispose() + { + foreach (var sheet in sheets) + sheet.Dispose(); + sheets.Clear(); + } } } diff --git a/OpenRA.Game/Graphics/SpriteRenderer.cs b/OpenRA.Game/Graphics/SpriteRenderer.cs index 0ac6b2e82e..d953128f20 100644 --- a/OpenRA.Game/Graphics/SpriteRenderer.cs +++ b/OpenRA.Game/Graphics/SpriteRenderer.cs @@ -17,8 +17,8 @@ namespace OpenRA.Graphics Renderer renderer; IShader shader; - Vertex[] vertices = new Vertex[Renderer.TempBufferSize]; - Sheet currentSheet = null; + readonly Vertex[] vertices; + Sheet currentSheet; BlendMode currentBlend = BlendMode.Alpha; int nv = 0; @@ -26,6 +26,7 @@ namespace OpenRA.Graphics { this.renderer = renderer; this.shader = shader; + vertices = new Vertex[renderer.TempBufferSize]; } public void Flush() @@ -60,7 +61,7 @@ namespace OpenRA.Graphics void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size) { - Renderer.CurrentBatchRenderer = this; + renderer.CurrentBatchRenderer = this; if (s.sheet != currentSheet) Flush(); @@ -68,7 +69,7 @@ namespace OpenRA.Graphics if (s.blendMode != currentBlend) Flush(); - if (nv + 4 > Renderer.TempBufferSize) + if (nv + 4 > renderer.TempBufferSize) Flush(); currentBlend = s.blendMode; @@ -90,7 +91,7 @@ namespace OpenRA.Graphics public void DrawSprite(Sprite s, float2 a, float2 b, float2 c, float2 d) { - Renderer.CurrentBatchRenderer = this; + renderer.CurrentBatchRenderer = this; if (s.sheet != currentSheet) Flush(); @@ -98,7 +99,7 @@ namespace OpenRA.Graphics if (s.blendMode != currentBlend) Flush(); - if (nv + 4 > Renderer.TempBufferSize) + if (nv + 4 > renderer.TempBufferSize) Flush(); currentSheet = s.sheet; diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index 4aeb3519db..bf01017cc5 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -8,11 +8,12 @@ */ #endregion +using System; using OpenRA.Traits; namespace OpenRA.Graphics { - class TerrainRenderer + sealed class TerrainRenderer : IDisposable { IVertexBuffer vertexBuffer; @@ -58,5 +59,10 @@ namespace OpenRA.Graphics foreach (var r in world.WorldActor.TraitsImplementing()) r.Render(wr); } + + public void Dispose() + { + vertexBuffer.Dispose(); + } } } diff --git a/OpenRA.Game/Graphics/Theater.cs b/OpenRA.Game/Graphics/Theater.cs index f3e20a95cb..684f2fb976 100644 --- a/OpenRA.Game/Graphics/Theater.cs +++ b/OpenRA.Game/Graphics/Theater.cs @@ -16,7 +16,7 @@ using OpenRA.FileSystem; namespace OpenRA.Graphics { - public class Theater + public sealed class Theater : IDisposable { SheetBuilder sheetBuilder; Dictionary templates; @@ -101,5 +101,10 @@ namespace OpenRA.Graphics } public Sheet Sheet { get { return sheetBuilder.Current; } } + + public void Dispose() + { + sheetBuilder.Dispose(); + } } } diff --git a/OpenRA.Game/Graphics/VoxelLoader.cs b/OpenRA.Game/Graphics/VoxelLoader.cs index 2fc2d2fdf8..5f80528131 100644 --- a/OpenRA.Game/Graphics/VoxelLoader.cs +++ b/OpenRA.Game/Graphics/VoxelLoader.cs @@ -32,7 +32,7 @@ namespace OpenRA.Graphics } } - public class VoxelLoader + public sealed class VoxelLoader : IDisposable { SheetBuilder sheetBuilder; @@ -50,7 +50,7 @@ namespace OpenRA.Graphics if (allocated) throw new SheetOverflowException(""); allocated = true; - return SheetBuilder.AllocateSheet(); + return SheetBuilder.AllocateSheet(Game.Renderer.SheetSize); }; return new SheetBuilder(SheetType.DualIndexed, allocate); @@ -195,6 +195,8 @@ namespace OpenRA.Graphics public void RefreshBuffer() { + if (vertexBuffer != null) + vertexBuffer.Dispose(); vertexBuffer = Game.Renderer.Device.CreateVertexBuffer(totalVertexCount); vertexBuffer.SetData(vertices.SelectMany(v => v).ToArray(), totalVertexCount); cachedVertexCount = totalVertexCount; @@ -230,5 +232,12 @@ namespace OpenRA.Graphics { sheetBuilder.Current.ReleaseBuffer(); } + + public void Dispose() + { + if (vertexBuffer != null) + vertexBuffer.Dispose(); + sheetBuilder.Dispose(); + } } } diff --git a/OpenRA.Game/Graphics/VoxelRenderer.cs b/OpenRA.Game/Graphics/VoxelRenderer.cs index 3afa4c611b..8180cdb7ce 100644 --- a/OpenRA.Game/Graphics/VoxelRenderer.cs +++ b/OpenRA.Game/Graphics/VoxelRenderer.cs @@ -32,7 +32,7 @@ namespace OpenRA.Graphics } } - public class VoxelRenderer + public sealed class VoxelRenderer : IDisposable { Renderer renderer; IShader shader; @@ -68,7 +68,7 @@ namespace OpenRA.Graphics public void SetViewportParams(Size screen, float zoom, int2 scroll) { - var a = 2f / Renderer.SheetSize; + var a = 2f / renderer.SheetSize; var view = new float[] { a, 0, 0, 0, @@ -169,8 +169,8 @@ namespace OpenRA.Graphics var spriteCenter = new float2(sb.Left + sb.Width / 2, sb.Top + sb.Height / 2); var shadowCenter = new float2(ssb.Left + ssb.Width / 2, ssb.Top + ssb.Height / 2); - var translateMtx = Util.TranslationMatrix(spriteCenter.X - spriteOffset.X, Renderer.SheetSize - (spriteCenter.Y - spriteOffset.Y), 0); - var shadowTranslateMtx = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, Renderer.SheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0); + var translateMtx = Util.TranslationMatrix(spriteCenter.X - spriteOffset.X, renderer.SheetSize - (spriteCenter.Y - spriteOffset.Y), 0); + var shadowTranslateMtx = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, renderer.SheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0); var correctionTransform = Util.MatrixMultiply(translateMtx, flipMtx); var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, shadowScaleFlipMtx); @@ -330,12 +330,24 @@ namespace OpenRA.Graphics return kv.Key; } - var size = new Size(Renderer.SheetSize, Renderer.SheetSize); + var size = new Size(renderer.SheetSize, renderer.SheetSize); var framebuffer = renderer.Device.CreateFrameBuffer(size); var sheet = new Sheet(framebuffer.Texture); mappedBuffers.Add(sheet, framebuffer); return sheet; } + + public void Dispose() + { + foreach (var kvp in mappedBuffers.Concat(unmappedBuffers)) + { + kvp.Key.Dispose(); + kvp.Value.Dispose(); + } + + mappedBuffers.Clear(); + unmappedBuffers.Clear(); + } } } diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 049d48a859..4a9d410ef6 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -29,7 +29,7 @@ namespace OpenRA.Graphics } } - public class WorldRenderer + public sealed class WorldRenderer : IDisposable { public readonly World world; public readonly Theater Theater; @@ -251,5 +251,12 @@ namespace OpenRA.Graphics var ts = Game.modData.Manifest.TileSize; return new WPos(1024 * screenPx.X / ts.Width, 1024 * screenPx.Y / ts.Height, 0); } + + public void Dispose() + { + palette.Dispose(); + Theater.Dispose(); + terrainRenderer.Dispose(); + } } } diff --git a/OpenRA.Game/Map/MapCache.cs b/OpenRA.Game/Map/MapCache.cs index cf528f1a99..2621808439 100644 --- a/OpenRA.Game/Map/MapCache.cs +++ b/OpenRA.Game/Map/MapCache.cs @@ -21,7 +21,7 @@ using OpenRA.Primitives; namespace OpenRA { - public class MapCache : IEnumerable + public sealed class MapCache : IEnumerable, IDisposable { public static readonly MapPreview UnknownMap = new MapPreview(null, null); readonly Cache previews; @@ -163,7 +163,13 @@ namespace OpenRA foreach (var p in todo) { // The rendering is thread safe because it only reads from the passed instances and writes to a new bitmap - var bitmap = p.CustomPreview ?? Minimap.RenderMapPreview(modData.DefaultRules.TileSets[p.Map.Tileset], p.Map, modData.DefaultRules, true); + var createdPreview = false; + var bitmap = p.CustomPreview; + if (bitmap == null) + { + createdPreview = true; + bitmap = Minimap.RenderMapPreview(modData.DefaultRules.TileSets[p.Map.Tileset], p.Map, modData.DefaultRules, true); + } // Note: this is not generally thread-safe, but it works here because: // (a) This worker is the only thread writing to this sheet // (b) The main thread is the only thread reading this sheet @@ -172,7 +178,15 @@ namespace OpenRA // the next render cycle. // (d) Any partially written bytes from the next minimap is in an // unallocated area, and will be committed in the next cycle. - p.SetMinimap(sheetBuilder.Add(bitmap)); + try + { + p.SetMinimap(sheetBuilder.Add(bitmap)); + } + finally + { + if (createdPreview) + bitmap.Dispose(); + } // Yuck... But this helps the UI Jank when opening the map selector significantly. Thread.Sleep(Environment.ProcessorCount == 1 ? 25 : 5); @@ -226,5 +240,10 @@ namespace OpenRA { return GetEnumerator(); } + + public void Dispose() + { + sheetBuilder.Dispose(); + } } } diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 288d9ac836..3dcd09796f 100644 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -18,7 +18,7 @@ using OpenRA.Widgets; namespace OpenRA { - public class ModData + public sealed class ModData : IDisposable { public readonly Manifest Manifest; public readonly ObjectCreator ObjectCreator; @@ -33,14 +33,17 @@ namespace OpenRA Lazy defaultRules; public Ruleset DefaultRules { get { return defaultRules.Value; } } - public ModData(string mod) + public ModData(string mod, bool useLoadScreen = false) { Languages = new string[0]; Manifest = new Manifest(mod); ObjectCreator = new ObjectCreator(Manifest); - LoadScreen = ObjectCreator.CreateObject(Manifest.LoadScreen.Value); - LoadScreen.Init(Manifest, Manifest.LoadScreen.ToDictionary(my => my.Value)); - LoadScreen.Display(); + if (useLoadScreen) + { + LoadScreen = ObjectCreator.CreateObject(Manifest.LoadScreen.Value); + LoadScreen.Init(Manifest, Manifest.LoadScreen.ToDictionary(my => my.Value)); + LoadScreen.Display(); + } WidgetLoader = new WidgetLoader(this); RulesetCache = new RulesetCache(this); RulesetCache.LoadingProgress += HandleLoadingProgress; @@ -82,8 +85,13 @@ namespace OpenRA // horribly when you use ModData in unexpected ways. ChromeMetrics.Initialize(Manifest.ChromeMetrics); ChromeProvider.Initialize(Manifest.Chrome); + + if (VoxelLoader != null) + VoxelLoader.Dispose(); VoxelLoader = new VoxelLoader(); + if (CursorProvider != null) + CursorProvider.Dispose(); CursorProvider = new CursorProvider(this); } @@ -130,7 +138,8 @@ namespace OpenRA public Map PrepareMap(string uid) { - LoadScreen.Display(); + if (LoadScreen != null) + LoadScreen.Display(); if (MapCache[uid].Status != MapStatus.Available) throw new InvalidDataException("Invalid map uid: {0}".F(uid)); @@ -157,9 +166,21 @@ namespace OpenRA return map; } + + public void Dispose() + { + if (LoadScreen != null) + LoadScreen.Dispose(); + RulesetCache.Dispose(); + MapCache.Dispose(); + if (VoxelLoader != null) + VoxelLoader.Dispose(); + if (CursorProvider != null) + CursorProvider.Dispose(); + } } - public interface ILoadScreen + public interface ILoadScreen : IDisposable { void Init(Manifest m, Dictionary info); void Display(); diff --git a/OpenRA.Lint/YamlChecker.cs b/OpenRA.Lint/YamlChecker.cs index a076c082ed..11e70ae4e8 100644 --- a/OpenRA.Lint/YamlChecker.cs +++ b/OpenRA.Lint/YamlChecker.cs @@ -55,6 +55,9 @@ namespace OpenRA.Lint FieldLoader.UnknownFieldAction = (s, f) => EmitError("FieldLoader: Missing field `{0}` on `{1}`".F(s, f.Name)); AppDomain.CurrentDomain.AssemblyResolve += GlobalFileSystem.ResolveAssembly; + Game.Renderer = new Graphics.Renderer( + new GraphicSettings() { Renderer = "Null", NumTempBuffers = 0, SheetSize = 0 }, + new ServerSettings()); Game.modData = new ModData(mod); IEnumerable maps; diff --git a/OpenRA.Mods.Cnc/CncLoadScreen.cs b/OpenRA.Mods.Cnc/CncLoadScreen.cs index b1047a0bde..29d1d9cf06 100644 --- a/OpenRA.Mods.Cnc/CncLoadScreen.cs +++ b/OpenRA.Mods.Cnc/CncLoadScreen.cs @@ -18,10 +18,11 @@ using OpenRA.Widgets; namespace OpenRA.Mods.Cnc { - public class CncLoadScreen : ILoadScreen + public sealed class CncLoadScreen : ILoadScreen { Dictionary loadInfo; Stopwatch loadTimer = Stopwatch.StartNew(); + Sheet sheet; Sprite[] ss; int loadTick; float2 nodPos, gdiPos, evaPos; @@ -39,31 +40,31 @@ namespace OpenRA.Mods.Cnc r = Game.Renderer; if (r == null) return; - var s = new Sheet(Platform.ResolvePath(loadInfo["Image"])); + sheet = new Sheet(Platform.ResolvePath(loadInfo["Image"])); var res = r.Resolution; bounds = new Rectangle(0, 0, res.Width, res.Height); ss = new[] { - new Sprite(s, new Rectangle(161, 128, 62, 33), TextureChannel.Alpha), - new Sprite(s, new Rectangle(161, 223, 62, 33), TextureChannel.Alpha), - new Sprite(s, new Rectangle(128, 161, 33, 62), TextureChannel.Alpha), - new Sprite(s, new Rectangle(223, 161, 33, 62), TextureChannel.Alpha), - new Sprite(s, new Rectangle(128, 128, 33, 33), TextureChannel.Alpha), - new Sprite(s, new Rectangle(223, 128, 33, 33), TextureChannel.Alpha), - new Sprite(s, new Rectangle(128, 223, 33, 33), TextureChannel.Alpha), - new Sprite(s, new Rectangle(223, 223, 33, 33), TextureChannel.Alpha) + new Sprite(sheet, new Rectangle(161, 128, 62, 33), TextureChannel.Alpha), + new Sprite(sheet, new Rectangle(161, 223, 62, 33), TextureChannel.Alpha), + new Sprite(sheet, new Rectangle(128, 161, 33, 62), TextureChannel.Alpha), + new Sprite(sheet, new Rectangle(223, 161, 33, 62), TextureChannel.Alpha), + new Sprite(sheet, new Rectangle(128, 128, 33, 33), TextureChannel.Alpha), + new Sprite(sheet, new Rectangle(223, 128, 33, 33), TextureChannel.Alpha), + new Sprite(sheet, new Rectangle(128, 223, 33, 33), TextureChannel.Alpha), + new Sprite(sheet, new Rectangle(223, 223, 33, 33), TextureChannel.Alpha) }; - nodLogo = new Sprite(s, new Rectangle(0, 256, 256, 256), TextureChannel.Alpha); - gdiLogo = new Sprite(s, new Rectangle(256, 256, 256, 256), TextureChannel.Alpha); - evaLogo = new Sprite(s, new Rectangle(256, 64, 128, 64), TextureChannel.Alpha); + nodLogo = new Sprite(sheet, new Rectangle(0, 256, 256, 256), TextureChannel.Alpha); + gdiLogo = new Sprite(sheet, new Rectangle(256, 256, 256, 256), TextureChannel.Alpha); + evaLogo = new Sprite(sheet, new Rectangle(256, 64, 128, 64), TextureChannel.Alpha); 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(s, new Rectangle(320, 0, 16, 35), TextureChannel.Alpha); - dimBlock = new Sprite(s, new Rectangle(336, 0, 16, 35), TextureChannel.Alpha); + brightBlock = new Sprite(sheet, new Rectangle(320, 0, 16, 35), TextureChannel.Alpha); + dimBlock = new Sprite(sheet, new Rectangle(336, 0, 16, 35), TextureChannel.Alpha); versionText = m.Mod.Version; } @@ -123,5 +124,11 @@ namespace OpenRA.Mods.Cnc { Game.TestAndContinue(); } + + public void Dispose() + { + if (sheet != null) + sheet.Dispose(); + } } } \ No newline at end of file diff --git a/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs index b10262a0e0..b8ad1c579c 100644 --- a/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs @@ -18,13 +18,14 @@ using OpenRA.Widgets; namespace OpenRA.Mods.Common.LoadScreens { - public class DefaultLoadScreen : ILoadScreen + public sealed class DefaultLoadScreen : ILoadScreen { Stopwatch lastUpdate = Stopwatch.StartNew(); Renderer r; Rectangle stripeRect; float2 logoPos; + Sheet sheet; Sprite stripe, logo; string[] messages; @@ -37,9 +38,9 @@ namespace OpenRA.Mods.Common.LoadScreens return; messages = info["Text"].Split(','); - var s = new Sheet(Platform.ResolvePath(info["Image"])); - logo = new Sprite(s, new Rectangle(0, 0, 256, 256), TextureChannel.Alpha); - stripe = new Sprite(s, new Rectangle(256, 0, 256, 256), TextureChannel.Alpha); + sheet = new Sheet(Platform.ResolvePath(info["Image"])); + logo = new Sprite(sheet, new Rectangle(0, 0, 256, 256), TextureChannel.Alpha); + stripe = new Sprite(sheet, new Rectangle(256, 0, 256, 256), TextureChannel.Alpha); 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); } @@ -71,5 +72,11 @@ namespace OpenRA.Mods.Common.LoadScreens { Game.TestAndContinue(); } + + public void Dispose() + { + if (sheet != null) + sheet.Dispose(); + } } } diff --git a/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs index f5ec655a05..ccc18e204e 100644 --- a/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs @@ -15,7 +15,7 @@ using OpenRA.Widgets; namespace OpenRA.Mods.Common.LoadScreens { - public class ModChooserLoadScreen : ILoadScreen + public sealed class ModChooserLoadScreen : ILoadScreen { Sprite sprite; Rectangle bounds; @@ -43,5 +43,11 @@ namespace OpenRA.Mods.Common.LoadScreens { Ui.LoadWidget("MODCHOOSER", Ui.Root, new WidgetArgs()); } + + public void Dispose() + { + if (sprite != null) + sprite.sheet.Dispose(); + } } } \ No newline at end of file diff --git a/OpenRA.Mods.Common/LoadScreens/NullLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/NullLoadScreen.cs index 122a2b1dfe..ce0c7b149c 100644 --- a/OpenRA.Mods.Common/LoadScreens/NullLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/NullLoadScreen.cs @@ -13,7 +13,7 @@ using OpenRA.Widgets; namespace OpenRA.Mods.Common.LoadScreens { - public class NullLoadScreen : ILoadScreen + public sealed class NullLoadScreen : ILoadScreen { public void Init(Manifest m, Dictionary info) { } @@ -31,5 +31,9 @@ namespace OpenRA.Mods.Common.LoadScreens { Ui.ResetAll(); } + + public void Dispose() + { + } } -} \ No newline at end of file +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs index 1ea99373f4..d624827991 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs @@ -23,6 +23,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic Widget modList; ButtonWidget modTemplate; ModMetadata[] allMods; + readonly SheetBuilder sheetBuilder; ModMetadata selectedMod; string selectedAuthor; string selectedDescription; @@ -63,7 +64,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic return ret; }; - var sheetBuilder = new SheetBuilder(SheetType.BGRA); + sheetBuilder = new SheetBuilder(SheetType.BGRA); previews = new Dictionary(); logos = new Dictionary(); allMods = ModMetadata.AllMods.Values.Where(m => m.Id != "modchooser") @@ -75,21 +76,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic { try { - var preview = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "preview.png")); - if (preview.Width != 296 || preview.Height != 196) - continue; - - previews.Add(mod.Id, sheetBuilder.Add(preview)); + using (var preview = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "preview.png"))) + if (preview.Width == 296 && preview.Height == 196) + previews.Add(mod.Id, sheetBuilder.Add(preview)); } catch (Exception) { } try { - var logo = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "logo.png")); - if (logo.Width != 96 || logo.Height != 96) - continue; - - logos.Add(mod.Id, sheetBuilder.Add(logo)); + using (var logo = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "logo.png"))) + if (logo.Width == 96 && logo.Height == 96) + logos.Add(mod.Id, sheetBuilder.Add(logo)); } catch (Exception) { } } @@ -155,11 +152,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic modOffset = selectedIndex - 4; } - static void LoadMod(ModMetadata mod) + void LoadMod(ModMetadata mod) { Game.RunAfterTick(() => { Ui.CloseWindow(); + sheetBuilder.Dispose(); Game.InitializeMod(mod.Id, null); }); } diff --git a/OpenRA.Renderer.Null/NullGraphicsDevice.cs b/OpenRA.Renderer.Null/NullGraphicsDevice.cs index 5e2da9c886..299fa0ddea 100644 --- a/OpenRA.Renderer.Null/NullGraphicsDevice.cs +++ b/OpenRA.Renderer.Null/NullGraphicsDevice.cs @@ -78,7 +78,7 @@ namespace OpenRA.Renderer.Null public void Render(Action a) { } } - public class NullTexture : ITexture + public sealed class NullTexture : ITexture { public TextureScaleFilter ScaleFilter { get { return TextureScaleFilter.Nearest; } set { } } public void SetData(Bitmap bitmap) { } @@ -86,18 +86,21 @@ namespace OpenRA.Renderer.Null public void SetData(byte[] colors, int width, int height) { } public byte[] GetData() { return new byte[0]; } public Size Size { get { return new Size(0, 0); } } + public void Dispose() { } } - public class NullFrameBuffer : IFrameBuffer + public sealed class NullFrameBuffer : IFrameBuffer { public void Bind() { } public void Unbind() { } public ITexture Texture { get { return new NullTexture(); } } + public void Dispose() { } } - class NullVertexBuffer : IVertexBuffer + sealed class NullVertexBuffer : IVertexBuffer { public void Bind() { } public void SetData(T[] vertices, int length) { } + public void Dispose() { } } } diff --git a/OpenRA.Renderer.Sdl2/FrameBuffer.cs b/OpenRA.Renderer.Sdl2/FrameBuffer.cs index a640229fdf..9ef1f4aeb2 100644 --- a/OpenRA.Renderer.Sdl2/FrameBuffer.cs +++ b/OpenRA.Renderer.Sdl2/FrameBuffer.cs @@ -16,11 +16,12 @@ using OpenTK.Graphics.OpenGL; namespace OpenRA.Renderer.Sdl2 { - public class FrameBuffer : IFrameBuffer + public sealed class FrameBuffer : IFrameBuffer { Texture texture; Size size; int framebuffer, depth; + bool disposed; public FrameBuffer(Size size) { @@ -81,16 +82,6 @@ namespace OpenRA.Renderer.Sdl2 return v; } - void FinalizeInner() - { - GL.Ext.DeleteFramebuffers(1, ref framebuffer); - ErrorHandler.CheckGlError(); - GL.Ext.DeleteRenderbuffers(1, ref depth); - ErrorHandler.CheckGlError(); - } - - ~FrameBuffer() { Game.RunAfterTick(FinalizeInner); } - int[] cv = new int[4]; public void Bind() { @@ -120,5 +111,29 @@ namespace OpenRA.Renderer.Sdl2 } public ITexture Texture { get { return texture; } } + + ~FrameBuffer() + { + Game.RunAfterTick(() => Dispose(false)); + } + + public void Dispose() + { + Game.RunAfterTick(() => Dispose(true)); + GC.SuppressFinalize(this); + } + + void Dispose(bool disposing) + { + if (disposed) + return; + disposed = true; + if (disposing) + texture.Dispose(); + GL.Ext.DeleteFramebuffers(1, ref framebuffer); + ErrorHandler.CheckGlError(); + GL.Ext.DeleteRenderbuffers(1, ref depth); + ErrorHandler.CheckGlError(); + } } } diff --git a/OpenRA.Renderer.Sdl2/Texture.cs b/OpenRA.Renderer.Sdl2/Texture.cs index de82a06e8e..60efb8c433 100644 --- a/OpenRA.Renderer.Sdl2/Texture.cs +++ b/OpenRA.Renderer.Sdl2/Texture.cs @@ -16,7 +16,7 @@ using OpenTK.Graphics.OpenGL; namespace OpenRA.Renderer.Sdl2 { - public class Texture : ITexture + public sealed class Texture : ITexture { int texture; TextureScaleFilter scaleFilter; @@ -26,6 +26,8 @@ namespace OpenRA.Renderer.Sdl2 public Size Size { get { return size; } } + bool disposed; + public TextureScaleFilter ScaleFilter { get @@ -55,9 +57,6 @@ namespace OpenRA.Renderer.Sdl2 SetData(bitmap); } - void FinalizeInner() { GL.DeleteTextures(1, ref texture); } - ~Texture() { Game.RunAfterTick(FinalizeInner); } - void PrepareTexture() { ErrorHandler.CheckGlError(); @@ -180,5 +179,24 @@ namespace OpenRA.Renderer.Sdl2 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero); ErrorHandler.CheckGlError(); } + + ~Texture() + { + Game.RunAfterTick(() => Dispose(false)); + } + + public void Dispose() + { + Game.RunAfterTick(() => Dispose(true)); + GC.SuppressFinalize(this); + } + + void Dispose(bool disposing) + { + if (disposed) + return; + disposed = true; + GL.DeleteTextures(1, ref texture); + } } } diff --git a/OpenRA.Renderer.Sdl2/VertexBuffer.cs b/OpenRA.Renderer.Sdl2/VertexBuffer.cs index a5655e4cd1..c35baa0f7d 100644 --- a/OpenRA.Renderer.Sdl2/VertexBuffer.cs +++ b/OpenRA.Renderer.Sdl2/VertexBuffer.cs @@ -14,11 +14,12 @@ using OpenTK.Graphics.OpenGL; namespace OpenRA.Renderer.Sdl2 { - public class VertexBuffer : IVertexBuffer + public sealed class VertexBuffer : IVertexBuffer where T : struct { static readonly int VertexSize = Marshal.SizeOf(typeof(T)); int buffer; + bool disposed; public VertexBuffer(int size) { @@ -52,7 +53,23 @@ namespace OpenRA.Renderer.Sdl2 ErrorHandler.CheckGlError(); } - void FinalizeInner() { GL.DeleteBuffers(1, ref buffer); } - ~VertexBuffer() { Game.RunAfterTick(FinalizeInner); } + ~VertexBuffer() + { + Game.RunAfterTick(() => Dispose(false)); + } + + public void Dispose() + { + Game.RunAfterTick(() => Dispose(true)); + GC.SuppressFinalize(this); + } + + void Dispose(bool disposing) + { + if (disposed) + return; + disposed = true; + GL.DeleteBuffers(1, ref buffer); + } } } From 9cbac2d5e1888868bf4cefe14936198461e96a41 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Mon, 20 Oct 2014 22:15:32 +0100 Subject: [PATCH 2/3] Clean up style of files affected by the last commit. --- OpenRA.Game/Graphics/ChromeProvider.cs | 17 ++- OpenRA.Game/Graphics/CursorProvider.cs | 8 +- OpenRA.Game/Graphics/LineRenderer.cs | 24 +-- OpenRA.Game/Graphics/QuadRenderer.cs | 6 +- OpenRA.Game/Graphics/Renderer.cs | 138 +++++++++--------- OpenRA.Game/Graphics/SheetBuilder.cs | 5 +- OpenRA.Game/Graphics/SpriteFont.cs | 5 +- OpenRA.Game/Graphics/SpriteRenderer.cs | 6 +- OpenRA.Game/Graphics/TerrainRenderer.cs | 9 +- OpenRA.Game/Graphics/Theater.cs | 6 +- OpenRA.Game/Graphics/VoxelLoader.cs | 85 +++++------ OpenRA.Game/Graphics/VoxelRenderer.cs | 87 ++++++----- OpenRA.Game/Graphics/WorldRenderer.cs | 6 +- OpenRA.Game/ModData.cs | 4 +- OpenRA.Mods.Cnc/CncLoadScreen.cs | 4 +- .../LoadScreens/DefaultLoadScreen.cs | 2 - .../Widgets/Logic/ModBrowserLogic.cs | 12 +- OpenRA.Renderer.Sdl2/Texture.cs | 1 + 18 files changed, 205 insertions(+), 220 deletions(-) diff --git a/OpenRA.Game/Graphics/ChromeProvider.cs b/OpenRA.Game/Graphics/ChromeProvider.cs index f3c665386c..2031d55099 100644 --- a/OpenRA.Game/Graphics/ChromeProvider.cs +++ b/OpenRA.Game/Graphics/ChromeProvider.cs @@ -17,8 +17,8 @@ namespace OpenRA.Graphics { struct Collection { - public string src; - public Dictionary regions; + public string Src; + public Dictionary Regions; } static Dictionary collections; @@ -62,10 +62,10 @@ namespace OpenRA.Graphics static MiniYaml SaveCollection(Collection collection) { var root = new List(); - foreach (var kv in collection.regions) - root.Add(new MiniYamlNode(kv.Key, kv.Value.Save(collection.src))); + foreach (var kv in collection.Regions) + root.Add(new MiniYamlNode(kv.Key, kv.Value.Save(collection.Src))); - return new MiniYaml(collection.src, root); + return new MiniYaml(collection.Src, root); } static void LoadCollection(string name, MiniYaml yaml) @@ -73,8 +73,8 @@ namespace OpenRA.Graphics Game.modData.LoadScreen.Display(); var collection = new Collection() { - src = yaml.Value, - regions = yaml.Nodes.ToDictionary(n => n.Key, n => new MappedImage(yaml.Value, n.Value)) + Src = yaml.Value, + Regions = yaml.Nodes.ToDictionary(n => n.Key, n => new MappedImage(yaml.Value, n.Value)) }; collections.Add(name, collection); @@ -96,7 +96,7 @@ namespace OpenRA.Graphics } MappedImage mi; - if (!collection.regions.TryGetValue(imageName, out mi)) + if (!collection.Regions.TryGetValue(imageName, out mi)) return null; // Cached sheet @@ -115,6 +115,7 @@ namespace OpenRA.Graphics cachedCollection = new Dictionary(); cachedSprites.Add(collectionName, cachedCollection); } + var image = mi.GetImage(sheet); cachedCollection.Add(imageName, image); diff --git a/OpenRA.Game/Graphics/CursorProvider.cs b/OpenRA.Game/Graphics/CursorProvider.cs index 15ca48db5c..1f1d8bdb79 100644 --- a/OpenRA.Game/Graphics/CursorProvider.cs +++ b/OpenRA.Game/Graphics/CursorProvider.cs @@ -18,9 +18,9 @@ namespace OpenRA.Graphics { public sealed class CursorProvider : IDisposable { - HardwarePalette palette; - Dictionary cursors; - Cache palettes; + readonly HardwarePalette palette = new HardwarePalette(); + readonly Dictionary cursors = new Dictionary(); + readonly Cache palettes; readonly SheetBuilder sheetBuilder; public static bool CursorViewportZoomed { get { return Game.Settings.Graphics.CursorDouble && Game.Settings.Graphics.PixelDouble; } } @@ -29,7 +29,6 @@ namespace OpenRA.Graphics { var sequenceFiles = modData.Manifest.Cursors; - cursors = new Dictionary(); palettes = new Cache(CreatePaletteReference); var sequences = new MiniYaml(null, sequenceFiles.Select(s => MiniYaml.FromFile(s)).Aggregate(MiniYaml.MergeLiberal)); var shadowIndex = new int[] { }; @@ -42,7 +41,6 @@ namespace OpenRA.Graphics out shadowIndex[shadowIndex.Length - 1]); } - palette = new HardwarePalette(); foreach (var p in nodesDict["Palettes"].Nodes) palette.AddPalette(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false); diff --git a/OpenRA.Game/Graphics/LineRenderer.cs b/OpenRA.Game/Graphics/LineRenderer.cs index 6bc4b93323..f7c3ff79ec 100644 --- a/OpenRA.Game/Graphics/LineRenderer.cs +++ b/OpenRA.Game/Graphics/LineRenderer.cs @@ -15,14 +15,16 @@ namespace OpenRA.Graphics { public class LineRenderer : Renderer.IBatchRenderer { - static float2 offset = new float2(0.5f, 0.5f); - float lineWidth = 1f; - Renderer renderer; - IShader shader; + static readonly float2 Offset = new float2(0.5f, 0.5f); + + readonly Renderer renderer; + readonly IShader shader; readonly Vertex[] vertices; int nv = 0; + float lineWidth = 1f; + public LineRenderer(Renderer renderer, IShader shader) { this.renderer = renderer; @@ -30,10 +32,12 @@ namespace OpenRA.Graphics vertices = new Vertex[renderer.TempBufferSize]; } - public float LineWidth { - get { return lineWidth; } + get + { + return lineWidth; + } set { if (LineWidth != value) @@ -77,11 +81,11 @@ namespace OpenRA.Graphics if (nv + 2 > renderer.TempBufferSize) Flush(); - vertices[nv++] = new Vertex(start + offset, + vertices[nv++] = new Vertex(start + Offset, startColor.R / 255.0f, startColor.G / 255.0f, startColor.B / 255.0f, startColor.A / 255.0f); - vertices[nv++] = new Vertex(end + offset, + vertices[nv++] = new Vertex(end + Offset, endColor.R / 255.0f, endColor.G / 255.0f, endColor.B / 255.0f, endColor.A / 255.0f); } @@ -100,7 +104,7 @@ namespace OpenRA.Graphics var yc = (r.Bottom + r.Top) / 2; for (var y = r.Top; y <= r.Bottom; y++) { - var dx = a * (float)(Math.Sqrt(1 - (y - yc) * (y - yc) / b / b)); + var dx = a * (float)Math.Sqrt(1 - (y - yc) * (y - yc) / b / b); DrawLine(new float2(xc - dx, y), new float2(xc + dx, y), color, color); } } @@ -108,7 +112,7 @@ namespace OpenRA.Graphics public void SetViewportParams(Size screen, float zoom, int2 scroll) { shader.SetVec("Scroll", scroll.X, scroll.Y); - shader.SetVec("r1", zoom*2f/screen.Width, -zoom*2f/screen.Height); + shader.SetVec("r1", zoom * 2f / screen.Width, -zoom * 2f / screen.Height); shader.SetVec("r2", -1, 1); } } diff --git a/OpenRA.Game/Graphics/QuadRenderer.cs b/OpenRA.Game/Graphics/QuadRenderer.cs index 254064c714..c3f562a4f7 100644 --- a/OpenRA.Game/Graphics/QuadRenderer.cs +++ b/OpenRA.Game/Graphics/QuadRenderer.cs @@ -14,8 +14,8 @@ namespace OpenRA.Graphics { public class QuadRenderer : Renderer.IBatchRenderer { - Renderer renderer; - IShader shader; + readonly Renderer renderer; + readonly IShader shader; readonly Vertex[] vertices; int nv = 0; @@ -66,7 +66,7 @@ namespace OpenRA.Graphics public void SetViewportParams(Size screen, float zoom, int2 scroll) { shader.SetVec("Scroll", scroll.X, scroll.Y); - shader.SetVec("r1", zoom*2f/screen.Width, -zoom*2f/screen.Height); + shader.SetVec("r1", zoom * 2f / screen.Width, -zoom * 2f / screen.Height); shader.SetVec("r2", -1, 1); } } diff --git a/OpenRA.Game/Graphics/Renderer.cs b/OpenRA.Game/Graphics/Renderer.cs index d6818475d2..c99cd38d94 100644 --- a/OpenRA.Game/Graphics/Renderer.cs +++ b/OpenRA.Game/Graphics/Renderer.cs @@ -11,7 +11,6 @@ using System; using System.Collections.Generic; using System.Drawing; -using System.IO; using System.Linq; using System.Reflection; using OpenRA.Support; @@ -20,10 +19,6 @@ namespace OpenRA.Graphics { public sealed class Renderer : IDisposable { - internal int SheetSize { get; private set; } - internal int TempBufferSize { get; private set; } - internal int TempBufferCount { get; private set; } - public SpriteRenderer WorldSpriteRenderer { get; private set; } public SpriteRenderer WorldRgbaSpriteRenderer { get; private set; } public QuadRenderer WorldQuadRenderer { get; private set; } @@ -32,49 +27,77 @@ namespace OpenRA.Graphics public LineRenderer LineRenderer { get; private set; } public SpriteRenderer RgbaSpriteRenderer { get; private set; } public SpriteRenderer SpriteRenderer { get; private set; } + public IReadOnlyDictionary Fonts; - Queue> tempBuffers = new Queue>(); + internal IGraphicsDevice Device { get; private set; } + internal int SheetSize { get; private set; } + internal int TempBufferSize { get; private set; } + internal int TempBufferCount { get; private set; } - public Dictionary Fonts; - Stack scissorState; + readonly Queue> tempBuffers = new Queue>(); + readonly Stack scissorState = new Stack(); + + Size? lastResolution; + int2? lastScroll; + float? lastZoom; + ITexture currentPaletteTexture; + IBatchRenderer currentBatchRenderer; public Renderer(GraphicSettings graphicSettings, ServerSettings serverSettings) { - Initialize(graphicSettings, serverSettings); + var resolution = GetResolution(graphicSettings); + + var rendererName = serverSettings.Dedicated ? "Null" : graphicSettings.Renderer; + var rendererPath = Platform.ResolvePath(".", "OpenRA.Renderer." + rendererName + ".dll"); + + Device = CreateDevice(Assembly.LoadFile(rendererPath), resolution.Width, resolution.Height, graphicSettings.Mode); TempBufferSize = graphicSettings.BatchSize; TempBufferCount = graphicSettings.NumTempBuffers; SheetSize = graphicSettings.SheetSize; - scissorState = new Stack(); - WorldSpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp")); - WorldRgbaSpriteRenderer = new SpriteRenderer(this, device.CreateShader("rgba")); - WorldLineRenderer = new LineRenderer(this, device.CreateShader("line")); - WorldVoxelRenderer = new VoxelRenderer(this, device.CreateShader("vxl")); - LineRenderer = new LineRenderer(this, device.CreateShader("line")); - WorldQuadRenderer = new QuadRenderer(this, device.CreateShader("line")); - RgbaSpriteRenderer = new SpriteRenderer(this, device.CreateShader("rgba")); - SpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp")); + WorldSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("shp")); + WorldRgbaSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("rgba")); + WorldLineRenderer = new LineRenderer(this, Device.CreateShader("line")); + WorldVoxelRenderer = new VoxelRenderer(this, Device.CreateShader("vxl")); + LineRenderer = new LineRenderer(this, Device.CreateShader("line")); + WorldQuadRenderer = new QuadRenderer(this, Device.CreateShader("line")); + RgbaSpriteRenderer = new SpriteRenderer(this, Device.CreateShader("rgba")); + SpriteRenderer = new SpriteRenderer(this, Device.CreateShader("shp")); for (var i = 0; i < TempBufferCount; i++) - tempBuffers.Enqueue(device.CreateVertexBuffer(TempBufferSize)); + tempBuffers.Enqueue(Device.CreateVertexBuffer(TempBufferSize)); + } + + static Size GetResolution(GraphicSettings graphicsSettings) + { + var size = (graphicsSettings.Mode == WindowMode.Windowed) + ? graphicsSettings.WindowedSize + : graphicsSettings.FullscreenSize; + return new Size(size.X, size.Y); + } + + static IGraphicsDevice CreateDevice(Assembly rendererDll, int width, int height, WindowMode window) + { + foreach (RendererAttribute r in rendererDll.GetCustomAttributes(typeof(RendererAttribute), false)) + { + var factory = (IDeviceFactory)r.Type.GetConstructor(Type.EmptyTypes).Invoke(null); + return factory.Create(new Size(width, height), window); + } + + throw new InvalidOperationException("Renderer DLL is missing RendererAttribute to tell us what type to use!"); } public void InitializeFonts(Manifest m) { using (new Support.PerfTimer("SpriteFonts")) - Fonts = m.Fonts.ToDictionary(x => x.Key, x => new SpriteFont(Platform.ResolvePath(x.Value.First), x.Value.Second)); + Fonts = m.Fonts.ToDictionary(x => x.Key, + x => new SpriteFont(Platform.ResolvePath(x.Value.First), x.Value.Second)).AsReadOnly(); } - internal IGraphicsDevice Device { get { return device; } } - - Size? lastResolution; - int2? lastScroll; - float? lastZoom; - public void BeginFrame(int2 scroll, float zoom) { - device.Clear(); + Device.Clear(); var resolutionChanged = lastResolution != Resolution; if (resolutionChanged) @@ -98,7 +121,6 @@ namespace OpenRA.Graphics } } - ITexture currentPaletteTexture; public void SetPalette(HardwarePalette palette) { if (palette.Texture == currentPaletteTexture) @@ -117,8 +139,8 @@ namespace OpenRA.Graphics public void EndFrame(IInputHandler inputHandler) { Flush(); - device.PumpInput(inputHandler); - device.Present(); + Device.PumpInput(inputHandler); + Device.Present(); } public void DrawBatch(IVertexBuffer vertices, @@ -126,7 +148,7 @@ namespace OpenRA.Graphics where T : struct { vertices.Bind(); - device.DrawPrimitives(type, firstVertex, numVertices); + Device.DrawPrimitives(type, firstVertex, numVertices); PerfHistory.Increment("batches", 1); } @@ -137,58 +159,28 @@ namespace OpenRA.Graphics public void SetLineWidth(float width) { - device.SetLineWidth(width); + Device.SetLineWidth(width); } - static IGraphicsDevice device; - - public Size Resolution { get { return device.WindowSize; } } - - void Initialize(GraphicSettings graphicSettings, ServerSettings serverSettings) - { - var resolution = GetResolution(graphicSettings); - - var rendererName = serverSettings.Dedicated ? "Null" : graphicSettings.Renderer; - var rendererPath = Platform.ResolvePath(".", "OpenRA.Renderer." + rendererName + ".dll"); - - device = CreateDevice(Assembly.LoadFile(rendererPath), resolution.Width, resolution.Height, graphicSettings.Mode); - } - - static Size GetResolution(GraphicSettings graphicsSettings) - { - var size = (graphicsSettings.Mode == WindowMode.Windowed) - ? graphicsSettings.WindowedSize - : graphicsSettings.FullscreenSize; - return new Size(size.X, size.Y); - } - - static IGraphicsDevice CreateDevice(Assembly rendererDll, int width, int height, WindowMode window) - { - foreach (RendererAttribute r in rendererDll.GetCustomAttributes(typeof(RendererAttribute), false)) - { - var factory = (IDeviceFactory)r.Type.GetConstructor(Type.EmptyTypes).Invoke(null); - return factory.Create(new Size(width, height), window); - } - - throw new InvalidOperationException("Renderer DLL is missing RendererAttribute to tell us what type to use!"); - } + public Size Resolution { get { return Device.WindowSize; } } internal IVertexBuffer GetTempVertexBuffer() { - var ret = tempBuffers.Dequeue(); - tempBuffers.Enqueue(ret); - return ret; + return tempBuffers.Peek(); } - public interface IBatchRenderer { void Flush(); } + public interface IBatchRenderer { void Flush(); } - IBatchRenderer currentBatchRenderer; public IBatchRenderer CurrentBatchRenderer { - get { return currentBatchRenderer; } + get + { + return currentBatchRenderer; + } set { - if (currentBatchRenderer == value) return; + if (currentBatchRenderer == value) + return; if (currentBatchRenderer != null) currentBatchRenderer.Flush(); currentBatchRenderer = value; @@ -235,12 +227,12 @@ namespace OpenRA.Graphics public void GrabWindowMouseFocus() { - device.GrabWindowMouseFocus(); + Device.GrabWindowMouseFocus(); } public void ReleaseWindowMouseFocus() { - device.ReleaseWindowMouseFocus(); + Device.ReleaseWindowMouseFocus(); } public void Dispose() diff --git a/OpenRA.Game/Graphics/SheetBuilder.cs b/OpenRA.Game/Graphics/SheetBuilder.cs index 4a1ff5dce6..e136654fcc 100644 --- a/OpenRA.Game/Graphics/SheetBuilder.cs +++ b/OpenRA.Game/Graphics/SheetBuilder.cs @@ -32,12 +32,13 @@ namespace OpenRA.Graphics public sealed class SheetBuilder : IDisposable { readonly List sheets = new List(); + readonly SheetType type; + readonly Func allocateSheet; + Sheet current; TextureChannel channel; - SheetType type; int rowHeight = 0; Point p; - Func allocateSheet; public static Sheet AllocateSheet(int sheetSize) { diff --git a/OpenRA.Game/Graphics/SpriteFont.cs b/OpenRA.Game/Graphics/SpriteFont.cs index 562b302855..cf477d66a3 100644 --- a/OpenRA.Game/Graphics/SpriteFont.cs +++ b/OpenRA.Game/Graphics/SpriteFont.cs @@ -22,7 +22,7 @@ namespace OpenRA.Graphics static Library library = new Library(); static SheetBuilder builder; - int size; + readonly int size; string name; public SpriteFont(string name, int size) @@ -114,7 +114,6 @@ namespace OpenRA.Graphics // A new bitmap is generated each time this property is accessed, so we do need to dispose it. using (var bitmap = face.Glyph.Bitmap) - { unsafe { var p = (byte*)bitmap.Buffer; @@ -136,7 +135,7 @@ namespace OpenRA.Graphics p += bitmap.Pitch; } } - } + s.sheet.CommitData(); diff --git a/OpenRA.Game/Graphics/SpriteRenderer.cs b/OpenRA.Game/Graphics/SpriteRenderer.cs index d953128f20..10a0ce6b9b 100644 --- a/OpenRA.Game/Graphics/SpriteRenderer.cs +++ b/OpenRA.Game/Graphics/SpriteRenderer.cs @@ -14,8 +14,8 @@ namespace OpenRA.Graphics { public class SpriteRenderer : Renderer.IBatchRenderer { - Renderer renderer; - IShader shader; + readonly Renderer renderer; + readonly IShader shader; readonly Vertex[] vertices; Sheet currentSheet; @@ -124,7 +124,7 @@ namespace OpenRA.Graphics public void SetViewportParams(Size screen, float zoom, int2 scroll) { shader.SetVec("Scroll", scroll.X, scroll.Y); - shader.SetVec("r1", zoom*2f/screen.Width, -zoom*2f/screen.Height); + shader.SetVec("r1", zoom * 2f / screen.Width, -zoom * 2f / screen.Height); shader.SetVec("r2", -1, 1); } } diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index bf01017cc5..dffe1bf2c3 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -15,10 +15,9 @@ namespace OpenRA.Graphics { sealed class TerrainRenderer : IDisposable { - IVertexBuffer vertexBuffer; - - World world; - Map map; + readonly IVertexBuffer vertexBuffer; + readonly World world; + readonly Map map; public TerrainRenderer(World world, WorldRenderer wr) { @@ -43,7 +42,7 @@ namespace OpenRA.Graphics public void Draw(WorldRenderer wr, Viewport viewport) { - var verticesPerRow = 4*map.Bounds.Width; + var verticesPerRow = 4 * map.Bounds.Width; var cells = viewport.VisibleCells; var shape = wr.world.Map.TileShape; diff --git a/OpenRA.Game/Graphics/Theater.cs b/OpenRA.Game/Graphics/Theater.cs index 684f2fb976..3972a6f564 100644 --- a/OpenRA.Game/Graphics/Theater.cs +++ b/OpenRA.Game/Graphics/Theater.cs @@ -18,9 +18,9 @@ namespace OpenRA.Graphics { public sealed class Theater : IDisposable { - SheetBuilder sheetBuilder; - Dictionary templates; - Sprite missingTile; + readonly Dictionary templates = new Dictionary(); + readonly SheetBuilder sheetBuilder; + readonly Sprite missingTile; TileSet tileset; public Theater(TileSet tileset) diff --git a/OpenRA.Game/Graphics/VoxelLoader.cs b/OpenRA.Game/Graphics/VoxelLoader.cs index 5f80528131..506a5070da 100644 --- a/OpenRA.Game/Graphics/VoxelLoader.cs +++ b/OpenRA.Game/Graphics/VoxelLoader.cs @@ -34,14 +34,16 @@ namespace OpenRA.Graphics public sealed class VoxelLoader : IDisposable { - SheetBuilder sheetBuilder; + static readonly float[] ChannelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; - Cache, Voxel> voxels; + readonly List vertices = new List(); + readonly Cache, Voxel> voxels; IVertexBuffer vertexBuffer; - List vertices; int totalVertexCount; int cachedVertexCount; + SheetBuilder sheetBuilder; + static SheetBuilder CreateSheetBuilder() { var allocated = false; @@ -58,7 +60,7 @@ namespace OpenRA.Graphics public VoxelLoader() { - voxels = new Cache, Voxel>(LoadFile); + voxels = new Cache, Voxel>(LoadFile); vertices = new List(); totalVertexCount = 0; cachedVertexCount = 0; @@ -66,29 +68,28 @@ namespace OpenRA.Graphics sheetBuilder = CreateSheetBuilder(); } - static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; - Vertex[] GenerateSlicePlane(int su, int sv, Func first, Func second, Func coord) + Vertex[] GenerateSlicePlane(int su, int sv, Func first, Func second, Func coord) { - var colors = new byte[su*sv]; - var normals = new byte[su*sv]; + var colors = new byte[su * sv]; + var normals = new byte[su * sv]; var c = 0; for (var v = 0; v < sv; v++) for (var u = 0; u < su; u++) - { - var voxel = first(u,v) ?? second(u,v); - colors[c] = voxel == null ? (byte)0 : voxel.Color; - normals[c] = voxel == null ? (byte)0 : voxel.Normal; - c++; - } + { + var voxel = first(u, v) ?? second(u, v); + colors[c] = voxel == null ? (byte)0 : voxel.Color; + normals[c] = voxel == null ? (byte)0 : voxel.Normal; + c++; + } var s = sheetBuilder.Allocate(new Size(su, sv)); Util.FastCopyIntoChannel(s, 0, colors); Util.FastCopyIntoChannel(s, 1, normals); s.sheet.CommitData(); - var channelP =channelSelect[(int)s.channel]; - var channelC = channelSelect[(int)s.channel + 1]; + var channelP = ChannelSelect[(int)s.channel]; + var channelC = ChannelSelect[(int)s.channel + 1]; return new Vertex[4] { new Vertex(coord(0, 0), s.left, s.top, channelP, channelC), @@ -100,7 +101,7 @@ namespace OpenRA.Graphics IEnumerable GenerateSlicePlanes(VxlLimb l) { - Func get = (x,y,z) => + Func get = (x, y, z) => { if (x < 0 || y < 0 || z < 0) return null; @@ -108,41 +109,41 @@ namespace OpenRA.Graphics if (x >= l.Size[0] || y >= l.Size[1] || z >= l.Size[2]) return null; - var v = l.VoxelMap[(byte)x,(byte)y]; + var v = l.VoxelMap[(byte)x, (byte)y]; if (v == null || !v.ContainsKey((byte)z)) return null; - return l.VoxelMap[(byte)x,(byte)y][(byte)z]; + return l.VoxelMap[(byte)x, (byte)y][(byte)z]; }; // Cull slices without any visible faces - var xPlanes = new bool[l.Size[0]+1]; - var yPlanes = new bool[l.Size[1]+1]; - var zPlanes = new bool[l.Size[2]+1]; + var xPlanes = new bool[l.Size[0] + 1]; + var yPlanes = new bool[l.Size[1] + 1]; + var zPlanes = new bool[l.Size[2] + 1]; for (var x = 0; x < l.Size[0]; x++) { for (var y = 0; y < l.Size[1]; y++) { for (var z = 0; z < l.Size[2]; z++) { - if (get(x,y,z) == null) + if (get(x, y, z) == null) continue; // Only generate a plane if it is actually visible - if (!xPlanes[x] && get(x-1,y,z) == null) + if (!xPlanes[x] && get(x - 1, y, z) == null) xPlanes[x] = true; - if (!xPlanes[x+1] && get(x+1,y,z) == null) - xPlanes[x+1] = true; + if (!xPlanes[x + 1] && get(x + 1, y, z) == null) + xPlanes[x + 1] = true; - if (!yPlanes[y] && get(x,y-1,z) == null) + if (!yPlanes[y] && get(x, y - 1, z) == null) yPlanes[y] = true; - if (!yPlanes[y+1] && get(x,y+1,z) == null) - yPlanes[y+1] = true; + if (!yPlanes[y + 1] && get(x, y + 1, z) == null) + yPlanes[y + 1] = true; - if (!zPlanes[z] && get(x,y,z-1) == null) + if (!zPlanes[z] && get(x, y, z - 1) == null) zPlanes[z] = true; - if (!zPlanes[z+1] && get(x,y,z+1) == null) - zPlanes[z+1] = true; + if (!zPlanes[z + 1] && get(x, y, z + 1) == null) + zPlanes[z + 1] = true; } } } @@ -150,23 +151,23 @@ namespace OpenRA.Graphics for (var x = 0; x <= l.Size[0]; x++) if (xPlanes[x]) yield return GenerateSlicePlane(l.Size[1], l.Size[2], - (u,v) => get(x, u, v), - (u,v) => get(x - 1, u, v), - (u,v) => new float[] {x, u, v}); + (u, v) => get(x, u, v), + (u, v) => get(x - 1, u, v), + (u, v) => new float[] { x, u, v }); for (var y = 0; y <= l.Size[1]; y++) if (yPlanes[y]) yield return GenerateSlicePlane(l.Size[0], l.Size[2], - (u,v) => get(u, y, v), - (u,v) => get(u, y - 1, v), - (u,v) => new float[] {u, y, v}); + (u, v) => get(u, y, v), + (u, v) => get(u, y - 1, v), + (u, v) => new float[] { u, y, v }); for (var z = 0; z <= l.Size[2]; z++) if (zPlanes[z]) yield return GenerateSlicePlane(l.Size[0], l.Size[1], - (u,v) => get(u, v, z), - (u,v) => get(u, v, z - 1), - (u,v) => new float[] {u, v, z}); + (u, v) => get(u, v, z), + (u, v) => get(u, v, z - 1), + (u, v) => new float[] { u, v, z }); } public VoxelRenderData GenerateRenderData(VxlLimb l) @@ -212,7 +213,7 @@ namespace OpenRA.Graphics } } - Voxel LoadFile(Pair files) + Voxel LoadFile(Pair files) { VxlReader vxl; HvaReader hva; diff --git a/OpenRA.Game/Graphics/VoxelRenderer.cs b/OpenRA.Game/Graphics/VoxelRenderer.cs index 8180cdb7ce..6b062b1faf 100644 --- a/OpenRA.Game/Graphics/VoxelRenderer.cs +++ b/OpenRA.Game/Graphics/VoxelRenderer.cs @@ -34,31 +34,28 @@ namespace OpenRA.Graphics public sealed class VoxelRenderer : IDisposable { - Renderer renderer; - IShader shader; + // Static constants + static readonly float[] ShadowDiffuse = new float[] { 0, 0, 0 }; + static readonly float[] ShadowAmbient = new float[] { 1, 1, 1 }; + static readonly float2 SpritePadding = new float2(2, 2); + static readonly float[] ZeroVector = new float[] { 0, 0, 0, 1 }; + static readonly float[] ZVector = new float[] { 0, 0, 1, 1 }; + static readonly float[] FlipMtx = Util.ScaleMatrix(1, -1, 1); + static readonly float[] ShadowScaleFlipMtx = Util.ScaleMatrix(2, -2, 2); + + readonly Renderer renderer; + readonly IShader shader; + + readonly Dictionary mappedBuffers = new Dictionary(); + readonly Stack> unmappedBuffers = new Stack>(); + readonly List> doRender = new List>(); SheetBuilder sheetBuilder; - Dictionary mappedBuffers; - Stack> unmappedBuffers; - List> doRender; - - // Static constants - static readonly float[] shadowDiffuse = new float[] {0,0,0}; - static readonly float[] shadowAmbient = new float[] {1,1,1}; - static readonly float2 spritePadding = new float2(2, 2); - static readonly float[] zeroVector = new float[] {0,0,0,1}; - static readonly float[] zVector = new float[] {0,0,1,1}; - static readonly float[] flipMtx = Util.ScaleMatrix(1, -1, 1); - static readonly float[] shadowScaleFlipMtx = Util.ScaleMatrix(2, -2, 2); public VoxelRenderer(Renderer renderer, IShader shader) { this.renderer = renderer; this.shader = shader; - - mappedBuffers = new Dictionary(); - unmappedBuffers = new Stack>(); - doRender = new List>(); } public void SetPalette(ITexture palette) @@ -73,7 +70,7 @@ namespace OpenRA.Graphics { a, 0, 0, 0, 0, -a, 0, 0, - 0, 0, -2*a, 0, + 0, 0, -2 * a, 0, -1, 1, 0, 1 }; @@ -111,7 +108,7 @@ namespace OpenRA.Graphics var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var worldTransform = v.RotationFunc().Aggregate(Util.IdentityMatrix(), - (x,y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); + (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); worldTransform = Util.MatrixMultiply(scaleTransform, worldTransform); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); @@ -128,18 +125,18 @@ namespace OpenRA.Graphics } // Inflate rects to ensure rendering is within bounds - tl -= spritePadding; - br += spritePadding; - stl -= spritePadding; - sbr += spritePadding; + tl -= SpritePadding; + br += SpritePadding; + stl -= SpritePadding; + sbr += SpritePadding; // Corners of the shadow quad, in shadow-space var corners = new float[][] { - new float[] {stl.X, stl.Y, 0, 1}, - new float[] {sbr.X, sbr.Y, 0, 1}, - new float[] {sbr.X, stl.Y, 0, 1}, - new float[] {stl.X, sbr.Y, 0, 1} + new[] { stl.X, stl.Y, 0, 1 }, + new[] { sbr.X, sbr.Y, 0, 1 }, + new[] { sbr.X, stl.Y, 0, 1 }, + new[] { stl.X, sbr.Y, 0, 1 } }; var shadowScreenTransform = Util.MatrixMultiply(cameraTransform, invShadowTransform); @@ -148,8 +145,8 @@ namespace OpenRA.Graphics for (var j = 0; j < 4; j++) { // Project to ground plane - corners[j][2] = -(corners[j][1]*shadowGroundNormal[1]/shadowGroundNormal[2] + - corners[j][0]*shadowGroundNormal[0]/shadowGroundNormal[2]); + corners[j][2] = -(corners[j][1] * shadowGroundNormal[1] / shadowGroundNormal[2] + + corners[j][0] * shadowGroundNormal[0] / shadowGroundNormal[2]); // Rotate to camera-space corners[j] = Util.MatrixVectorMultiply(shadowScreenTransform, corners[j]); @@ -171,8 +168,8 @@ namespace OpenRA.Graphics var translateMtx = Util.TranslationMatrix(spriteCenter.X - spriteOffset.X, renderer.SheetSize - (spriteCenter.Y - spriteOffset.Y), 0); var shadowTranslateMtx = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, renderer.SheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0); - var correctionTransform = Util.MatrixMultiply(translateMtx, flipMtx); - var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, shadowScaleFlipMtx); + var correctionTransform = Util.MatrixMultiply(translateMtx, FlipMtx); + var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, ShadowScaleFlipMtx); doRender.Add(Pair.New(sprite.sheet, () => { @@ -183,7 +180,7 @@ namespace OpenRA.Graphics var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var rotations = v.RotationFunc().Aggregate(Util.IdentityMatrix(), - (x,y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); + (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x)); var worldTransform = Util.MatrixMultiply(scaleTransform, rotations); worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform); @@ -209,21 +206,21 @@ namespace OpenRA.Graphics // Disable shadow normals by forcing zero diffuse and identity ambient light Render(rd, Util.MatrixMultiply(shadow, t), lightDirection, - shadowAmbient, shadowDiffuse, shadowPalette.Index, normals.Index); + ShadowAmbient, ShadowDiffuse, shadowPalette.Index, normals.Index); } } })); - var screenLightVector = Util.MatrixVectorMultiply(invShadowTransform, zVector); + var screenLightVector = Util.MatrixVectorMultiply(invShadowTransform, ZVector); screenLightVector = Util.MatrixVectorMultiply(cameraTransform, screenLightVector); - return new VoxelRenderProxy(sprite, shadowSprite, screenCorners, -screenLightVector[2]/screenLightVector[1]); + return new VoxelRenderProxy(sprite, shadowSprite, screenCorners, -screenLightVector[2] / screenLightVector[1]); } static void CalculateSpriteGeometry(float2 tl, float2 br, float scale, out Size size, out int2 offset) { - var width = (int)(scale*(br.X - tl.X)); - var height = (int)(scale*(br.Y - tl.Y)); - offset = (0.5f*scale*(br + tl)).ToInt2(); + var width = (int)(scale * (br.X - tl.X)); + var height = (int)(scale * (br.Y - tl.Y)); + offset = (0.5f * scale * (br + tl)).ToInt2(); // Width and height must be even to avoid rendering glitches if ((width & 1) == 1) @@ -236,14 +233,14 @@ namespace OpenRA.Graphics static float[] ExtractRotationVector(float[] mtx) { - var tVec = Util.MatrixVectorMultiply(mtx, zVector); - var tOrigin = Util.MatrixVectorMultiply(mtx, zeroVector); - tVec[0] -= tOrigin[0]*tVec[3]/tOrigin[3]; - tVec[1] -= tOrigin[1]*tVec[3]/tOrigin[3]; - tVec[2] -= tOrigin[2]*tVec[3]/tOrigin[3]; + var tVec = Util.MatrixVectorMultiply(mtx, ZVector); + var tOrigin = Util.MatrixVectorMultiply(mtx, ZeroVector); + tVec[0] -= tOrigin[0] * tVec[3] / tOrigin[3]; + tVec[1] -= tOrigin[1] * tVec[3] / tOrigin[3]; + tVec[2] -= tOrigin[2] * tVec[3] / tOrigin[3]; // Renormalize - var w = (float)Math.Sqrt(tVec[0]*tVec[0] + tVec[1]*tVec[1] + tVec[2]*tVec[2]); + var w = (float)Math.Sqrt(tVec[0] * tVec[0] + tVec[1] * tVec[1] + tVec[2] * tVec[2]); tVec[0] /= w; tVec[1] /= w; tVec[2] /= w; diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 4a9d410ef6..89140b8406 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -35,18 +35,16 @@ namespace OpenRA.Graphics public readonly Theater Theater; public Viewport Viewport { get; private set; } + readonly HardwarePalette palette = new HardwarePalette(); + readonly Dictionary palettes = new Dictionary(); readonly TerrainRenderer terrainRenderer; - readonly HardwarePalette palette; - readonly Dictionary palettes; readonly Lazy devTrait; internal WorldRenderer(World world) { this.world = world; Viewport = new Viewport(this, world.Map); - palette = new HardwarePalette(); - palettes = new Dictionary(); foreach (var pal in world.traitDict.ActorsWithTrait()) pal.Trait.LoadPalettes(this); diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 3dcd09796f..3715a3fbe6 100644 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -25,9 +25,9 @@ namespace OpenRA public readonly WidgetLoader WidgetLoader; public readonly MapCache MapCache; public readonly ISpriteLoader[] SpriteLoaders; - public ILoadScreen LoadScreen = null; - public VoxelLoader VoxelLoader; public readonly RulesetCache RulesetCache; + public ILoadScreen LoadScreen { get; private set; } + public VoxelLoader VoxelLoader { get; private set; } public CursorProvider CursorProvider { get; private set; } Lazy defaultRules; diff --git a/OpenRA.Mods.Cnc/CncLoadScreen.cs b/OpenRA.Mods.Cnc/CncLoadScreen.cs index 29d1d9cf06..1f3d424737 100644 --- a/OpenRA.Mods.Cnc/CncLoadScreen.cs +++ b/OpenRA.Mods.Cnc/CncLoadScreen.cs @@ -11,8 +11,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Drawing; -using System.Linq; -using OpenRA.FileSystem; using OpenRA.Graphics; using OpenRA.Widgets; @@ -29,7 +27,7 @@ namespace OpenRA.Mods.Cnc Sprite nodLogo, gdiLogo, evaLogo, brightBlock, dimBlock; Rectangle bounds; Renderer r; - NullInputHandler nih = new NullInputHandler(); + readonly NullInputHandler nih = new NullInputHandler(); public void Init(Manifest m, Dictionary info) { diff --git a/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs index b8ad1c579c..c04fa6738d 100644 --- a/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/DefaultLoadScreen.cs @@ -11,8 +11,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Drawing; -using System.Linq; -using OpenRA.FileSystem; using OpenRA.Graphics; using OpenRA.Widgets; diff --git a/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs index d624827991..8b7e110d3d 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs @@ -20,16 +20,16 @@ namespace OpenRA.Mods.Common.Widgets.Logic { public class ModBrowserLogic { - Widget modList; - ButtonWidget modTemplate; - ModMetadata[] allMods; + readonly Widget modList; + readonly ButtonWidget modTemplate; + readonly ModMetadata[] allMods; + readonly Dictionary previews = new Dictionary(); + readonly Dictionary logos = new Dictionary(); readonly SheetBuilder sheetBuilder; ModMetadata selectedMod; string selectedAuthor; string selectedDescription; int modOffset = 0; - Dictionary previews; - Dictionary logos; [ObjectCreator.UseCtor] public ModBrowserLogic(Widget widget) @@ -65,8 +65,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic }; sheetBuilder = new SheetBuilder(SheetType.BGRA); - previews = new Dictionary(); - logos = new Dictionary(); allMods = ModMetadata.AllMods.Values.Where(m => m.Id != "modchooser") .OrderBy(m => m.Title) .ToArray(); diff --git a/OpenRA.Renderer.Sdl2/Texture.cs b/OpenRA.Renderer.Sdl2/Texture.cs index 60efb8c433..3e3ae2bd7a 100644 --- a/OpenRA.Renderer.Sdl2/Texture.cs +++ b/OpenRA.Renderer.Sdl2/Texture.cs @@ -130,6 +130,7 @@ namespace OpenRA.Renderer.Sdl2 bitmap = new Bitmap(bitmap, bitmap.Size.NextPowerOf2()); allocatedBitmap = true; } + try { size = new Size(bitmap.Width, bitmap.Height); From b28d999131a21ecf1b9259f45eb77daa64d5cda8 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Sun, 7 Dec 2014 17:28:01 +0000 Subject: [PATCH 3/3] Made SheetBuilder rely on global settings rather than global renderer. Additionally exposed an InitializeSettings method on game to initialize the global settings so that other classes can set up all the secret dependencies on the global settings required. --- OpenRA.Editor/Form1.cs | 16 ++++++++-------- OpenRA.Game/Game.cs | 7 ++++++- OpenRA.Game/Graphics/SheetBuilder.cs | 2 +- OpenRA.Lint/YamlChecker.cs | 4 +--- OpenRA.Utility/Program.cs | 1 + 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/OpenRA.Editor/Form1.cs b/OpenRA.Editor/Form1.cs index c9834e1c8d..e68aac57e9 100644 --- a/OpenRA.Editor/Form1.cs +++ b/OpenRA.Editor/Form1.cs @@ -46,6 +46,7 @@ namespace OpenRA.Editor miniMapBox.Image = null; currentMod = toolStripComboBox1.SelectedItem as string; + Game.InitializeSettings(Arguments.Empty); Game.modData = new ModData(currentMod); GlobalFileSystem.LoadFromManifest(Game.modData.Manifest); Program.Rules = Game.modData.RulesetCache.LoadDefaultRules(); @@ -203,10 +204,10 @@ namespace OpenRA.Editor Height = bitmap.Height / 2, SizeMode = PictureBoxSizeMode.StretchImage }; - + var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key }; ibox.Click += (_, e) => surface1.SetTool(new BrushTool(brushTemplate)); - + var template = t.Value; tilePalette.Controls.Add(ibox); tt.SetToolTip(ibox, "{1}:{0} ({2}x{3})".F(template.Image, template.Id, template.Size.X, template.Size.Y)); @@ -463,7 +464,7 @@ namespace OpenRA.Editor void ExportMinimap(object sender, EventArgs e) { using (var sfd = new SaveFileDialog() - { + { InitialDirectory = Path.Combine(Environment.CurrentDirectory, "maps"), DefaultExt = "*.png", Filter = "PNG Image (*.png)|*.png", @@ -471,9 +472,8 @@ namespace OpenRA.Editor FileName = Path.ChangeExtension(loadedMapName, ".png"), RestoreDirectory = true }) - - if (DialogResult.OK == sfd.ShowDialog()) - miniMapBox.Image.Save(sfd.FileName); + if (DialogResult.OK == sfd.ShowDialog()) + miniMapBox.Image.Save(sfd.FileName); } void ShowActorNamesClicked(object sender, EventArgs e) @@ -637,7 +637,7 @@ namespace OpenRA.Editor { ShowGridClicked(sender, e); } - + public int CalculateTotalResource() { var totalResource = 0; @@ -651,7 +651,7 @@ namespace OpenRA.Editor return totalResource; } - + int GetAdjecentCellsWith(int resourceType, int x, int y) { var sum = 0; diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 506ad986e6..1fbb6d8683 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -175,13 +175,18 @@ namespace OpenRA public static Modifiers GetModifierKeys() { return modifiers; } internal static void HandleModifierKeys(Modifiers mods) { modifiers = mods; } + public static void InitializeSettings(Arguments args) + { + Settings = new Settings(Platform.ResolvePath("^", "settings.yaml"), args); + } + internal static void Initialize(Arguments args) { Console.WriteLine("Platform is {0}", Platform.CurrentPlatform); AppDomain.CurrentDomain.AssemblyResolve += GlobalFileSystem.ResolveAssembly; - Settings = new Settings(Platform.ResolvePath("^", "settings.yaml"), args); + InitializeSettings(args); Log.AddChannel("perf", "perf.log"); Log.AddChannel("debug", "debug.log"); diff --git a/OpenRA.Game/Graphics/SheetBuilder.cs b/OpenRA.Game/Graphics/SheetBuilder.cs index e136654fcc..b79eb2d0cc 100644 --- a/OpenRA.Game/Graphics/SheetBuilder.cs +++ b/OpenRA.Game/Graphics/SheetBuilder.cs @@ -46,7 +46,7 @@ namespace OpenRA.Graphics } public SheetBuilder(SheetType t) - : this(t, Game.Renderer.SheetSize) { } + : this(t, Game.Settings.Graphics.SheetSize) { } public SheetBuilder(SheetType t, int sheetSize) : this(t, () => AllocateSheet(sheetSize)) { } diff --git a/OpenRA.Lint/YamlChecker.cs b/OpenRA.Lint/YamlChecker.cs index 11e70ae4e8..c8686378bb 100644 --- a/OpenRA.Lint/YamlChecker.cs +++ b/OpenRA.Lint/YamlChecker.cs @@ -55,9 +55,7 @@ namespace OpenRA.Lint FieldLoader.UnknownFieldAction = (s, f) => EmitError("FieldLoader: Missing field `{0}` on `{1}`".F(s, f.Name)); AppDomain.CurrentDomain.AssemblyResolve += GlobalFileSystem.ResolveAssembly; - Game.Renderer = new Graphics.Renderer( - new GraphicSettings() { Renderer = "Null", NumTempBuffers = 0, SheetSize = 0 }, - new ServerSettings()); + Game.InitializeSettings(Arguments.Empty); Game.modData = new ModData(mod); IEnumerable maps; diff --git a/OpenRA.Utility/Program.cs b/OpenRA.Utility/Program.cs index 0a403c2ecc..8b79d8f580 100644 --- a/OpenRA.Utility/Program.cs +++ b/OpenRA.Utility/Program.cs @@ -38,6 +38,7 @@ namespace OpenRA.Utility return; } + Game.InitializeSettings(Arguments.Empty); var modData = new ModData(modName); args = args.Skip(1).ToArray(); var actions = new Dictionary>();