Skip to content

Commit

Permalink
Add SimplePipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
MrScautHD committed Sep 1, 2024
1 parent df4d762 commit f3dbff3
Show file tree
Hide file tree
Showing 11 changed files with 278 additions and 163 deletions.
2 changes: 1 addition & 1 deletion src/Bliss/CSharp/Camera/Dim3/Cam3D.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.Numerics;
using Bliss.CSharp.Rendering;
using Bliss.CSharp.Graphics.Rendering;
using Bliss.CSharp.Windowing;
using Vortice.Mathematics;
using Viewport = Veldrid.Viewport;
Expand Down
23 changes: 19 additions & 4 deletions src/Bliss/CSharp/Effects/Effect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,35 @@

namespace Bliss.CSharp.Effects;

// TODO: Add Load from Stream method, in generel by all things like by the model too.
public class Effect : Disposable {

public readonly (Shader, Shader) Shader;
public readonly VertexLayoutDescription VertexLayout;

public Effect(ResourceFactory resourceFactory, string vertPath, string fragPath) {
/// <summary>
/// Initializes a new instance of the <see cref="Effect"/> class by loading and compiling shaders and setting up the vertex layout.
/// </summary>
/// <param name="resourceFactory">The resource factory used to create GPU resources.</param>
/// <param name="vertexLayout">The vertex layout description to be used with this effect.</param>
/// <param name="vertPath">The file path to the vertex shader source code.</param>
/// <param name="fragPath">The file path to the fragment shader source code.</param>
public Effect(ResourceFactory resourceFactory, VertexLayoutDescription vertexLayout, string vertPath, string fragPath) {
ShaderDescription vertDescription = new ShaderDescription(ShaderStages.Vertex, this.LoadBytecode(vertPath), "main");
ShaderDescription fragDescription = new ShaderDescription(ShaderStages.Fragment, this.LoadBytecode(fragPath), "main");

Shader[] shaders = resourceFactory.CreateFromSpirv(vertDescription, fragDescription);

this.Shader.Item1 = shaders[0];
this.Shader.Item2 = shaders[1];

this.VertexLayout = vertexLayout;
}


/// <summary>
/// Loads the bytecode from the specified shader file path.
/// </summary>
/// <param name="path">The file path to the shader source code.</param>
/// <returns>A byte array containing the bytecode from the shader file.</returns>
private byte[] LoadBytecode(string path) {
if (!File.Exists(path) || (Path.GetExtension(path) != ".vert" && Path.GetExtension(path) != ".frag")) {
throw new ApplicationException($"No shader file found in the path: [{path}]");
Expand All @@ -28,6 +42,7 @@ private byte[] LoadBytecode(string path) {
return File.ReadAllBytes(path);
}

// TODO: ADD MATERIAL param here.
/// <summary>
/// Apply the state effect immediately before rendering it.
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions src/Bliss/CSharp/Geometry/Mesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ namespace Bliss.CSharp.Geometry;
// TODO: Add Material
public struct Mesh {

public Vertex[] Vertices;
public Vertex3D[] Vertices;
public uint[] Indices;

/// <summary>
/// Initializes a new instance of the <see cref="Mesh"/> class with optional vertices and indices.
/// </summary>
/// <param name="vertices">An array of <see cref="Vertex"/> objects. If null, an empty array is used.</param>
/// <param name="vertices">An array of <see cref="Vertex3D"/> objects. If null, an empty array is used.</param>
/// <param name="indices">An array of indices. If null, an empty array is used.</param>
public Mesh(Vertex[]? vertices = default, uint[]? indices = default) {
public Mesh(Vertex3D[]? vertices = default, uint[]? indices = default) {
this.Vertices = vertices ?? [];
this.Indices = indices ?? [];
}
Expand Down
2 changes: 1 addition & 1 deletion src/Bliss/CSharp/Geometry/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static Model Load(ResourceFactory factory, string path, bool flipUv = fal
}

// Vertices
Vertex[] vertices = new Vertex[scene.Meshes[i].VertexCount];
Vertex3D[] vertices = new Vertex3D[scene.Meshes[i].VertexCount];

for (int j = 0; j < mesh.VertexCount; j++) {

Expand Down
5 changes: 5 additions & 0 deletions src/Bliss/CSharp/Geometry/Vertex2D.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Bliss.CSharp.Geometry;

public struct Vertex2D {
// TODO: ADD IT.
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

namespace Bliss.CSharp.Geometry;

public struct Vertex {
public struct Vertex3D {

public Vector3 Position;
public Vector2 TexCoord;
Expand All @@ -13,15 +13,15 @@ public struct Vertex {
public Vector4 Color;

/// <summary>
/// Initializes a new instance of the <see cref="Vertex"/> struct with the specified position, texture coordinates, secondary texture coordinates, normal, tangent, and color.
/// Initializes a new instance of the <see cref="Vertex3D"/> struct with the specified position, texture coordinates, secondary texture coordinates, normal, tangent, and color.
/// </summary>
/// <param name="position">The vertex position in 3D space.</param>
/// <param name="texCoord">The primary texture coordinates for the vertex.</param>
/// <param name="texCoord2">The secondary texture coordinates for the vertex.</param>
/// <param name="normal">The normal vector for the vertex.</param>
/// <param name="tangent">The tangent vector for the vertex.</param>
/// <param name="color">The color of the vertex.</param>
public Vertex(Vector3 position, Vector2 texCoord, Vector2 texCoord2, Vector3 normal, Vector3 tangent, Color color) {
public Vertex3D(Vector3 position, Vector2 texCoord, Vector2 texCoord2, Vector3 normal, Vector3 tangent, Color color) {
this.Position = position;
this.TexCoord = texCoord;
this.TexCoord2 = texCoord2;
Expand Down
64 changes: 64 additions & 0 deletions src/Bliss/CSharp/Graphics/Pipelines/SimplePipeline.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using Bliss.CSharp.Effects;
using Veldrid;

namespace Bliss.CSharp.Graphics.Pipelines;

public class SimplePipeline : Disposable {

public GraphicsDevice GraphicsDevice { get; private set; }
public Effect Effect { get; private set; }
public ResourceLayout ResourceLayout { get; private set; }
public OutputDescription Output { get; private set; }
public BlendStateDescription BlendState { get; private set; }
public FaceCullMode CullMode { get; private set; }

public Pipeline Pipeline { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="SimplePipeline"/> class, setting up the graphics pipeline with the specified configurations.
/// </summary>
/// <param name="graphicsDevice">The graphics device used to create GPU resources and manage rendering.</param>
/// <param name="effect">The effect containing the vertex and fragment shaders to be used in the pipeline.</param>
/// <param name="resourceLayout">The resource layout defining the structure of the resources used in the pipeline.</param>
/// <param name="output">The output description that defines the render targets and their formats.</param>
/// <param name="blendState">The blend state description for controlling how colors are blended.</param>
/// <param name="cullMode">The face culling mode for rendering triangles.</param>
public SimplePipeline(GraphicsDevice graphicsDevice, Effect effect, ResourceLayout resourceLayout, OutputDescription output, BlendStateDescription blendState, FaceCullMode cullMode) {
this.GraphicsDevice = graphicsDevice;
this.Effect = effect;
this.ResourceLayout = resourceLayout;
this.Output = output;
this.BlendState = blendState;
this.CullMode = cullMode;

this.Pipeline = this.GraphicsDevice.ResourceFactory.CreateGraphicsPipeline(new GraphicsPipelineDescription() {
BlendState = this.BlendState,
DepthStencilState = new DepthStencilStateDescription(true, true, ComparisonKind.LessEqual),
RasterizerState = new RasterizerStateDescription() {
DepthClipEnabled = true,
CullMode = this.CullMode,
ScissorTestEnabled = true
},
PrimitiveTopology = PrimitiveTopology.TriangleList,
ResourceLayouts = [
this.ResourceLayout
],
ShaderSet = new ShaderSetDescription() {
VertexLayouts = [
this.Effect.VertexLayout
],
Shaders = [
this.Effect.Shader.Item1,
this.Effect.Shader.Item2
]
},
Outputs = this.Output
});
}

protected override void Dispose(bool disposing) {
if (disposing) {
this.Pipeline.Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Numerics;
using Bliss.CSharp.Geometry;

namespace Bliss.CSharp.Rendering;
namespace Bliss.CSharp.Graphics.Rendering;

public class Frustum {

Expand Down
14 changes: 14 additions & 0 deletions src/Bliss/CSharp/Graphics/Rendering/Sprites/Sprite.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Numerics;
using Bliss.CSharp.Colors;
using Bliss.CSharp.Textures;
using Veldrid;

namespace Bliss.CSharp.Graphics.Rendering.Sprites;

public struct Sprite {

public Matrix4x4 Transform;
public Texture2D Texture;
public Sampler Sampler;
public Color Color;
}
167 changes: 167 additions & 0 deletions src/Bliss/CSharp/Graphics/Rendering/Sprites/SpriteBatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
using System.Numerics;
using Bliss.CSharp.Effects;
using Bliss.CSharp.Graphics.Pipelines;
using Bliss.CSharp.Logging;
using Bliss.CSharp.Textures;
using Veldrid;

namespace Bliss.CSharp.Graphics.Rendering.Sprites;

public class SpriteBatch : Disposable {

public const uint MaxSprites = 15360;

private const uint VertexCount = 4;
private const uint IndexCount = 6;

public GraphicsDevice GraphicsDevice { get; private set; }

private CommandList _commandList;
private Fence _fence;

private List<Sprite> _sprites;

private DeviceBuffer _vertexBuffer;
private DeviceBuffer _indexBuffer;

private Effect? _effect;
private ResourceLayout? _resourceLayout;
private Pipeline _pipeline;
private bool _isDefaultPipeline;

private ResourceSet _resourceSet;

private bool _begun;

public Matrix4x4 _currentTransform;
private Effect _currentEffect;
private Texture2D _currentTexture;

public SpriteBatch(GraphicsDevice graphicsDevice, SimplePipeline? pipeline = null) {
this.GraphicsDevice = graphicsDevice;
this._commandList = graphicsDevice.ResourceFactory.CreateCommandList();
this._fence = graphicsDevice.ResourceFactory.CreateFence(false);

this._sprites = new List<Sprite>();

// Create Vertex and Index Buffer.
uint vertexBufferSize = VertexCount * sizeof(float);
uint indexBufferSize = IndexCount * sizeof(float);

this._vertexBuffer = graphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription(MaxSprites * vertexBufferSize, BufferUsage.VertexBuffer));
this._indexBuffer = graphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription(MaxSprites * indexBufferSize, BufferUsage.IndexBuffer));

if (pipeline != null) {
this._pipeline = pipeline.Pipeline;
}
else {
// Load default sprite shader.
this._effect = new Effect(graphicsDevice.ResourceFactory, new VertexLayoutDescription() {
Elements = [ // TODO: UPDATE THE SHADER PARAMS
new VertexElementDescription("vertexPosition", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float3),
new VertexElementDescription("vertexTexCoord", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2),
new VertexElementDescription("vertexColor", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float4)
]
}, "content/shaders/default_shader.vert", "content/shaders/default_shader.frag");

// Create default resource layout.
this._resourceLayout = graphicsDevice.ResourceFactory.CreateResourceLayout(
new ResourceLayoutDescription( // TODO: UPDATE THE SHADER PARAMS
new ResourceLayoutElementDescription("MVP", ResourceKind.UniformBuffer, ShaderStages.Vertex),
new ResourceLayoutElementDescription("Color", ResourceKind.UniformBuffer, ShaderStages.Fragment),
new ResourceLayoutElementDescription("texture0", ResourceKind.TextureReadOnly, ShaderStages.Fragment),
new ResourceLayoutElementDescription("Sampler", ResourceKind.Sampler, ShaderStages.Fragment)
)
);

// Create default pipeline.
this._pipeline = new SimplePipeline(this.GraphicsDevice, this._effect, this._resourceLayout, graphicsDevice.SwapchainFramebuffer.OutputDescription, BlendStateDescription.SingleOverrideBlend, FaceCullMode.Back).Pipeline;
this._isDefaultPipeline = true;
}
}

public void Begin(Matrix4x4? transform = null, Effect? effect = null, BlendStateDescription? blendState = null) {
if (this._begun) {
throw new Exception("SpriteBatch is already active.");
}

this._begun = true;

Matrix4x4 trans = transform ?? Matrix4x4.Identity;

this._commandList.Begin();
}

public CommandList End() {
if (!this._begun) {
throw new Exception("The SpriteBatch begin method get not called at first.");
}

// TODO: DO A IF CHECK IF THERE IS A INSTANCE if not do not run it!

if (true) {
this.ReallyDraw();

this._commandList.End();
this.GraphicsDevice.SubmitCommands(this._commandList, this._fence);
}

this._begun = false;
return this._commandList;
}

public CommandList GetCommandList() {
if (this._begun) {
Logger.Error("Cannot call .GetCommandList() while begin is true. Call .End() first.");
return null;
}

return this._commandList;
}

private void ReallyDraw() {

}

private void Flush() {

ResourceSetDescription resourceSetDescription = new ResourceSetDescription(this._resourceLayout, this._currentTexture.DeviceTexture, this.GraphicsDevice.PointSampler);
// Update Resources
this._resourceSet = this.GraphicsDevice.ResourceFactory.CreateResourceSet(ref resourceSetDescription);

// Update Index Buffer
this.GraphicsDevice.UpdateBuffer(this._vertexBuffer, 0, [
(new Vector2())
]);

// Update Index Buffer
ushort[] quadIndices = [0, 1, 2, 3];
this.GraphicsDevice.UpdateBuffer(this._indexBuffer, 0, quadIndices);

// Setup Resources
this._commandList.SetVertexBuffer(0, this._vertexBuffer);
this._commandList.SetIndexBuffer(this._indexBuffer, IndexFormat.UInt16);
this._commandList.SetPipeline(this._pipeline);
this._commandList.SetGraphicsResourceSet(0, this._resourceSet);

// Draw
this._commandList.DrawIndexed(4, 1, 0, 0, 0);
}

protected override void Dispose(bool disposing) {
if (disposing) {
this._fence.Dispose();
this._sprites.Clear();

this._vertexBuffer.Dispose();
this._indexBuffer.Dispose();

this._effect?.Dispose();
this._resourceLayout?.Dispose();

if (this._isDefaultPipeline) {
this._pipeline.Dispose();
}
}
}
}
Loading

0 comments on commit f3dbff3

Please sign in to comment.