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.
This commit is contained in:
committed by
RoosterDragon
parent
38b579a081
commit
f0f02dff5c
@@ -140,7 +140,10 @@ namespace OpenRA
|
|||||||
orderManager.World = new World(map, orderManager, isShellmap);
|
orderManager.World = new World(map, orderManager, isShellmap);
|
||||||
orderManager.World.Timestep = Timestep;
|
orderManager.World.Timestep = Timestep;
|
||||||
}
|
}
|
||||||
|
if (worldRenderer != null)
|
||||||
|
worldRenderer.Dispose();
|
||||||
worldRenderer = new WorldRenderer(orderManager.World);
|
worldRenderer = new WorldRenderer(orderManager.World);
|
||||||
|
|
||||||
using (new PerfTimer("LoadComplete"))
|
using (new PerfTimer("LoadComplete"))
|
||||||
orderManager.World.LoadComplete(worldRenderer);
|
orderManager.World.LoadComplete(worldRenderer);
|
||||||
|
|
||||||
@@ -215,7 +218,7 @@ namespace OpenRA
|
|||||||
Settings.Graphics.Renderer = r;
|
Settings.Graphics.Renderer = r;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Renderer.Initialize(Settings.Graphics.Mode);
|
Renderer = new Renderer(Settings.Graphics, Settings.Server);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -225,8 +228,6 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer = new Renderer();
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Sound.Create(Settings.Sound.Engine);
|
Sound.Create(Settings.Sound.Engine);
|
||||||
@@ -257,12 +258,18 @@ namespace OpenRA
|
|||||||
BeforeGameStart = () => { };
|
BeforeGameStart = () => { };
|
||||||
Ui.ResetAll();
|
Ui.ResetAll();
|
||||||
|
|
||||||
|
if (worldRenderer != null)
|
||||||
|
worldRenderer.Dispose();
|
||||||
worldRenderer = null;
|
worldRenderer = null;
|
||||||
if (server != null)
|
if (server != null)
|
||||||
server.Shutdown();
|
server.Shutdown();
|
||||||
if (orderManager != null)
|
if (orderManager != null)
|
||||||
orderManager.Dispose();
|
orderManager.Dispose();
|
||||||
|
|
||||||
|
if (modData != null)
|
||||||
|
modData.Dispose();
|
||||||
|
modData = null;
|
||||||
|
|
||||||
// Fall back to default if the mod doesn't exist
|
// Fall back to default if the mod doesn't exist
|
||||||
if (!ModMetadata.AllMods.ContainsKey(mod))
|
if (!ModMetadata.AllMods.ContainsKey(mod))
|
||||||
mod = new GameSettings().Mod;
|
mod = new GameSettings().Mod;
|
||||||
@@ -274,7 +281,7 @@ namespace OpenRA
|
|||||||
Sound.StopVideo();
|
Sound.StopVideo();
|
||||||
Sound.Initialize();
|
Sound.Initialize();
|
||||||
|
|
||||||
modData = new ModData(mod);
|
modData = new ModData(mod, true);
|
||||||
Renderer.InitializeFonts(modData.Manifest);
|
Renderer.InitializeFonts(modData.Manifest);
|
||||||
modData.InitializeLoaders();
|
modData.InitializeLoaders();
|
||||||
using (new PerfTimer("LoadMaps"))
|
using (new PerfTimer("LoadMaps"))
|
||||||
@@ -632,8 +639,12 @@ namespace OpenRA
|
|||||||
if (orderManager != null)
|
if (orderManager != null)
|
||||||
orderManager.Dispose();
|
orderManager.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer.Device.Dispose();
|
if (worldRenderer != null)
|
||||||
|
worldRenderer.Dispose();
|
||||||
|
modData.Dispose();
|
||||||
|
ChromeProvider.Deinitialize();
|
||||||
|
Renderer.Dispose();
|
||||||
|
|
||||||
OnQuit();
|
OnQuit();
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ using OpenRA.Support;
|
|||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
{
|
{
|
||||||
public class RulesetCache
|
public sealed class RulesetCache : IDisposable
|
||||||
{
|
{
|
||||||
readonly ModData modData;
|
readonly ModData modData;
|
||||||
|
|
||||||
@@ -137,5 +137,12 @@ namespace OpenRA
|
|||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var cache in sequenceCaches.Values)
|
||||||
|
cache.Dispose();
|
||||||
|
sequenceCaches.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public static void Initialize(IEnumerable<string> chromeFiles)
|
public static void Initialize(IEnumerable<string> chromeFiles)
|
||||||
{
|
{
|
||||||
|
Deinitialize();
|
||||||
|
|
||||||
collections = new Dictionary<string, Collection>();
|
collections = new Dictionary<string, Collection>();
|
||||||
cachedSheets = new Dictionary<string, Sheet>();
|
cachedSheets = new Dictionary<string, Sheet>();
|
||||||
cachedSprites = new Dictionary<string, Dictionary<string, Sprite>>();
|
cachedSprites = new Dictionary<string, Dictionary<string, Sprite>>();
|
||||||
@@ -37,6 +39,17 @@ namespace OpenRA.Graphics
|
|||||||
LoadCollection(c.Key, c.Value);
|
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)
|
public static void Save(string file)
|
||||||
{
|
{
|
||||||
var root = new List<MiniYamlNode>();
|
var root = new List<MiniYamlNode>();
|
||||||
|
|||||||
@@ -16,11 +16,12 @@ using OpenRA.Primitives;
|
|||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
public class CursorProvider
|
public sealed class CursorProvider : IDisposable
|
||||||
{
|
{
|
||||||
HardwarePalette palette;
|
HardwarePalette palette;
|
||||||
Dictionary<string, CursorSequence> cursors;
|
Dictionary<string, CursorSequence> cursors;
|
||||||
Cache<string, PaletteReference> palettes;
|
Cache<string, PaletteReference> palettes;
|
||||||
|
readonly SheetBuilder sheetBuilder;
|
||||||
|
|
||||||
public static bool CursorViewportZoomed { get { return Game.Settings.Graphics.CursorDouble && Game.Settings.Graphics.PixelDouble; } }
|
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)
|
foreach (var p in nodesDict["Palettes"].Nodes)
|
||||||
palette.AddPalette(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false);
|
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)
|
foreach (var s in nodesDict["Cursors"].Nodes)
|
||||||
LoadSequencesForCursor(spriteCache, s.Key, s.Value);
|
LoadSequencesForCursor(spriteCache, s.Key, s.Value);
|
||||||
spriteCache.SheetBuilder.Current.ReleaseBuffer();
|
sheetBuilder.Current.ReleaseBuffer();
|
||||||
|
|
||||||
palette.Initialize();
|
palette.Initialize();
|
||||||
}
|
}
|
||||||
@@ -95,5 +97,11 @@ namespace OpenRA.Graphics
|
|||||||
throw new InvalidOperationException("Cursor does not have a sequence `{0}`".F(cursor));
|
throw new InvalidOperationException("Cursor does not have a sequence `{0}`".F(cursor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
palette.Dispose();
|
||||||
|
sheetBuilder.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ using OpenRA.Traits;
|
|||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
public class HardwarePalette
|
public sealed class HardwarePalette : IDisposable
|
||||||
{
|
{
|
||||||
public const int MaxPalettes = 256;
|
public const int MaxPalettes = 256;
|
||||||
|
|
||||||
@@ -111,5 +111,10 @@ namespace OpenRA.Graphics
|
|||||||
modifiedPalette.SetFromPalette(originalPalette);
|
modifiedPalette.SetFromPalette(originalPalette);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Texture.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace OpenRA
|
|||||||
void ReleaseWindowMouseFocus();
|
void ReleaseWindowMouseFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IVertexBuffer<T>
|
public interface IVertexBuffer<T> : IDisposable
|
||||||
{
|
{
|
||||||
void Bind();
|
void Bind();
|
||||||
void SetData(T[] vertices, int length);
|
void SetData(T[] vertices, int length);
|
||||||
@@ -80,7 +80,8 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum TextureScaleFilter { Nearest, Linear }
|
public enum TextureScaleFilter { Nearest, Linear }
|
||||||
public interface ITexture
|
|
||||||
|
public interface ITexture : IDisposable
|
||||||
{
|
{
|
||||||
void SetData(Bitmap bitmap);
|
void SetData(Bitmap bitmap);
|
||||||
void SetData(uint[,] colors);
|
void SetData(uint[,] colors);
|
||||||
@@ -90,7 +91,7 @@ namespace OpenRA
|
|||||||
TextureScaleFilter ScaleFilter { get; set; }
|
TextureScaleFilter ScaleFilter { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IFrameBuffer
|
public interface IFrameBuffer : IDisposable
|
||||||
{
|
{
|
||||||
void Bind();
|
void Bind();
|
||||||
void Unbind();
|
void Unbind();
|
||||||
|
|||||||
@@ -20,13 +20,14 @@ namespace OpenRA.Graphics
|
|||||||
Renderer renderer;
|
Renderer renderer;
|
||||||
IShader shader;
|
IShader shader;
|
||||||
|
|
||||||
Vertex[] vertices = new Vertex[Renderer.TempBufferSize];
|
readonly Vertex[] vertices;
|
||||||
int nv = 0;
|
int nv = 0;
|
||||||
|
|
||||||
public LineRenderer(Renderer renderer, IShader shader)
|
public LineRenderer(Renderer renderer, IShader shader)
|
||||||
{
|
{
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.shader = shader;
|
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)
|
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();
|
Flush();
|
||||||
|
|
||||||
vertices[nv++] = new Vertex(start + offset,
|
vertices[nv++] = new Vertex(start + offset,
|
||||||
|
|||||||
@@ -203,8 +203,8 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public static Bitmap RenderMapPreview(TileSet tileset, Map map, Ruleset resourceRules, bool actualSize)
|
public static Bitmap RenderMapPreview(TileSet tileset, Map map, Ruleset resourceRules, bool actualSize)
|
||||||
{
|
{
|
||||||
var terrain = TerrainBitmap(tileset, map, actualSize);
|
using (var terrain = TerrainBitmap(tileset, map, actualSize))
|
||||||
return AddStaticResources(tileset, map, resourceRules, terrain);
|
return AddStaticResources(tileset, map, resourceRules, terrain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ namespace OpenRA.Graphics
|
|||||||
Renderer renderer;
|
Renderer renderer;
|
||||||
IShader shader;
|
IShader shader;
|
||||||
|
|
||||||
Vertex[] vertices = new Vertex[Renderer.TempBufferSize];
|
readonly Vertex[] vertices;
|
||||||
int nv = 0;
|
int nv = 0;
|
||||||
|
|
||||||
public QuadRenderer(Renderer renderer, IShader shader)
|
public QuadRenderer(Renderer renderer, IShader shader)
|
||||||
{
|
{
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.shader = shader;
|
this.shader = shader;
|
||||||
|
vertices = new Vertex[renderer.TempBufferSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flush()
|
public void Flush()
|
||||||
@@ -45,9 +46,9 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public void FillRect(RectangleF rect, Color color)
|
public void FillRect(RectangleF rect, Color color)
|
||||||
{
|
{
|
||||||
Renderer.CurrentBatchRenderer = this;
|
renderer.CurrentBatchRenderer = this;
|
||||||
|
|
||||||
if (nv + 4 > Renderer.TempBufferSize)
|
if (nv + 4 > renderer.TempBufferSize)
|
||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
var r = color.R / 255.0f;
|
var r = color.R / 255.0f;
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ using OpenRA.Support;
|
|||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
public class Renderer
|
public sealed class Renderer : IDisposable
|
||||||
{
|
{
|
||||||
internal static int SheetSize;
|
internal int SheetSize { get; private set; }
|
||||||
internal static int TempBufferSize;
|
internal int TempBufferSize { get; private set; }
|
||||||
internal static int TempBufferCount;
|
internal int TempBufferCount { get; private set; }
|
||||||
|
|
||||||
public SpriteRenderer WorldSpriteRenderer { get; private set; }
|
public SpriteRenderer WorldSpriteRenderer { get; private set; }
|
||||||
public SpriteRenderer WorldRgbaSpriteRenderer { get; private set; }
|
public SpriteRenderer WorldRgbaSpriteRenderer { get; private set; }
|
||||||
@@ -38,11 +38,13 @@ namespace OpenRA.Graphics
|
|||||||
public Dictionary<string, SpriteFont> Fonts;
|
public Dictionary<string, SpriteFont> Fonts;
|
||||||
Stack<Rectangle> scissorState;
|
Stack<Rectangle> scissorState;
|
||||||
|
|
||||||
public Renderer()
|
public Renderer(GraphicSettings graphicSettings, ServerSettings serverSettings)
|
||||||
{
|
{
|
||||||
TempBufferSize = Game.Settings.Graphics.BatchSize;
|
Initialize(graphicSettings, serverSettings);
|
||||||
TempBufferCount = Game.Settings.Graphics.NumTempBuffers;
|
|
||||||
SheetSize = Game.Settings.Graphics.SheetSize;
|
TempBufferSize = graphicSettings.BatchSize;
|
||||||
|
TempBufferCount = graphicSettings.NumTempBuffers;
|
||||||
|
SheetSize = graphicSettings.SheetSize;
|
||||||
scissorState = new Stack<Rectangle>();
|
scissorState = new Stack<Rectangle>();
|
||||||
|
|
||||||
WorldSpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp"));
|
WorldSpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp"));
|
||||||
@@ -142,21 +144,21 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public Size Resolution { get { return device.WindowSize; } }
|
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 rendererName = serverSettings.Dedicated ? "Null" : graphicSettings.Renderer;
|
||||||
var rendererPath = Platform.ResolvePath(".", "OpenRA.Renderer." + renderer + ".dll");
|
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)
|
var size = (graphicsSettings.Mode == WindowMode.Windowed)
|
||||||
? Game.Settings.Graphics.WindowedSize
|
? graphicsSettings.WindowedSize
|
||||||
: Game.Settings.Graphics.FullscreenSize;
|
: graphicsSettings.FullscreenSize;
|
||||||
return new Size(size.X, size.Y);
|
return new Size(size.X, size.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,8 +182,8 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public interface IBatchRenderer { void Flush(); }
|
public interface IBatchRenderer { void Flush(); }
|
||||||
|
|
||||||
static IBatchRenderer currentBatchRenderer;
|
IBatchRenderer currentBatchRenderer;
|
||||||
public static IBatchRenderer CurrentBatchRenderer
|
public IBatchRenderer CurrentBatchRenderer
|
||||||
{
|
{
|
||||||
get { return currentBatchRenderer; }
|
get { return currentBatchRenderer; }
|
||||||
set
|
set
|
||||||
@@ -240,5 +242,14 @@ namespace OpenRA.Graphics
|
|||||||
{
|
{
|
||||||
device.ReleaseWindowMouseFocus();
|
device.ReleaseWindowMouseFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Device.Dispose();
|
||||||
|
WorldVoxelRenderer.Dispose();
|
||||||
|
foreach (var buffer in tempBuffers)
|
||||||
|
buffer.Dispose();
|
||||||
|
tempBuffers.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ namespace OpenRA.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SequenceCache
|
public sealed class SequenceCache : IDisposable
|
||||||
{
|
{
|
||||||
readonly ModData modData;
|
readonly ModData modData;
|
||||||
readonly Lazy<SpriteCache> spriteCache;
|
readonly Lazy<SpriteCache> spriteCache;
|
||||||
@@ -141,5 +141,11 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
return new ReadOnlyDictionary<string, Sequence>(unitSequences);
|
return new ReadOnlyDictionary<string, Sequence>(unitSequences);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (spriteCache.IsValueCreated)
|
||||||
|
spriteCache.Value.SheetBuilder.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ using OpenRA.FileSystem;
|
|||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
public class Sheet
|
public sealed class Sheet : IDisposable
|
||||||
{
|
{
|
||||||
readonly object textureLock = new object();
|
readonly object textureLock = new object();
|
||||||
bool dirty;
|
bool dirty;
|
||||||
@@ -178,5 +178,11 @@ namespace OpenRA.Graphics
|
|||||||
releaseBufferOnCommit = true;
|
releaseBufferOnCommit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (texture != null)
|
||||||
|
texture.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
@@ -27,8 +29,9 @@ namespace OpenRA.Graphics
|
|||||||
BGRA = 4,
|
BGRA = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SheetBuilder
|
public sealed class SheetBuilder : IDisposable
|
||||||
{
|
{
|
||||||
|
readonly List<Sheet> sheets = new List<Sheet>();
|
||||||
Sheet current;
|
Sheet current;
|
||||||
TextureChannel channel;
|
TextureChannel channel;
|
||||||
SheetType type;
|
SheetType type;
|
||||||
@@ -36,19 +39,23 @@ namespace OpenRA.Graphics
|
|||||||
Point p;
|
Point p;
|
||||||
Func<Sheet> allocateSheet;
|
Func<Sheet> 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)
|
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<Sheet> allocateSheet)
|
public SheetBuilder(SheetType t, Func<Sheet> allocateSheet)
|
||||||
{
|
{
|
||||||
channel = TextureChannel.Red;
|
channel = TextureChannel.Red;
|
||||||
type = t;
|
type = t;
|
||||||
current = allocateSheet();
|
current = allocateSheet();
|
||||||
|
sheets.Add(current);
|
||||||
this.allocateSheet = allocateSheet;
|
this.allocateSheet = allocateSheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +118,7 @@ namespace OpenRA.Graphics
|
|||||||
{
|
{
|
||||||
current.ReleaseBuffer();
|
current.ReleaseBuffer();
|
||||||
current = allocateSheet();
|
current = allocateSheet();
|
||||||
|
sheets.Add(current);
|
||||||
channel = TextureChannel.Red;
|
channel = TextureChannel.Red;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -127,5 +135,12 @@ namespace OpenRA.Graphics
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Sheet Current { get { return current; } }
|
public Sheet Current { get { return current; } }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var sheet in sheets)
|
||||||
|
sheet.Dispose();
|
||||||
|
sheets.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ namespace OpenRA.Graphics
|
|||||||
Renderer renderer;
|
Renderer renderer;
|
||||||
IShader shader;
|
IShader shader;
|
||||||
|
|
||||||
Vertex[] vertices = new Vertex[Renderer.TempBufferSize];
|
readonly Vertex[] vertices;
|
||||||
Sheet currentSheet = null;
|
Sheet currentSheet;
|
||||||
BlendMode currentBlend = BlendMode.Alpha;
|
BlendMode currentBlend = BlendMode.Alpha;
|
||||||
int nv = 0;
|
int nv = 0;
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@ namespace OpenRA.Graphics
|
|||||||
{
|
{
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.shader = shader;
|
this.shader = shader;
|
||||||
|
vertices = new Vertex[renderer.TempBufferSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flush()
|
public void Flush()
|
||||||
@@ -60,7 +61,7 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size)
|
void DrawSprite(Sprite s, float2 location, int paletteIndex, float2 size)
|
||||||
{
|
{
|
||||||
Renderer.CurrentBatchRenderer = this;
|
renderer.CurrentBatchRenderer = this;
|
||||||
|
|
||||||
if (s.sheet != currentSheet)
|
if (s.sheet != currentSheet)
|
||||||
Flush();
|
Flush();
|
||||||
@@ -68,7 +69,7 @@ namespace OpenRA.Graphics
|
|||||||
if (s.blendMode != currentBlend)
|
if (s.blendMode != currentBlend)
|
||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
if (nv + 4 > Renderer.TempBufferSize)
|
if (nv + 4 > renderer.TempBufferSize)
|
||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
currentBlend = s.blendMode;
|
currentBlend = s.blendMode;
|
||||||
@@ -90,7 +91,7 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public void DrawSprite(Sprite s, float2 a, float2 b, float2 c, float2 d)
|
public void DrawSprite(Sprite s, float2 a, float2 b, float2 c, float2 d)
|
||||||
{
|
{
|
||||||
Renderer.CurrentBatchRenderer = this;
|
renderer.CurrentBatchRenderer = this;
|
||||||
|
|
||||||
if (s.sheet != currentSheet)
|
if (s.sheet != currentSheet)
|
||||||
Flush();
|
Flush();
|
||||||
@@ -98,7 +99,7 @@ namespace OpenRA.Graphics
|
|||||||
if (s.blendMode != currentBlend)
|
if (s.blendMode != currentBlend)
|
||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
if (nv + 4 > Renderer.TempBufferSize)
|
if (nv + 4 > renderer.TempBufferSize)
|
||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
currentSheet = s.sheet;
|
currentSheet = s.sheet;
|
||||||
|
|||||||
@@ -8,11 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
class TerrainRenderer
|
sealed class TerrainRenderer : IDisposable
|
||||||
{
|
{
|
||||||
IVertexBuffer<Vertex> vertexBuffer;
|
IVertexBuffer<Vertex> vertexBuffer;
|
||||||
|
|
||||||
@@ -58,5 +59,10 @@ namespace OpenRA.Graphics
|
|||||||
foreach (var r in world.WorldActor.TraitsImplementing<IRenderOverlay>())
|
foreach (var r in world.WorldActor.TraitsImplementing<IRenderOverlay>())
|
||||||
r.Render(wr);
|
r.Render(wr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
vertexBuffer.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ using OpenRA.FileSystem;
|
|||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
public class Theater
|
public sealed class Theater : IDisposable
|
||||||
{
|
{
|
||||||
SheetBuilder sheetBuilder;
|
SheetBuilder sheetBuilder;
|
||||||
Dictionary<ushort, Sprite[]> templates;
|
Dictionary<ushort, Sprite[]> templates;
|
||||||
@@ -101,5 +101,10 @@ namespace OpenRA.Graphics
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Sheet Sheet { get { return sheetBuilder.Current; } }
|
public Sheet Sheet { get { return sheetBuilder.Current; } }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
sheetBuilder.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace OpenRA.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VoxelLoader
|
public sealed class VoxelLoader : IDisposable
|
||||||
{
|
{
|
||||||
SheetBuilder sheetBuilder;
|
SheetBuilder sheetBuilder;
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ namespace OpenRA.Graphics
|
|||||||
if (allocated)
|
if (allocated)
|
||||||
throw new SheetOverflowException("");
|
throw new SheetOverflowException("");
|
||||||
allocated = true;
|
allocated = true;
|
||||||
return SheetBuilder.AllocateSheet();
|
return SheetBuilder.AllocateSheet(Game.Renderer.SheetSize);
|
||||||
};
|
};
|
||||||
|
|
||||||
return new SheetBuilder(SheetType.DualIndexed, allocate);
|
return new SheetBuilder(SheetType.DualIndexed, allocate);
|
||||||
@@ -195,6 +195,8 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public void RefreshBuffer()
|
public void RefreshBuffer()
|
||||||
{
|
{
|
||||||
|
if (vertexBuffer != null)
|
||||||
|
vertexBuffer.Dispose();
|
||||||
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer(totalVertexCount);
|
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer(totalVertexCount);
|
||||||
vertexBuffer.SetData(vertices.SelectMany(v => v).ToArray(), totalVertexCount);
|
vertexBuffer.SetData(vertices.SelectMany(v => v).ToArray(), totalVertexCount);
|
||||||
cachedVertexCount = totalVertexCount;
|
cachedVertexCount = totalVertexCount;
|
||||||
@@ -230,5 +232,12 @@ namespace OpenRA.Graphics
|
|||||||
{
|
{
|
||||||
sheetBuilder.Current.ReleaseBuffer();
|
sheetBuilder.Current.ReleaseBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (vertexBuffer != null)
|
||||||
|
vertexBuffer.Dispose();
|
||||||
|
sheetBuilder.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace OpenRA.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VoxelRenderer
|
public sealed class VoxelRenderer : IDisposable
|
||||||
{
|
{
|
||||||
Renderer renderer;
|
Renderer renderer;
|
||||||
IShader shader;
|
IShader shader;
|
||||||
@@ -68,7 +68,7 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
public void SetViewportParams(Size screen, float zoom, int2 scroll)
|
public void SetViewportParams(Size screen, float zoom, int2 scroll)
|
||||||
{
|
{
|
||||||
var a = 2f / Renderer.SheetSize;
|
var a = 2f / renderer.SheetSize;
|
||||||
var view = new float[]
|
var view = new float[]
|
||||||
{
|
{
|
||||||
a, 0, 0, 0,
|
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 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 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 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 shadowTranslateMtx = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, renderer.SheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0);
|
||||||
var correctionTransform = Util.MatrixMultiply(translateMtx, flipMtx);
|
var correctionTransform = Util.MatrixMultiply(translateMtx, flipMtx);
|
||||||
var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, shadowScaleFlipMtx);
|
var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, shadowScaleFlipMtx);
|
||||||
|
|
||||||
@@ -330,12 +330,24 @@ namespace OpenRA.Graphics
|
|||||||
return kv.Key;
|
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 framebuffer = renderer.Device.CreateFrameBuffer(size);
|
||||||
var sheet = new Sheet(framebuffer.Texture);
|
var sheet = new Sheet(framebuffer.Texture);
|
||||||
mappedBuffers.Add(sheet, framebuffer);
|
mappedBuffers.Add(sheet, framebuffer);
|
||||||
|
|
||||||
return sheet;
|
return sheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var kvp in mappedBuffers.Concat(unmappedBuffers))
|
||||||
|
{
|
||||||
|
kvp.Key.Dispose();
|
||||||
|
kvp.Value.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
mappedBuffers.Clear();
|
||||||
|
unmappedBuffers.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ namespace OpenRA.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class WorldRenderer
|
public sealed class WorldRenderer : IDisposable
|
||||||
{
|
{
|
||||||
public readonly World world;
|
public readonly World world;
|
||||||
public readonly Theater Theater;
|
public readonly Theater Theater;
|
||||||
@@ -251,5 +251,12 @@ namespace OpenRA.Graphics
|
|||||||
var ts = Game.modData.Manifest.TileSize;
|
var ts = Game.modData.Manifest.TileSize;
|
||||||
return new WPos(1024 * screenPx.X / ts.Width, 1024 * screenPx.Y / ts.Height, 0);
|
return new WPos(1024 * screenPx.X / ts.Width, 1024 * screenPx.Y / ts.Height, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
palette.Dispose();
|
||||||
|
Theater.Dispose();
|
||||||
|
terrainRenderer.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ using OpenRA.Primitives;
|
|||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
{
|
{
|
||||||
public class MapCache : IEnumerable<MapPreview>
|
public sealed class MapCache : IEnumerable<MapPreview>, IDisposable
|
||||||
{
|
{
|
||||||
public static readonly MapPreview UnknownMap = new MapPreview(null, null);
|
public static readonly MapPreview UnknownMap = new MapPreview(null, null);
|
||||||
readonly Cache<string, MapPreview> previews;
|
readonly Cache<string, MapPreview> previews;
|
||||||
@@ -163,7 +163,13 @@ namespace OpenRA
|
|||||||
foreach (var p in todo)
|
foreach (var p in todo)
|
||||||
{
|
{
|
||||||
// The rendering is thread safe because it only reads from the passed instances and writes to a new bitmap
|
// 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:
|
// Note: this is not generally thread-safe, but it works here because:
|
||||||
// (a) This worker is the only thread writing to this sheet
|
// (a) This worker is the only thread writing to this sheet
|
||||||
// (b) The main thread is the only thread reading this sheet
|
// (b) The main thread is the only thread reading this sheet
|
||||||
@@ -172,7 +178,15 @@ namespace OpenRA
|
|||||||
// the next render cycle.
|
// the next render cycle.
|
||||||
// (d) Any partially written bytes from the next minimap is in an
|
// (d) Any partially written bytes from the next minimap is in an
|
||||||
// unallocated area, and will be committed in the next cycle.
|
// 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.
|
// Yuck... But this helps the UI Jank when opening the map selector significantly.
|
||||||
Thread.Sleep(Environment.ProcessorCount == 1 ? 25 : 5);
|
Thread.Sleep(Environment.ProcessorCount == 1 ? 25 : 5);
|
||||||
@@ -226,5 +240,10 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
return GetEnumerator();
|
return GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
sheetBuilder.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ using OpenRA.Widgets;
|
|||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
{
|
{
|
||||||
public class ModData
|
public sealed class ModData : IDisposable
|
||||||
{
|
{
|
||||||
public readonly Manifest Manifest;
|
public readonly Manifest Manifest;
|
||||||
public readonly ObjectCreator ObjectCreator;
|
public readonly ObjectCreator ObjectCreator;
|
||||||
@@ -33,14 +33,17 @@ namespace OpenRA
|
|||||||
Lazy<Ruleset> defaultRules;
|
Lazy<Ruleset> defaultRules;
|
||||||
public Ruleset DefaultRules { get { return defaultRules.Value; } }
|
public Ruleset DefaultRules { get { return defaultRules.Value; } }
|
||||||
|
|
||||||
public ModData(string mod)
|
public ModData(string mod, bool useLoadScreen = false)
|
||||||
{
|
{
|
||||||
Languages = new string[0];
|
Languages = new string[0];
|
||||||
Manifest = new Manifest(mod);
|
Manifest = new Manifest(mod);
|
||||||
ObjectCreator = new ObjectCreator(Manifest);
|
ObjectCreator = new ObjectCreator(Manifest);
|
||||||
LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen.Value);
|
if (useLoadScreen)
|
||||||
LoadScreen.Init(Manifest, Manifest.LoadScreen.ToDictionary(my => my.Value));
|
{
|
||||||
LoadScreen.Display();
|
LoadScreen = ObjectCreator.CreateObject<ILoadScreen>(Manifest.LoadScreen.Value);
|
||||||
|
LoadScreen.Init(Manifest, Manifest.LoadScreen.ToDictionary(my => my.Value));
|
||||||
|
LoadScreen.Display();
|
||||||
|
}
|
||||||
WidgetLoader = new WidgetLoader(this);
|
WidgetLoader = new WidgetLoader(this);
|
||||||
RulesetCache = new RulesetCache(this);
|
RulesetCache = new RulesetCache(this);
|
||||||
RulesetCache.LoadingProgress += HandleLoadingProgress;
|
RulesetCache.LoadingProgress += HandleLoadingProgress;
|
||||||
@@ -82,8 +85,13 @@ namespace OpenRA
|
|||||||
// horribly when you use ModData in unexpected ways.
|
// horribly when you use ModData in unexpected ways.
|
||||||
ChromeMetrics.Initialize(Manifest.ChromeMetrics);
|
ChromeMetrics.Initialize(Manifest.ChromeMetrics);
|
||||||
ChromeProvider.Initialize(Manifest.Chrome);
|
ChromeProvider.Initialize(Manifest.Chrome);
|
||||||
|
|
||||||
|
if (VoxelLoader != null)
|
||||||
|
VoxelLoader.Dispose();
|
||||||
VoxelLoader = new VoxelLoader();
|
VoxelLoader = new VoxelLoader();
|
||||||
|
|
||||||
|
if (CursorProvider != null)
|
||||||
|
CursorProvider.Dispose();
|
||||||
CursorProvider = new CursorProvider(this);
|
CursorProvider = new CursorProvider(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +138,8 @@ namespace OpenRA
|
|||||||
|
|
||||||
public Map PrepareMap(string uid)
|
public Map PrepareMap(string uid)
|
||||||
{
|
{
|
||||||
LoadScreen.Display();
|
if (LoadScreen != null)
|
||||||
|
LoadScreen.Display();
|
||||||
|
|
||||||
if (MapCache[uid].Status != MapStatus.Available)
|
if (MapCache[uid].Status != MapStatus.Available)
|
||||||
throw new InvalidDataException("Invalid map uid: {0}".F(uid));
|
throw new InvalidDataException("Invalid map uid: {0}".F(uid));
|
||||||
@@ -157,9 +166,21 @@ namespace OpenRA
|
|||||||
|
|
||||||
return map;
|
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<string, string> info);
|
void Init(Manifest m, Dictionary<string, string> info);
|
||||||
void Display();
|
void Display();
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ namespace OpenRA.Lint
|
|||||||
FieldLoader.UnknownFieldAction = (s, f) => EmitError("FieldLoader: Missing field `{0}` on `{1}`".F(s, f.Name));
|
FieldLoader.UnknownFieldAction = (s, f) => EmitError("FieldLoader: Missing field `{0}` on `{1}`".F(s, f.Name));
|
||||||
|
|
||||||
AppDomain.CurrentDomain.AssemblyResolve += GlobalFileSystem.ResolveAssembly;
|
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);
|
Game.modData = new ModData(mod);
|
||||||
|
|
||||||
IEnumerable<Map> maps;
|
IEnumerable<Map> maps;
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ using OpenRA.Widgets;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Cnc
|
namespace OpenRA.Mods.Cnc
|
||||||
{
|
{
|
||||||
public class CncLoadScreen : ILoadScreen
|
public sealed class CncLoadScreen : ILoadScreen
|
||||||
{
|
{
|
||||||
Dictionary<string, string> loadInfo;
|
Dictionary<string, string> loadInfo;
|
||||||
Stopwatch loadTimer = Stopwatch.StartNew();
|
Stopwatch loadTimer = Stopwatch.StartNew();
|
||||||
|
Sheet sheet;
|
||||||
Sprite[] ss;
|
Sprite[] ss;
|
||||||
int loadTick;
|
int loadTick;
|
||||||
float2 nodPos, gdiPos, evaPos;
|
float2 nodPos, gdiPos, evaPos;
|
||||||
@@ -39,31 +40,31 @@ namespace OpenRA.Mods.Cnc
|
|||||||
r = Game.Renderer;
|
r = Game.Renderer;
|
||||||
if (r == null) return;
|
if (r == null) return;
|
||||||
|
|
||||||
var s = new Sheet(Platform.ResolvePath(loadInfo["Image"]));
|
sheet = new Sheet(Platform.ResolvePath(loadInfo["Image"]));
|
||||||
var res = r.Resolution;
|
var res = r.Resolution;
|
||||||
bounds = new Rectangle(0, 0, res.Width, res.Height);
|
bounds = new Rectangle(0, 0, res.Width, res.Height);
|
||||||
|
|
||||||
ss = new[]
|
ss = new[]
|
||||||
{
|
{
|
||||||
new Sprite(s, new Rectangle(161, 128, 62, 33), TextureChannel.Alpha),
|
new Sprite(sheet, new Rectangle(161, 128, 62, 33), TextureChannel.Alpha),
|
||||||
new Sprite(s, new Rectangle(161, 223, 62, 33), TextureChannel.Alpha),
|
new Sprite(sheet, new Rectangle(161, 223, 62, 33), TextureChannel.Alpha),
|
||||||
new Sprite(s, new Rectangle(128, 161, 33, 62), TextureChannel.Alpha),
|
new Sprite(sheet, new Rectangle(128, 161, 33, 62), TextureChannel.Alpha),
|
||||||
new Sprite(s, new Rectangle(223, 161, 33, 62), TextureChannel.Alpha),
|
new Sprite(sheet, new Rectangle(223, 161, 33, 62), TextureChannel.Alpha),
|
||||||
new Sprite(s, new Rectangle(128, 128, 33, 33), TextureChannel.Alpha),
|
new Sprite(sheet, new Rectangle(128, 128, 33, 33), TextureChannel.Alpha),
|
||||||
new Sprite(s, new Rectangle(223, 128, 33, 33), TextureChannel.Alpha),
|
new Sprite(sheet, new Rectangle(223, 128, 33, 33), TextureChannel.Alpha),
|
||||||
new Sprite(s, new Rectangle(128, 223, 33, 33), TextureChannel.Alpha),
|
new Sprite(sheet, new Rectangle(128, 223, 33, 33), TextureChannel.Alpha),
|
||||||
new Sprite(s, new Rectangle(223, 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);
|
nodLogo = new Sprite(sheet, new Rectangle(0, 256, 256, 256), TextureChannel.Alpha);
|
||||||
gdiLogo = new Sprite(s, new Rectangle(256, 256, 256, 256), TextureChannel.Alpha);
|
gdiLogo = new Sprite(sheet, new Rectangle(256, 256, 256, 256), TextureChannel.Alpha);
|
||||||
evaLogo = new Sprite(s, new Rectangle(256, 64, 128, 64), 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);
|
nodPos = new float2(bounds.Width / 2 - 384, bounds.Height / 2 - 128);
|
||||||
gdiPos = new float2(bounds.Width / 2 + 128, bounds.Height / 2 - 128);
|
gdiPos = new float2(bounds.Width / 2 + 128, bounds.Height / 2 - 128);
|
||||||
evaPos = new float2(bounds.Width - 43 - 128, 43);
|
evaPos = new float2(bounds.Width - 43 - 128, 43);
|
||||||
|
|
||||||
brightBlock = new Sprite(s, new Rectangle(320, 0, 16, 35), TextureChannel.Alpha);
|
brightBlock = new Sprite(sheet, new Rectangle(320, 0, 16, 35), TextureChannel.Alpha);
|
||||||
dimBlock = new Sprite(s, new Rectangle(336, 0, 16, 35), TextureChannel.Alpha);
|
dimBlock = new Sprite(sheet, new Rectangle(336, 0, 16, 35), TextureChannel.Alpha);
|
||||||
|
|
||||||
versionText = m.Mod.Version;
|
versionText = m.Mod.Version;
|
||||||
}
|
}
|
||||||
@@ -123,5 +124,11 @@ namespace OpenRA.Mods.Cnc
|
|||||||
{
|
{
|
||||||
Game.TestAndContinue();
|
Game.TestAndContinue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (sheet != null)
|
||||||
|
sheet.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,13 +18,14 @@ using OpenRA.Widgets;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.LoadScreens
|
namespace OpenRA.Mods.Common.LoadScreens
|
||||||
{
|
{
|
||||||
public class DefaultLoadScreen : ILoadScreen
|
public sealed class DefaultLoadScreen : ILoadScreen
|
||||||
{
|
{
|
||||||
Stopwatch lastUpdate = Stopwatch.StartNew();
|
Stopwatch lastUpdate = Stopwatch.StartNew();
|
||||||
Renderer r;
|
Renderer r;
|
||||||
|
|
||||||
Rectangle stripeRect;
|
Rectangle stripeRect;
|
||||||
float2 logoPos;
|
float2 logoPos;
|
||||||
|
Sheet sheet;
|
||||||
Sprite stripe, logo;
|
Sprite stripe, logo;
|
||||||
string[] messages;
|
string[] messages;
|
||||||
|
|
||||||
@@ -37,9 +38,9 @@ namespace OpenRA.Mods.Common.LoadScreens
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
messages = info["Text"].Split(',');
|
messages = info["Text"].Split(',');
|
||||||
var s = new Sheet(Platform.ResolvePath(info["Image"]));
|
sheet = new Sheet(Platform.ResolvePath(info["Image"]));
|
||||||
logo = new Sprite(s, new Rectangle(0, 0, 256, 256), TextureChannel.Alpha);
|
logo = new Sprite(sheet, new Rectangle(0, 0, 256, 256), TextureChannel.Alpha);
|
||||||
stripe = new Sprite(s, new Rectangle(256, 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);
|
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);
|
logoPos = new float2(r.Resolution.Width / 2 - 128, r.Resolution.Height / 2 - 128);
|
||||||
}
|
}
|
||||||
@@ -71,5 +72,11 @@ namespace OpenRA.Mods.Common.LoadScreens
|
|||||||
{
|
{
|
||||||
Game.TestAndContinue();
|
Game.TestAndContinue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (sheet != null)
|
||||||
|
sheet.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ using OpenRA.Widgets;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.LoadScreens
|
namespace OpenRA.Mods.Common.LoadScreens
|
||||||
{
|
{
|
||||||
public class ModChooserLoadScreen : ILoadScreen
|
public sealed class ModChooserLoadScreen : ILoadScreen
|
||||||
{
|
{
|
||||||
Sprite sprite;
|
Sprite sprite;
|
||||||
Rectangle bounds;
|
Rectangle bounds;
|
||||||
@@ -43,5 +43,11 @@ namespace OpenRA.Mods.Common.LoadScreens
|
|||||||
{
|
{
|
||||||
Ui.LoadWidget("MODCHOOSER", Ui.Root, new WidgetArgs());
|
Ui.LoadWidget("MODCHOOSER", Ui.Root, new WidgetArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (sprite != null)
|
||||||
|
sprite.sheet.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ using OpenRA.Widgets;
|
|||||||
|
|
||||||
namespace OpenRA.Mods.Common.LoadScreens
|
namespace OpenRA.Mods.Common.LoadScreens
|
||||||
{
|
{
|
||||||
public class NullLoadScreen : ILoadScreen
|
public sealed class NullLoadScreen : ILoadScreen
|
||||||
{
|
{
|
||||||
public void Init(Manifest m, Dictionary<string, string> info) { }
|
public void Init(Manifest m, Dictionary<string, string> info) { }
|
||||||
|
|
||||||
@@ -31,5 +31,9 @@ namespace OpenRA.Mods.Common.LoadScreens
|
|||||||
{
|
{
|
||||||
Ui.ResetAll();
|
Ui.ResetAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
Widget modList;
|
Widget modList;
|
||||||
ButtonWidget modTemplate;
|
ButtonWidget modTemplate;
|
||||||
ModMetadata[] allMods;
|
ModMetadata[] allMods;
|
||||||
|
readonly SheetBuilder sheetBuilder;
|
||||||
ModMetadata selectedMod;
|
ModMetadata selectedMod;
|
||||||
string selectedAuthor;
|
string selectedAuthor;
|
||||||
string selectedDescription;
|
string selectedDescription;
|
||||||
@@ -63,7 +64,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
var sheetBuilder = new SheetBuilder(SheetType.BGRA);
|
sheetBuilder = new SheetBuilder(SheetType.BGRA);
|
||||||
previews = new Dictionary<string, Sprite>();
|
previews = new Dictionary<string, Sprite>();
|
||||||
logos = new Dictionary<string, Sprite>();
|
logos = new Dictionary<string, Sprite>();
|
||||||
allMods = ModMetadata.AllMods.Values.Where(m => m.Id != "modchooser")
|
allMods = ModMetadata.AllMods.Values.Where(m => m.Id != "modchooser")
|
||||||
@@ -75,21 +76,17 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var preview = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "preview.png"));
|
using (var preview = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "preview.png")))
|
||||||
if (preview.Width != 296 || preview.Height != 196)
|
if (preview.Width == 296 && preview.Height == 196)
|
||||||
continue;
|
previews.Add(mod.Id, sheetBuilder.Add(preview));
|
||||||
|
|
||||||
previews.Add(mod.Id, sheetBuilder.Add(preview));
|
|
||||||
}
|
}
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var logo = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "logo.png"));
|
using (var logo = new Bitmap(Platform.ResolvePath(".", "mods", mod.Id, "logo.png")))
|
||||||
if (logo.Width != 96 || logo.Height != 96)
|
if (logo.Width == 96 && logo.Height == 96)
|
||||||
continue;
|
logos.Add(mod.Id, sheetBuilder.Add(logo));
|
||||||
|
|
||||||
logos.Add(mod.Id, sheetBuilder.Add(logo));
|
|
||||||
}
|
}
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
@@ -155,11 +152,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
modOffset = selectedIndex - 4;
|
modOffset = selectedIndex - 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LoadMod(ModMetadata mod)
|
void LoadMod(ModMetadata mod)
|
||||||
{
|
{
|
||||||
Game.RunAfterTick(() =>
|
Game.RunAfterTick(() =>
|
||||||
{
|
{
|
||||||
Ui.CloseWindow();
|
Ui.CloseWindow();
|
||||||
|
sheetBuilder.Dispose();
|
||||||
Game.InitializeMod(mod.Id, null);
|
Game.InitializeMod(mod.Id, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ namespace OpenRA.Renderer.Null
|
|||||||
public void Render(Action a) { }
|
public void Render(Action a) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NullTexture : ITexture
|
public sealed class NullTexture : ITexture
|
||||||
{
|
{
|
||||||
public TextureScaleFilter ScaleFilter { get { return TextureScaleFilter.Nearest; } set { } }
|
public TextureScaleFilter ScaleFilter { get { return TextureScaleFilter.Nearest; } set { } }
|
||||||
public void SetData(Bitmap bitmap) { }
|
public void SetData(Bitmap bitmap) { }
|
||||||
@@ -86,18 +86,21 @@ namespace OpenRA.Renderer.Null
|
|||||||
public void SetData(byte[] colors, int width, int height) { }
|
public void SetData(byte[] colors, int width, int height) { }
|
||||||
public byte[] GetData() { return new byte[0]; }
|
public byte[] GetData() { return new byte[0]; }
|
||||||
public Size Size { get { return new Size(0, 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 Bind() { }
|
||||||
public void Unbind() { }
|
public void Unbind() { }
|
||||||
public ITexture Texture { get { return new NullTexture(); } }
|
public ITexture Texture { get { return new NullTexture(); } }
|
||||||
|
public void Dispose() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
class NullVertexBuffer<T> : IVertexBuffer<T>
|
sealed class NullVertexBuffer<T> : IVertexBuffer<T>
|
||||||
{
|
{
|
||||||
public void Bind() { }
|
public void Bind() { }
|
||||||
public void SetData(T[] vertices, int length) { }
|
public void SetData(T[] vertices, int length) { }
|
||||||
|
public void Dispose() { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,12 @@ using OpenTK.Graphics.OpenGL;
|
|||||||
|
|
||||||
namespace OpenRA.Renderer.Sdl2
|
namespace OpenRA.Renderer.Sdl2
|
||||||
{
|
{
|
||||||
public class FrameBuffer : IFrameBuffer
|
public sealed class FrameBuffer : IFrameBuffer
|
||||||
{
|
{
|
||||||
Texture texture;
|
Texture texture;
|
||||||
Size size;
|
Size size;
|
||||||
int framebuffer, depth;
|
int framebuffer, depth;
|
||||||
|
bool disposed;
|
||||||
|
|
||||||
public FrameBuffer(Size size)
|
public FrameBuffer(Size size)
|
||||||
{
|
{
|
||||||
@@ -81,16 +82,6 @@ namespace OpenRA.Renderer.Sdl2
|
|||||||
return v;
|
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];
|
int[] cv = new int[4];
|
||||||
public void Bind()
|
public void Bind()
|
||||||
{
|
{
|
||||||
@@ -120,5 +111,29 @@ namespace OpenRA.Renderer.Sdl2
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ITexture Texture { get { return texture; } }
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ using OpenTK.Graphics.OpenGL;
|
|||||||
|
|
||||||
namespace OpenRA.Renderer.Sdl2
|
namespace OpenRA.Renderer.Sdl2
|
||||||
{
|
{
|
||||||
public class Texture : ITexture
|
public sealed class Texture : ITexture
|
||||||
{
|
{
|
||||||
int texture;
|
int texture;
|
||||||
TextureScaleFilter scaleFilter;
|
TextureScaleFilter scaleFilter;
|
||||||
@@ -26,6 +26,8 @@ namespace OpenRA.Renderer.Sdl2
|
|||||||
|
|
||||||
public Size Size { get { return size; } }
|
public Size Size { get { return size; } }
|
||||||
|
|
||||||
|
bool disposed;
|
||||||
|
|
||||||
public TextureScaleFilter ScaleFilter
|
public TextureScaleFilter ScaleFilter
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -55,9 +57,6 @@ namespace OpenRA.Renderer.Sdl2
|
|||||||
SetData(bitmap);
|
SetData(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinalizeInner() { GL.DeleteTextures(1, ref texture); }
|
|
||||||
~Texture() { Game.RunAfterTick(FinalizeInner); }
|
|
||||||
|
|
||||||
void PrepareTexture()
|
void PrepareTexture()
|
||||||
{
|
{
|
||||||
ErrorHandler.CheckGlError();
|
ErrorHandler.CheckGlError();
|
||||||
@@ -180,5 +179,24 @@ namespace OpenRA.Renderer.Sdl2
|
|||||||
0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
|
0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
|
||||||
ErrorHandler.CheckGlError();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ using OpenTK.Graphics.OpenGL;
|
|||||||
|
|
||||||
namespace OpenRA.Renderer.Sdl2
|
namespace OpenRA.Renderer.Sdl2
|
||||||
{
|
{
|
||||||
public class VertexBuffer<T> : IVertexBuffer<T>
|
public sealed class VertexBuffer<T> : IVertexBuffer<T>
|
||||||
where T : struct
|
where T : struct
|
||||||
{
|
{
|
||||||
static readonly int VertexSize = Marshal.SizeOf(typeof(T));
|
static readonly int VertexSize = Marshal.SizeOf(typeof(T));
|
||||||
int buffer;
|
int buffer;
|
||||||
|
bool disposed;
|
||||||
|
|
||||||
public VertexBuffer(int size)
|
public VertexBuffer(int size)
|
||||||
{
|
{
|
||||||
@@ -52,7 +53,23 @@ namespace OpenRA.Renderer.Sdl2
|
|||||||
ErrorHandler.CheckGlError();
|
ErrorHandler.CheckGlError();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinalizeInner() { GL.DeleteBuffers(1, ref buffer); }
|
~VertexBuffer()
|
||||||
~VertexBuffer() { Game.RunAfterTick(FinalizeInner); }
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user