-
-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* start implementing node graph * update Sekai * remove previous rendering impl * add coordinate providing interfaces * add `Node` * add `Effect` * add material-related interfaces * add `ShaderMaterial` * add `UnlitMaterial` * add `Behavior` * add `Renderable` * add `RenderGroup`s * add `RenderObject`s * add `RenderData` * add `RenderQueue` and `RenderContext` * add `RenderTarget` * add `Renderer` * add `SortedFilteredCollection<T>` * add `Drawable` * add projectors * add `World` * add `Window` node * add executable * ensure material resources are applied * remove `Renderable` * cleanup pass * add `ServiceLocator` * add `Node.Services` * make `Window` override `Services` * refactor `World` * start implementing content manager * add `ContentManager` and `IContentLoader` * add shader and texture loaders * include stbisharp * load content manager * add more constructors to `UnlitMaterial` --------- Co-authored-by: Ayase Minori <[email protected]>
- Loading branch information
Showing
7 changed files
with
266 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// Copyright (c) Cosyne | ||
// Licensed under GPL 3.0 with SDK Exception. See LICENSE for details. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.IO; | ||
using Sekai.Storages; | ||
|
||
namespace Vignette.Content; | ||
|
||
/// <summary> | ||
/// Manages content. | ||
/// </summary> | ||
public sealed class ContentManager | ||
{ | ||
private readonly Storage storage; | ||
private readonly HashSet<string> extensions = new(); | ||
private readonly HashSet<IContentLoader> loaders = new(); | ||
private readonly Dictionary<ContentKey, WeakReference> content = new(); | ||
|
||
internal ContentManager(Storage storage) | ||
{ | ||
this.storage = storage; | ||
} | ||
|
||
/// <summary> | ||
/// Reads a file from <see cref="Storage"/> and loads it as <typeparamref name="T"/>. | ||
/// </summary> | ||
/// <typeparam name="T">The type of content to load.</typeparam> | ||
/// <param name="path">The path to the content.</param> | ||
/// <returns>The loaded content.</returns> | ||
/// <exception cref="ArgumentException">Thrown when invalid path has been passed.</exception> | ||
public T Load<T>([StringSyntax(StringSyntaxAttribute.Uri)] string path) | ||
where T : class | ||
{ | ||
string ext = Path.GetExtension(path); | ||
|
||
if (string.IsNullOrEmpty(ext)) | ||
{ | ||
throw new ArgumentException($"Failed to determine file extension.", nameof(path)); | ||
} | ||
|
||
if (!extensions.Contains(ext)) | ||
{ | ||
throw new ArgumentException($"Cannot load unsupported file extension \"{ext}\"."); | ||
} | ||
|
||
var key = new ContentKey(typeof(T), path); | ||
|
||
if (!content.TryGetValue(key, out var weak)) | ||
{ | ||
weak = new WeakReference(null); | ||
content.Add(key, weak); | ||
} | ||
|
||
if (!weak.IsAlive) | ||
{ | ||
weak.Target = Load<T>(storage.Open(path, FileMode.Open, FileAccess.Read)); | ||
} | ||
|
||
return (T)weak.Target!; | ||
} | ||
|
||
/// <summary> | ||
/// Loads a <see cref="Stream"/> as <typeparamref name="T"/>. | ||
/// </summary> | ||
/// <typeparam name="T">The type of content to load.</typeparam> | ||
/// <param name="stream">The stream to be read.</param> | ||
/// <returns>The loaded content.</returns> | ||
/// <exception cref="InvalidOperationException">Thrown when the stream can't be read.</exception> | ||
public T Load<T>(Stream stream) | ||
where T : class | ||
{ | ||
Span<byte> buffer = stackalloc byte[(int)stream.Length]; | ||
|
||
if (stream.Read(buffer) <= 0) | ||
{ | ||
throw new InvalidOperationException("Failed to read stream."); | ||
} | ||
|
||
return Load<T>((ReadOnlySpan<byte>)buffer); | ||
} | ||
|
||
/// <summary> | ||
/// Loads a <see cref="byte[]"/> as <typeparamref name="T"/>. | ||
/// </summary> | ||
/// <typeparam name="T">The type of content to load.</typeparam> | ||
/// <param name="bytes">The byte data to be read.</param> | ||
/// <returns>The loaded content.</returns> | ||
public T Load<T>(byte[] bytes) | ||
where T : class | ||
{ | ||
return Load<T>(bytes); | ||
} | ||
|
||
/// <summary> | ||
/// Loads a <see cref="ReadOnlySpan{byte}"/> as <typeparamref name="T"/>. | ||
/// </summary> | ||
/// <typeparam name="T">The type of content to load.</typeparam> | ||
/// <param name="bytes">The byte data to be read.</param> | ||
/// <returns>The loaded content.</returns> | ||
/// <exception cref="InvalidOperationException">Thrown when no loader was able to load the content.</exception> | ||
public T Load<T>(ReadOnlySpan<byte> bytes) | ||
where T : class | ||
{ | ||
var result = default(T); | ||
|
||
foreach (var loader in loaders) | ||
{ | ||
if (loader is not IContentLoader<T> typedLoader) | ||
{ | ||
continue; | ||
} | ||
|
||
try | ||
{ | ||
result = typedLoader.Load(bytes); | ||
break; | ||
} | ||
catch | ||
{ | ||
} | ||
} | ||
|
||
if (result is null) | ||
{ | ||
throw new InvalidOperationException("Failed to load content."); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
/// <summary> | ||
/// Adds a content loader to the content manager. | ||
/// </summary> | ||
/// <param name="loader">The content loader to add.</param> | ||
/// <param name="extensions">The file extensions supported by this loader.</param> | ||
/// <exception cref="InvalidOperationException">Thrown when </exception> | ||
internal void Add(IContentLoader loader, params string[] extensions) | ||
{ | ||
foreach (string extension in extensions) | ||
{ | ||
string ext = extension.StartsWith(ext_separator) ? extension : ext_separator + extension; | ||
this.loaders.Add(loader); | ||
this.extensions.Add(ext); | ||
} | ||
} | ||
|
||
private const char ext_separator = '.'; | ||
|
||
private readonly record struct ContentKey(Type Type, string Path); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Copyright (c) Cosyne | ||
// Licensed under GPL 3.0 with SDK Exception. See LICENSE for details. | ||
|
||
using System; | ||
|
||
namespace Vignette.Content; | ||
|
||
/// <summary> | ||
/// Defines a mechanism for loading content. | ||
/// </summary> | ||
public interface IContentLoader | ||
{ | ||
} | ||
|
||
/// <summary> | ||
/// Defines a mechanism for loading <typeparamref name="T"/>. | ||
/// </summary> | ||
/// <typeparam name="T">The type of content it loads.</typeparam> | ||
public interface IContentLoader<T> : IContentLoader | ||
where T : class | ||
{ | ||
/// <summary> | ||
/// Loads a <see cref="ReadOnlySpan{byte}"/> as <typeparamref name="T"/>. | ||
/// </summary> | ||
/// <param name="bytes">The byte data to be read.</param> | ||
/// <returns>The loaded content.</returns> | ||
T Load(ReadOnlySpan<byte> bytes); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright (c) Cosyne | ||
// Licensed under GPL 3.0 with SDK Exception. See LICENSE for details. | ||
|
||
using System; | ||
using System.Text; | ||
using Vignette.Graphics; | ||
|
||
namespace Vignette.Content; | ||
|
||
internal sealed class ShaderLoader : IContentLoader<ShaderMaterial> | ||
{ | ||
public ShaderMaterial Load(ReadOnlySpan<byte> bytes) | ||
{ | ||
return ShaderMaterial.Create(Encoding.UTF8.GetString(bytes)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (c) Cosyne | ||
// Licensed under GPL 3.0 with SDK Exception. See LICENSE for details. | ||
|
||
using System; | ||
using Sekai.Graphics; | ||
using StbiSharp; | ||
|
||
namespace Vignette.Content; | ||
|
||
internal sealed class TextureLoader : IContentLoader<Texture> | ||
{ | ||
private readonly GraphicsDevice device; | ||
|
||
public TextureLoader(GraphicsDevice device) | ||
{ | ||
this.device = device; | ||
} | ||
|
||
public Texture Load(ReadOnlySpan<byte> bytes) | ||
{ | ||
var image = Stbi.LoadFromMemory(bytes, 4); | ||
|
||
var texture = device.CreateTexture(new TextureDescription | ||
( | ||
image.Width, | ||
image.Height, | ||
PixelFormat.R8G8B8A8_UNorm, | ||
1, | ||
1, | ||
TextureUsage.Resource | ||
)); | ||
|
||
texture.SetData(image.Data, 0, 0, 0, 0, 0, image.Width, image.Height, 0); | ||
|
||
return texture; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters