Skip to content

Commit 7317969

Browse files
committed
Add asset pipeline and Shader importer
1 parent 544a713 commit 7317969

File tree

9 files changed

+148
-16
lines changed

9 files changed

+148
-16
lines changed

Engine/Assets/AssetDataLoader.cs

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Reflection;
6+
using JetBrains.Annotations;
7+
using LiteGuard;
8+
9+
namespace Engine.Assets
10+
{
11+
public class AssetDataLoader
12+
{
13+
private readonly Assembly _gameAssembly;
14+
private readonly Dictionary<AssetType, string> _assetDirectoryPaths;
15+
private readonly string[] _assetFilenames;
16+
17+
public AssetDataLoader(Assembly gameAssembly, Dictionary<AssetType, string> assetDirectoryPaths)
18+
{
19+
_gameAssembly = gameAssembly;
20+
_assetDirectoryPaths = assetDirectoryPaths;
21+
_assetFilenames = gameAssembly.GetManifestResourceNames();
22+
}
23+
24+
/// <summary>
25+
/// Load an asset from the asset library given a <paramref name="type"/> and a <paramref name="filename"/>.
26+
/// </summary>
27+
/// <param name="type"></param>
28+
/// <param name="filename"></param>
29+
/// <returns><see cref="Stream"/> of loaded asset's data</returns>
30+
/// <exception cref="ArgumentNullException"><paramref name="filename"/> is null</exception>
31+
/// <exception cref="InvalidOperationException">Asset type doesn't exist in asset directory dictionary</exception>
32+
/// <exception cref="FileNotFoundException">Given <paramref name="filename"/> doesn't exist in asset library</exception>
33+
public Stream Load(AssetType type, [NotNull] string filename)
34+
{
35+
Guard.AgainstNullArgument(nameof(filename), filename);
36+
if (!_assetDirectoryPaths.ContainsKey(type))
37+
{
38+
throw new InvalidOperationException($"{type} does not exist in the asset directory path dictionary");
39+
}
40+
41+
var assetFilePath = $"{_assetDirectoryPaths[type]}.{filename}";
42+
43+
if (!_assetFilenames.Contains(assetFilePath))
44+
{
45+
throw new FileNotFoundException($"{filename} not found in asset library");
46+
}
47+
48+
return _gameAssembly.GetManifestResourceStream(assetFilePath);
49+
}
50+
}
51+
}

Engine/Assets/AssetType.cs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Engine.Assets
2+
{
3+
public enum AssetType
4+
{
5+
Model,
6+
Shader
7+
}
8+
}

Engine/Assets/IAssetImporter.cs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.IO;
2+
3+
namespace Engine.Assets
4+
{
5+
public interface IAssetImporter<out T>
6+
{
7+
T Import(Stream assetData);
8+
}
9+
}

Engine/Assets/ShaderImporter.cs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System.IO;
2+
3+
namespace Engine.Assets
4+
{
5+
public class ShaderImporter : IAssetImporter<byte[]>
6+
{
7+
public static ShaderImporter Instance = new ShaderImporter();
8+
9+
public byte[] Import(Stream assetData)
10+
{
11+
using (var stream = new MemoryStream())
12+
{
13+
// TODO: User CopyToAsync when we need "Loading..." screen
14+
assetData.CopyTo(stream);
15+
return stream.ToArray();
16+
}
17+
}
18+
}
19+
}

Engine/Components/IAsset.cs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using Engine.Assets;
2+
3+
namespace Engine.Components
4+
{
5+
public interface IAsset
6+
{
7+
void LoadAssets(AssetDataLoader assetDataLoader);
8+
}
9+
}

Engine/Components/Material.cs

+17-15
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
1+
using Engine.Assets;
12
using Engine.ECS;
23
using Veldrid;
4+
using Veldrid.SPIRV;
35

