diff --git a/.vscode/launch.json b/.vscode/launch.json index 61bfa58..d70b356 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,7 @@ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md "version": "0.2.0", "configurations": [ + { "name": ".NET Core Launch (console)", "type": "coreclr", diff --git a/RecrownedGTK.Tests/assets/texture_test_2048x2048.png b/RecrownedGTK.Tests/assets/texture_test_2048x2048.png new file mode 100644 index 0000000..2aeb6d8 Binary files /dev/null and b/RecrownedGTK.Tests/assets/texture_test_2048x2048.png differ diff --git a/RecrownedGTK/AssetsSystem/AssetLoader.cs b/RecrownedGTK/AssetsSystem/AssetLoader.cs index 491c7fc..21b6279 100644 --- a/RecrownedGTK/AssetsSystem/AssetLoader.cs +++ b/RecrownedGTK/AssetsSystem/AssetLoader.cs @@ -9,11 +9,11 @@ namespace RecrownedGTK.AssetsSystem { public AssetLoader() { typeLoaders = new Dictionary(); } - public void AddLoaderResolver(Type type, ILoader loader) { - if (typeLoaders.ContainsKey(type)) { - throw new InvalidOperationException(String.Format("The type {0} already exists in this resolver.", type)); + public void AddLoaderResolver(ILoader loader) { + if (typeLoaders.ContainsKey(loader.resultingType)) { + throw new InvalidOperationException(String.Format("The type {0} already exists in this resolver.", loader.resultingType)); } - typeLoaders.Add(type, loader); + typeLoaders.Add(loader.resultingType, loader); } public void RemoveLoaderResolver(Type type) { if (!typeLoaders.ContainsKey(type)) { @@ -21,6 +21,11 @@ namespace RecrownedGTK.AssetsSystem { } typeLoaders.Remove(type); } + + public void RemoveLoaderResolver(ILoader loader) { + RemoveLoaderResolver(loader.resultingType); + } + public IInfo Load(string path, Type type) { if (!typeLoaders.ContainsKey(type)) { throw new InvalidOperationException(String.Format("The type {0} doesn't exist in this resolver.", type)); diff --git a/RecrownedGTK/AssetsSystem/AssetManager.cs b/RecrownedGTK/AssetsSystem/AssetManager.cs index 45b7bca..df6ffdf 100644 --- a/RecrownedGTK/AssetsSystem/AssetManager.cs +++ b/RecrownedGTK/AssetsSystem/AssetManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Threading; @@ -11,16 +12,10 @@ namespace RecrownedGTK.AssetsSystem /// public class AssetManager { - private AssetLoader assetLoader; - readonly Queue queue; - Dictionary assets; - /// - /// Path modifiers to change the path in which the content manager looks to load a file. Used for better organizing things while not needing to type entire path. - /// + public readonly AssetLoader assetLoader; + readonly Queue queue; + ConcurrentDictionary assets; private readonly Dictionary contentPathModifier; - /// - /// Used when no path modifier is defined for that specific type. - /// public IAssetPathResolver normalPathModifier = new NormalAssetPathResolver(); volatile float progress; volatile bool running; @@ -36,13 +31,21 @@ namespace RecrownedGTK.AssetsSystem public float Progress { get { return progress; } } /// - /// Wraps the . + /// Creates an asset manager with a default asset loader. /// - /// The manager to wrap. - public AssetManager() + public AssetManager() : this(new AssetLoader()) { - assets = new Dictionary(); - queue = new Queue(); + } + + /// + /// A manager for the given asset loader. + /// The manager will asynchronously load assets and store them. + /// + /// The asset loader to use for loading. + public AssetManager(AssetLoader assetLoader) { + this.assetLoader = assetLoader; + assets = new ConcurrentDictionary(); + queue = new Queue(); contentPathModifier = new Dictionary(); } @@ -80,8 +83,7 @@ namespace RecrownedGTK.AssetsSystem } path = handler.Modify(assetName); } - assets.Add(assetName, assetLoader.Load(path, type).CreateUseable()); - + assets.TryAdd(assetName, assetLoader.Load(path, type).CreateUseable()); } /// @@ -110,7 +112,7 @@ namespace RecrownedGTK.AssetsSystem { if (!assets.ContainsKey(assetName)) { - queue.Enqueue(new ContentData(assetName, typeof(T), usePathModifier)); + queue.Enqueue(new AssetOutline(assetName, typeof(T), usePathModifier)); Debug.WriteLine("Queued asset: " + assetName); Update(); } @@ -145,7 +147,7 @@ namespace RecrownedGTK.AssetsSystem { lock (queue) { - ContentData content = queue.Dequeue(); + AssetOutline content = queue.Dequeue(); Load(content.assetName, content.type, content.usePathModifier); tasksCompleted++; progress = (float)tasksCompleted / totalTasks; @@ -169,7 +171,8 @@ namespace RecrownedGTK.AssetsSystem { ((IDisposable)assets[name]).Dispose(); } - assets.Remove(name); + IDisposable disposable = null; + assets.TryRemove(name, out disposable); } } } @@ -201,13 +204,13 @@ namespace RecrownedGTK.AssetsSystem Debug.WriteLine("Unloaded all assets."); } } - private struct ContentData + private struct AssetOutline { internal Type type; internal string assetName; internal bool usePathModifier; - public ContentData(string assetName, Type type, bool usePathModifier) + public AssetOutline(string assetName, Type type, bool usePathModifier) { this.type = type; this.assetName = assetName; diff --git a/RecrownedGTK/AssetsSystem/Information/IInfo.cs b/RecrownedGTK/AssetsSystem/Information/IInfo.cs index 31d20fc..7122170 100644 --- a/RecrownedGTK/AssetsSystem/Information/IInfo.cs +++ b/RecrownedGTK/AssetsSystem/Information/IInfo.cs @@ -1,9 +1,12 @@ using System; namespace RecrownedGTK.AssetsSystem.Information { + /// + /// Describes a serializable datatype. + /// Meant for use as a part of the asset pipeline. + /// public interface IInfo { - Type type {get;} IDisposable CreateUseable(); } } \ No newline at end of file diff --git a/RecrownedGTK/AssetsSystem/Information/IInformation.cs b/RecrownedGTK/AssetsSystem/Information/IInformation.cs new file mode 100644 index 0000000..57b2cf5 --- /dev/null +++ b/RecrownedGTK/AssetsSystem/Information/IInformation.cs @@ -0,0 +1,12 @@ +using System; + +namespace RecrownedGTK.AssetsSystem.Information { + /// + /// An interface that describes an information class. + /// An information class is class that can produce a useable asset object. + /// In the asset pipeline, this is the second step, after loading the asset data. + /// + public interface IInformation + { + } +} \ No newline at end of file diff --git a/RecrownedGTK/AssetsSystem/Information/TextureInfo.cs b/RecrownedGTK/AssetsSystem/Information/TextureInfo.cs index 46c155f..0690ae5 100644 --- a/RecrownedGTK/AssetsSystem/Information/TextureInfo.cs +++ b/RecrownedGTK/AssetsSystem/Information/TextureInfo.cs @@ -5,7 +5,7 @@ namespace RecrownedGTK.AssetsSystem.Information { public struct TextureInfo : IInfo { public readonly byte[] textureData; int width, height; - public Type type => typeof(TextureData); + public Type resultingType => typeof(TextureData); public TextureInfo(int width, int height, byte[] textureData) { this.width = width; this.height = height; diff --git a/RecrownedGTK/AssetsSystem/Loaders/ILoader.cs b/RecrownedGTK/AssetsSystem/Loaders/ILoader.cs index a22cd01..351085b 100644 --- a/RecrownedGTK/AssetsSystem/Loaders/ILoader.cs +++ b/RecrownedGTK/AssetsSystem/Loaders/ILoader.cs @@ -3,6 +3,7 @@ using RecrownedGTK.AssetsSystem.Information; namespace RecrownedGTK.AssetsSystem.Loaders { public interface ILoader { + Type resultingType {get;} IInfo load(string path); } } \ No newline at end of file diff --git a/RecrownedGTK/AssetsSystem/Loaders/TextureLoader.cs b/RecrownedGTK/AssetsSystem/Loaders/TextureLoader.cs index d07a9ea..e6b5c46 100644 --- a/RecrownedGTK/AssetsSystem/Loaders/TextureLoader.cs +++ b/RecrownedGTK/AssetsSystem/Loaders/TextureLoader.cs @@ -7,6 +7,8 @@ using RecrownedGTK.Graphics; namespace RecrownedGTK.AssetsSystem.Loaders { public class TextureLoader : ILoader { + public Type resultingType => typeof(TextureData); + public IInfo load(string path) { int width; diff --git a/RecrownedGTK/Game/GameEngine.cs b/RecrownedGTK/Game/GameEngine.cs index cc3714f..37ed743 100644 --- a/RecrownedGTK/Game/GameEngine.cs +++ b/RecrownedGTK/Game/GameEngine.cs @@ -7,12 +7,8 @@ using RecrownedGTK.AssetsSystem; namespace RecrownedGTK.Game { public sealed class GameEngine : GameWindow { private IState state; - public readonly Preferences preferences; - public readonly AssetManager assets; - public GameEngine(IState initialState, Preferences preferences, AssetManager assets) : base() { + public GameEngine(IState initialState) : base() { this.state = initialState; - this.assets = assets; - this.preferences = preferences; } protected override void OnUpdateFrame(FrameEventArgs e) { @@ -34,7 +30,7 @@ namespace RecrownedGTK.Game { } protected override void OnClosed(EventArgs e) { - if (state.CloseRequested()) { + if (!state.CloseRequested()) { ((CancelEventArgs) e).Cancel = true; } base.OnClosed(e); diff --git a/RecrownedGTK/Game/IState.cs b/RecrownedGTK/Game/IState.cs index 8c649d2..0204416 100644 --- a/RecrownedGTK/Game/IState.cs +++ b/RecrownedGTK/Game/IState.cs @@ -3,13 +3,47 @@ using OpenTK.Input; namespace RecrownedGTK.Game { public interface IState { + /// + /// Called when this state is going to be shown. + /// + /// The instance of the game manager that is requesting this. + /// True of it's ready to be displayed, false otherwise. bool Shown(GameEngine gameManager); + + /// + /// Called on updating the state. + /// + /// The time that has passed since the last update in seconds. void Update(double time); + /// + /// Called for rendering things. + /// + /// The time that has elapsed since last rendering in seconds. void Render(double time); + + /// + /// Called when this state is no longer being displayed. + /// void Hidden(); + + /// + /// Called when the game window size is updated. + /// + /// The new width + /// The new height void WindowSizeUpdate(int width, int height); + + /// + /// When the game is being requested to be closed. + /// + /// True if closing is acceptable, or false otherwise. bool CloseRequested(); + + /// + /// Called every update in the case that there should be a state change. + /// + /// Another state if ready to change states, or null if not. IState ChangeState(); }