46
namespace Engine.Components
57
{
6-
public class Material : Component, IResource
8+
public class Material : Component, IResource, IAsset
79
{
8-
private readonly byte[] _shaderSource;
9-
private Shader _vertexShader;
10-
private Shader _fragmentShader;
10+
private ResourceFactory _factory;
1111

1212
public Material(
1313
string name,
14-
byte[] shaderSource,
1514
string shaderFilename,
1615
BlendStateDescription blendState,
1716
DepthStencilStateDescription depthStencilState,
1817
PolygonFillMode fillMode = PolygonFillMode.Solid,
1918
bool depthClipEnabled = true)
2019
: base(name)
2120
{
22-
_shaderSource = shaderSource;
2321
ShaderFilename = shaderFilename;
2422
DepthStencilState = depthStencilState;
2523
FillMode = fillMode;
@@ -31,28 +29,32 @@ public Material(
3129
depthTestEnabled: true, depthWriteEnabled: true, comparisonKind: ComparisonKind.LessEqual);
3230

3331
public string ShaderFilename { get; }
34-
public Shader[] Shaders => new Shader[] {_vertexShader, _fragmentShader};
32+
public Shader[] Shaders { get; private set; }
3533
public DepthStencilStateDescription DepthStencilState { get; }
3634
public PolygonFillMode FillMode { get; }
3735
public bool DepthClipEnabled { get; }
3836
public BlendStateDescription BlendState { get; }
3937

4038
public void Initialize(ResourceFactory factory, GraphicsDevice device)
4139
{
42-
// Compile shaders
43-
_vertexShader = CompileShader(factory, ShaderStages.Vertex);
44-
_fragmentShader = CompileShader(factory, ShaderStages.Fragment);
40+
_factory = factory;
4541
}
4642

47-
public void Dispose()
43+
public void LoadAssets(AssetDataLoader assetDataLoader)
4844
{
49-
throw new System.NotImplementedException();
45+
var shaderSource = ShaderImporter.Instance.Import(assetDataLoader.Load(AssetType.Shader, ShaderFilename));
46+
// Compile shaders
47+
Shaders = _factory.CreateFromSpirv(
48+
new ShaderDescription(ShaderStages.Vertex, shaderSource, "VS"),
49+
new ShaderDescription(ShaderStages.Fragment, shaderSource, "FS"));
5050
}
5151

52-
private Shader CompileShader(ResourceFactory factory, ShaderStages stage)
52+
public void Dispose()
5353
{
54-
var entryPoint = stage == ShaderStages.Vertex ? "VS" : "FS";
55-
return factory.CreateShader(new ShaderDescription(stage, _shaderSource, entryPoint));
54+
foreach (var shader in Shaders)
55+
{
56+
shader.Dispose();
57+
}
5658
}
5759
}
5860
}

Engine/Game.cs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4-
using Engine.Components;
4+
using System.Reflection;
5+
using Engine.Assets;
56
using Engine.ECS;
67
using Engine.Input;
78
using Engine.Systems;
@@ -11,13 +12,16 @@ namespace Engine
1112
{
1213
public abstract class Game : IDisposable
1314
{
15+
private readonly AssetDataLoader _assetDataLoader;
1416
private readonly FrameTimeAverager _frameTimeAverager = new FrameTimeAverager(0.666);
1517

1618
protected Game()
1719
{
1820
World = new World();
1921
LimitFrameRate = true;
2022
DesiredFrameLengthSeconds = 1.0 / 60.0;
23+
24+
_assetDataLoader = new AssetDataLoader(Assembly.GetCallingAssembly(), AssetDirectoryPaths);
2125
}
2226

2327
private GameTime _gameTime;
@@ -35,6 +39,8 @@ protected Game()
3539
public ResourceFactory ResourceFactory => GraphicsDevice.ResourceFactory;
3640
public Framebuffer Framebuffer => GraphicsDevice.SwapchainFramebuffer;
3741

42+
public Dictionary<AssetType, string> AssetDirectoryPaths { get; } = new Dictionary<AssetType, string>();
43+
3844
private TimeSpan TotalElapsedTime => _gameTime?.TotalGameTime ?? TimeSpan.Zero;
3945

4046
protected abstract GraphicsDevice CreateGraphicsDevice();
@@ -45,6 +51,7 @@ private void InternalInitialize()
4551
{
4652
// Initialize all world resources
4753
new ResourceInitializer(World, ResourceFactory, GraphicsDevice).Operate();
54+
new ComponentAssetLoader(World, _assetDataLoader).Operate();
4855
}
4956

5057
public void Run()
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Engine.Assets;
2+
using Engine.Components;
3+
using Engine.ECS;
4+
5+
namespace Engine.Systems
6+
{
7+
public class ComponentAssetLoader : System<IAsset>
8+
{
9+
private readonly AssetDataLoader _assetDataLoader;
10+
11+
public ComponentAssetLoader(World world, AssetDataLoader assetDataLoader) : base(world)
12+
{
13+
_assetDataLoader = assetDataLoader;
14+
}
15+
16+
public override void Operate()
17+
{
18+
foreach (var asset in OperableComponents)
19+
{
20+
asset.LoadAssets(_assetDataLoader);
21+
}
22+
}
23+
}
24+
}

Game/Game.cs

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Runtime.InteropServices;
44
using System.Text;
55
using Engine;
6+
using Engine.Assets;
67
using Engine.Components;
78
using Engine.Entities;
89
using Veldrid;
@@ -54,6 +55,8 @@ protected override GraphicsDevice CreateGraphicsDevice()
5455

5556
protected override void Initialize()
5657
{
58+
AssetDirectoryPaths.Add(AssetType.Shader, "Game.Content.Shaders");
59+
5760
World.Add(EntityFactory.Create<Camera>());
5861

5962
_commandList = ResourceFactory.CreateCommandList();

0 commit comments

Comments
 (0)