diff --git a/src/Bliss.Test/Game.cs b/src/Bliss.Test/Game.cs index 9b2bbfc..15b00da 100644 --- a/src/Bliss.Test/Game.cs +++ b/src/Bliss.Test/Game.cs @@ -98,7 +98,10 @@ public void Run() { this.SetTargetFps(this.Settings.TargetFps); Logger.Info("Initialize command list..."); - this.CommandList = this.GraphicsDevice.ResourceFactory.CreateCommandList(); + this.CommandList = graphicsDevice.ResourceFactory.CreateCommandList(); + + Logger.Info("Initialize global resources..."); + GlobalResource.Init(graphicsDevice); Logger.Info("Initialize input..."); if (this.MainWindow is Sdl3Window) { @@ -133,7 +136,7 @@ public void Run() { this._fixedUpdateTimer -= this._fixedUpdateTimeStep; } - this.Draw(this.GraphicsDevice, this.CommandList); + this.Draw(graphicsDevice, this.CommandList); Input.End(); } @@ -217,7 +220,7 @@ protected virtual void Draw(GraphicsDevice graphicsDevice, CommandList commandLi commandList.ResolveTexture(this.FullScreenTexture.ColorTexture, this.FullScreenTexture.DestinationTexture); } - commandList.SetFramebuffer(this.GraphicsDevice.SwapchainFramebuffer); + commandList.SetFramebuffer(graphicsDevice.SwapchainFramebuffer); commandList.ClearColorTarget(0, Color.DarkGray.ToRgbaFloat()); this.FullScreenRenderPass.Draw(commandList, this.FullScreenTexture, SamplerType.Point); @@ -249,6 +252,10 @@ protected override void Dispose(bool disposing) { this.GraphicsDevice.Dispose(); this.MainWindow.Dispose(); Input.Destroy(); + GlobalResource.Destroy(); + + this._playerModel.Dispose(); + this._planeModel.Dispose(); } } } \ No newline at end of file diff --git a/src/Bliss/CSharp/Effects/Effect.cs b/src/Bliss/CSharp/Effects/Effect.cs index ff8363f..25b51ce 100644 --- a/src/Bliss/CSharp/Effects/Effect.cs +++ b/src/Bliss/CSharp/Effects/Effect.cs @@ -6,6 +6,7 @@ * https://github.com/MrScautHD/Bliss/blob/main/LICENSE */ +using Bliss.CSharp.Graphics.Pipelines; using Bliss.CSharp.Logging; using Veldrid; using Veldrid.SPIRV; @@ -14,6 +15,11 @@ namespace Bliss.CSharp.Effects; public class Effect : Disposable { + /// + /// The graphics device used for creating and managing graphical resources. + /// + public GraphicsDevice GraphicsDevice { get; private set; } + /// /// Represents a pair of shaders consisting of a vertex shader and a fragment shader. /// @@ -25,31 +31,40 @@ public class Effect : Disposable { public readonly VertexLayoutDescription VertexLayout; /// - /// Initializes a new instance of the class by loading and compiling shaders and setting up the vertex layout. + /// A cache of pipelines created for specific pipeline descriptions, enabling reuse. /// - /// The resource factory used to create GPU resources. - /// The vertex layout description to be used with this effect. + private Dictionary _cachedPipelines; + + /// + /// Initializes a new instance of the class by loading shaders from file paths. + /// + /// The graphics device used for creating resources. + /// The vertex layout description for the pipeline. /// The file path to the vertex shader source code. /// The file path to the fragment shader source code. - public Effect(ResourceFactory resourceFactory, VertexLayoutDescription vertexLayout, string vertPath, string fragPath) : this(resourceFactory, vertexLayout, LoadBytecode(vertPath), LoadBytecode(fragPath)) { } - + public Effect(GraphicsDevice graphicsDevice, VertexLayoutDescription vertexLayout, string vertPath, string fragPath) : this(graphicsDevice, vertexLayout, LoadBytecode(vertPath), LoadBytecode(fragPath)) { } + /// - /// Initializes a new instance of the class with the specified vertex layout and shader bytecode. + /// Initializes a new instance of the class with precompiled shader bytecode. /// - /// The resource factory used to create shaders and resources. - /// The layout of the vertex data for this effect. - /// A byte array containing the vertex shader bytecode. - /// A byte array containing the fragment shader bytecode. - public Effect(ResourceFactory resourceFactory, VertexLayoutDescription vertexLayout, byte[] vertBytes, byte[] fragBytes) { + /// The graphics device used for creating resources. + /// The vertex layout description for the pipeline. + /// The bytecode for the vertex shader. + /// The bytecode for the fragment shader. + public Effect(GraphicsDevice graphicsDevice, VertexLayoutDescription vertexLayout, byte[] vertBytes, byte[] fragBytes) { + this.GraphicsDevice = graphicsDevice; + ShaderDescription vertDescription = new ShaderDescription(ShaderStages.Vertex, vertBytes, "main"); ShaderDescription fragDescription = new ShaderDescription(ShaderStages.Fragment, fragBytes, "main"); - Shader[] shaders = resourceFactory.CreateFromSpirv(vertDescription, fragDescription); + Shader[] shaders = graphicsDevice.ResourceFactory.CreateFromSpirv(vertDescription, fragDescription); this.Shader.Item1 = shaders[0]; this.Shader.Item2 = shaders[1]; this.VertexLayout = vertexLayout; + + this._cachedPipelines = new Dictionary(); } /// @@ -69,9 +84,26 @@ private static byte[] LoadBytecode(string path) { Logger.Info($"Shader bytes loaded successfully from path: [{path}]"); return File.ReadAllBytes(path); } + + /// + /// Retrieves or creates a pipeline for the given pipeline description. + /// + /// The description of the pipeline to retrieve or create. + /// A configured with the specified description. + public SimplePipeline GetPipeline(SimplePipelineDescription pipelineDescription) { + if (!this._cachedPipelines.TryGetValue(pipelineDescription, out SimplePipeline? pipeline)) { + SimplePipeline newPipeline = new SimplePipeline(this.GraphicsDevice, pipelineDescription); + + Logger.Error(pipelineDescription.ToString()); + + this._cachedPipelines.Add(pipelineDescription, newPipeline); + return newPipeline; + } + + return pipeline; + } // TODO: Adding Location system, for Material(Texture, Color) and in generel for buffers... - // TODO: ADD MATERIAL param here. /// /// Apply the state effect immediately before rendering it. @@ -82,6 +114,10 @@ protected override void Dispose(bool disposing) { if (disposing) { this.Shader.Item1.Dispose(); this.Shader.Item2.Dispose(); + + foreach (SimplePipeline pipeline in this._cachedPipelines.Values) { + pipeline.Dispose(); + } } } } \ No newline at end of file diff --git a/src/Bliss/CSharp/Geometry/Animations/Keyframes/QuatKey.cs b/src/Bliss/CSharp/Geometry/Animations/Keyframes/QuatKey.cs index 03018f5..e7bf861 100644 --- a/src/Bliss/CSharp/Geometry/Animations/Keyframes/QuatKey.cs +++ b/src/Bliss/CSharp/Geometry/Animations/Keyframes/QuatKey.cs @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024 Elias Springer (@MrScautHD) + * License-Identifier: Bliss License 1.0 + * + * For full license details, see: + * https://github.com/MrScautHD/Bliss/blob/main/LICENSE + */ + using System.Numerics; namespace Bliss.CSharp.Geometry.Animations.Keyframes; diff --git a/src/Bliss/CSharp/Geometry/Animations/Keyframes/Vector3Key.cs b/src/Bliss/CSharp/Geometry/Animations/Keyframes/Vector3Key.cs index 78ba972..5841be5 100644 --- a/src/Bliss/CSharp/Geometry/Animations/Keyframes/Vector3Key.cs +++ b/src/Bliss/CSharp/Geometry/Animations/Keyframes/Vector3Key.cs @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024 Elias Springer (@MrScautHD) + * License-Identifier: Bliss License 1.0 + * + * For full license details, see: + * https://github.com/MrScautHD/Bliss/blob/main/LICENSE + */ + using System.Numerics; namespace Bliss.CSharp.Geometry.Animations.Keyframes; diff --git a/src/Bliss/CSharp/Geometry/Animations/MeshAmateurBuilder.cs b/src/Bliss/CSharp/Geometry/Animations/MeshAmateurBuilder.cs index c719f09..0288c61 100644 --- a/src/Bliss/CSharp/Geometry/Animations/MeshAmateurBuilder.cs +++ b/src/Bliss/CSharp/Geometry/Animations/MeshAmateurBuilder.cs @@ -218,8 +218,8 @@ private Matrix4x4 InterpolateScale(NodeAnimChannel channel, ModelAnimation anima } } - Vector3Key currentFrame = channel.Scales[(int)frameIndex]; - Vector3Key nextFrame = channel.Scales[(int)((frameIndex + 1) % channel.Scales.Count)]; + Vector3Key currentFrame = channel.Scales[(int) frameIndex]; + Vector3Key nextFrame = channel.Scales[(int) ((frameIndex + 1) % channel.Scales.Count)]; double delta = (frameTime - currentFrame.Time) / (nextFrame.Time - currentFrame.Time); diff --git a/src/Bliss/CSharp/Geometry/Animations/NodeAnimChannel.cs b/src/Bliss/CSharp/Geometry/Animations/NodeAnimChannel.cs index d4a45cb..ecadc5d 100644 --- a/src/Bliss/CSharp/Geometry/Animations/NodeAnimChannel.cs +++ b/src/Bliss/CSharp/Geometry/Animations/NodeAnimChannel.cs @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024 Elias Springer (@MrScautHD) + * License-Identifier: Bliss License 1.0 + * + * For full license details, see: + * https://github.com/MrScautHD/Bliss/blob/main/LICENSE + */ + using Bliss.CSharp.Geometry.Animations.Keyframes; namespace Bliss.CSharp.Geometry.Animations; diff --git a/src/Bliss/CSharp/Geometry/Mesh.cs b/src/Bliss/CSharp/Geometry/Mesh.cs index 6379c7e..93fb42e 100644 --- a/src/Bliss/CSharp/Geometry/Mesh.cs +++ b/src/Bliss/CSharp/Geometry/Mesh.cs @@ -24,12 +24,6 @@ namespace Bliss.CSharp.Geometry; public class Mesh : Disposable { - /// - /// A dictionary that caches instances of SimplePipeline based on Material keys. - /// This helps in reusing pipeline configurations for materials, enhancing rendering performance and reducing redundant pipeline creation. - /// - private static Dictionary _cachedPipelines = new(); // TODO: Take care of disposing it idk maybe a system that checks if its the last mesh that using it and dispose it with it. - /// /// Represents the graphics device used for rendering operations. /// This property provides access to the underlying GraphicsDevice instance responsible for managing GPU resources and executing rendering commands. @@ -101,6 +95,13 @@ public class Mesh : Disposable { /// This buffer holds an array of structures representing bone matrices and is utilized during rendering to apply bone transformations to vertices. /// private SimpleBuffer _boneBuffer; + + /// + /// Defines the characteristics of the rendering pipeline used by the mesh. + /// This field specifies the pipeline configurations such as blending, depth stencil, rasterizer state, + /// primitive topology, associated buffers, texture layouts, shader set, and output descriptions. + /// + private SimplePipelineDescription _pipelineDescription; /// /// Initializes a new instance of the class with the specified properties. @@ -138,6 +139,8 @@ public Mesh(GraphicsDevice graphicsDevice, Material material, Vertex3D[]? vertic } this._boneBuffer.UpdateBufferImmediate(); + + this._pipelineDescription = this.CreatePipelineDescription(); } /// @@ -191,6 +194,11 @@ public void Draw(CommandList commandList, OutputDescription output, Transform tr this._modelMatrixBuffer.SetValue(1, cam3D.GetView()); this._modelMatrixBuffer.SetValue(2, transform.GetTransform()); this._modelMatrixBuffer.UpdateBuffer(commandList); + + // Update pipeline description. + this._pipelineDescription.BlendState = this.Material.BlendState.Description; + this._pipelineDescription.TextureLayouts = this.Material.GetTextureLayouts(); + this._pipelineDescription.Outputs = output; if (this.IndexCount > 0) { @@ -199,7 +207,7 @@ public void Draw(CommandList commandList, OutputDescription output, Transform tr commandList.SetIndexBuffer(this._indexBuffer, IndexFormat.UInt32); // Set pipeline. - commandList.SetPipeline(this.GetOrCreatePipeline(this.Material, output).Pipeline); + commandList.SetPipeline(this.Material.Effect.GetPipeline(this._pipelineDescription).Pipeline); // Set projection view buffer. commandList.SetGraphicsResourceSet(0, this._modelMatrixBuffer.ResourceSet); @@ -226,7 +234,7 @@ public void Draw(CommandList commandList, OutputDescription output, Transform tr commandList.SetVertexBuffer(0, this._vertexBuffer); // Set pipeline. - commandList.SetPipeline(this.GetOrCreatePipeline(this.Material, output).Pipeline); + commandList.SetPipeline(this.Material.Effect.GetPipeline(this._pipelineDescription).Pipeline); // Set projection view buffer. commandList.SetGraphicsResourceSet(0, this._modelMatrixBuffer.ResourceSet); @@ -252,49 +260,35 @@ public void Draw(CommandList commandList, OutputDescription output, Transform tr this.Material.SetMapColor(MaterialMapType.Albedo.ToString(), cachedColor); } - /// - /// Retrieves an existing pipeline associated with the given material and output description, or creates a new one if it doesn't exist. - /// - /// The material associated with the pipeline. - /// The output description for the pipeline. - /// A pipeline that matches the specified material and output description. - private SimplePipeline GetOrCreatePipeline(Material material, OutputDescription output) { - if (!_cachedPipelines.TryGetValue(material, out SimplePipeline? pipeline)) { - SimplePipeline newPipeline = new SimplePipeline(this.GraphicsDevice, new SimplePipelineDescription() { - BlendState = material.BlendState.Description, - DepthStencilState = new DepthStencilStateDescription(true, true, ComparisonKind.LessEqual), - RasterizerState = new RasterizerStateDescription() { - CullMode = FaceCullMode.Back, - FillMode = PolygonFillMode.Solid, - FrontFace = FrontFace.Clockwise, - DepthClipEnabled = true, - ScissorTestEnabled = false - }, - PrimitiveTopology = PrimitiveTopology.TriangleList, - Buffers = [ - this._modelMatrixBuffer, - this._boneBuffer + private SimplePipelineDescription CreatePipelineDescription() { + return new SimplePipelineDescription() { + BlendState = this.Material.BlendState.Description, + DepthStencilState = new DepthStencilStateDescription(true, true, ComparisonKind.LessEqual), + RasterizerState = new RasterizerStateDescription() { + CullMode = FaceCullMode.Back, + FillMode = PolygonFillMode.Solid, + FrontFace = FrontFace.Clockwise, + DepthClipEnabled = true, + ScissorTestEnabled = false + }, + PrimitiveTopology = PrimitiveTopology.TriangleList, + Buffers = [ + this._modelMatrixBuffer, + this._boneBuffer + ], + TextureLayouts = this.Material.GetTextureLayouts(), + ShaderSet = new ShaderSetDescription() { + VertexLayouts = [ + this.Material.Effect.VertexLayout ], - TextureLayouts = material.GetTextureLayouts(), - ShaderSet = new ShaderSetDescription() { - VertexLayouts = [ - material.Effect.VertexLayout - ], - Shaders = [ - material.Effect.Shader.Item1, - material.Effect.Shader.Item2 - ] - }, - Outputs = output - }); - - _cachedPipelines.Add(material, newPipeline); - return newPipeline; - } - - return pipeline; + Shaders = [ + this.Material.Effect.Shader.Item1, + this.Material.Effect.Shader.Item2 + ] + } + }; } - + /// /// Calculates the bounding box for the current mesh based on its vertices. /// diff --git a/src/Bliss/CSharp/Geometry/Model.cs b/src/Bliss/CSharp/Geometry/Model.cs index f5c6904..42ea848 100644 --- a/src/Bliss/CSharp/Geometry/Model.cs +++ b/src/Bliss/CSharp/Geometry/Model.cs @@ -62,18 +62,6 @@ public class Model : Disposable { new FBXImportCamerasConfig(false), new FBXStrictModeConfig(false) ]; - - /// - /// The default effect applied to models. - /// This is instantiated with shaders for rendering models, and includes configuration for vertex layout. - /// - private static Effect? _defaultEffect; - - /// - /// The default texture used when no other texture is specified. - /// Typically a 1x1 pixel texture with a solid color. - /// - private static Texture2D? _defaultTexture; /// /// The graphics device used for rendering the model. @@ -126,7 +114,6 @@ public static Model Load(GraphicsDevice graphicsDevice, string path, bool loadMa } Scene scene = context.ImportFile(path, DefaultPostProcessSteps); - List meshes = new List(); List animations = new List(); @@ -181,11 +168,11 @@ public static Model Load(GraphicsDevice graphicsDevice, string path, bool loadMa ShaderMaterialProperties shaderProperties = aMaterial.Shaders; if (shaderProperties.HasVertexShader && shaderProperties.HasFragmentShader) { - effect = new Effect(graphicsDevice.ResourceFactory, Vertex3D.VertexLayout, Encoding.UTF8.GetBytes(shaderProperties.VertexShader), Encoding.UTF8.GetBytes(shaderProperties.FragmentShader)); + effect = new Effect(graphicsDevice, Vertex3D.VertexLayout, Encoding.UTF8.GetBytes(shaderProperties.VertexShader), Encoding.UTF8.GetBytes(shaderProperties.FragmentShader)); } } - effect ??= GetDefaultEffect(graphicsDevice); + effect ??= GlobalResource.DefaultModelEffect; // Load material maps. Material material = new Material(graphicsDevice, effect); @@ -240,7 +227,7 @@ public static Model Load(GraphicsDevice graphicsDevice, string path, bool loadMa } else { material.AddMaterialMap(MaterialMapType.Albedo.ToString(), new MaterialMap() { - Texture = GetDefaultTexture(graphicsDevice), + Texture = GlobalResource.DefaultModelTexture, Color = Color.White }); } @@ -322,32 +309,6 @@ public static Model Load(GraphicsDevice graphicsDevice, string path, bool loadMa return new Model(graphicsDevice, meshes.ToArray(), animations.ToArray()); } - /// - /// Retrieves the default effect for the model. - /// If the default effect is not already created, it initializes a new with the specified graphics device. - /// - /// The graphics device used to create the default effect. - /// The default for the model. - private static Effect GetDefaultEffect(GraphicsDevice graphicsDevice) { // TODO: Take care to dispose it! - return _defaultEffect ??= new Effect(graphicsDevice.ResourceFactory, Vertex3D.VertexLayout, "content/shaders/default_model.vert", "content/shaders/default_model.frag"); - } - - /// - /// Retrieves the default texture for the specified graphics device. - /// - /// The graphics device to associate with the default texture. - /// Returns a new instance of the class with a default solid color texture. - private static Texture2D GetDefaultTexture(GraphicsDevice graphicsDevice) { // TODO: Take care to dispose it! - if (_defaultTexture != null) { - return _defaultTexture; - } - else { - using (Image image = new Image(1, 1, new Rgba32(128, 128, 128, 255))) { - return _defaultTexture ??= new Texture2D(graphicsDevice, image); - } - } - } - /// /// Loads a texture from a material and returns it as a Texture2D object. If the texture is embedded, it extracts from the embedded data. /// diff --git a/src/Bliss/CSharp/GlobalResource.cs b/src/Bliss/CSharp/GlobalResource.cs new file mode 100644 index 0000000..5f78654 --- /dev/null +++ b/src/Bliss/CSharp/GlobalResource.cs @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 Elias Springer (@MrScautHD) + * License-Identifier: Bliss License 1.0 + * + * For full license details, see: + * https://github.com/MrScautHD/Bliss/blob/main/LICENSE + */ + +using Bliss.CSharp.Effects; +using Bliss.CSharp.Graphics.VertexTypes; +using Bliss.CSharp.Textures; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using Veldrid; + +namespace Bliss.CSharp; + +public static class GlobalResource { + + /// + /// Provides access to the global graphics device used for rendering operations. + /// + public static GraphicsDevice GraphicsDevice { get; private set; } + + /// + /// The default effect used for rendering 3D models. + /// + public static Effect DefaultModelEffect { get; private set; } + + /// + /// The default texture used for rendering 3D models. + /// + public static Texture2D DefaultModelTexture { get; private set; } + + /// + /// Initializes global resources. + /// + /// The graphics device to be used for resource creation and rendering. + public static void Init(GraphicsDevice graphicsDevice) { + GraphicsDevice = graphicsDevice; + + // Default model effect. + DefaultModelEffect = new Effect(graphicsDevice, Vertex3D.VertexLayout, "content/shaders/default_model.vert", "content/shaders/default_model.frag"); + + // Default model texture. + using (Image image = new Image(1, 1, new Rgba32(128, 128, 128, 255))) { + DefaultModelTexture = new Texture2D(graphicsDevice, image); + } + } + + /// + /// Releases and disposes of all global resources. + /// + public static void Destroy() { + DefaultModelEffect.Dispose(); + DefaultModelTexture.Dispose(); + } +} \ No newline at end of file diff --git a/src/Bliss/CSharp/Graphics/Pipelines/SimplePipeline.cs b/src/Bliss/CSharp/Graphics/Pipelines/SimplePipeline.cs index d7d9246..8e3cb68 100644 --- a/src/Bliss/CSharp/Graphics/Pipelines/SimplePipeline.cs +++ b/src/Bliss/CSharp/Graphics/Pipelines/SimplePipeline.cs @@ -76,6 +76,15 @@ public SimplePipeline(GraphicsDevice graphicsDevice, SimplePipelineDescription p public ISimpleBuffer? GetBuffer(string name) { return this.PipelineDescription.Buffers.FirstOrDefault(buffer => buffer.Name == name); } + + /// + /// Retrieves the texture layout associated with the specified name from the pipeline description. + /// + /// The name of the texture layout to retrieve. + /// The associated with the specified name, or null if no layout with the given name exists. + public SimpleTextureLayout? GetTextureLayout(string name) { + return this.PipelineDescription.TextureLayouts.FirstOrDefault(buffer => buffer.Name == name); + } protected override void Dispose(bool disposing) { if (disposing) { diff --git a/src/Bliss/CSharp/Graphics/Pipelines/SimplePipelineDescription.cs b/src/Bliss/CSharp/Graphics/Pipelines/SimplePipelineDescription.cs index 5074aad..d216e9f 100644 --- a/src/Bliss/CSharp/Graphics/Pipelines/SimplePipelineDescription.cs +++ b/src/Bliss/CSharp/Graphics/Pipelines/SimplePipelineDescription.cs @@ -12,7 +12,7 @@ namespace Bliss.CSharp.Graphics.Pipelines; -public struct SimplePipelineDescription { +public struct SimplePipelineDescription : IEquatable { /// /// Defines the blend state configuration, controlling how colors are blended in the pipeline. @@ -81,7 +81,7 @@ public SimplePipelineDescription(BlendStateDescription blendState, DepthStencilS this.Outputs = outputs; this.ResourceBindingModel = null; } - + /// /// Initializes a new instance of the struct. /// @@ -89,4 +89,88 @@ public SimplePipelineDescription() { this.Buffers = []; this.TextureLayouts = []; } + + /// + /// Determines whether two instances are equal based on their properties. + /// + /// The first instance to compare. + /// The second instance to compare. + /// true if the instances are equal; otherwise, false. + public static bool operator ==(SimplePipelineDescription left, SimplePipelineDescription right) => left.Equals(right); + + /// + /// Determines whether two instances are equal. + /// + /// The first to compare. + /// The second to compare. + /// True if both instances are equal; otherwise, false. + public static bool operator !=(SimplePipelineDescription left, SimplePipelineDescription right) => !left.Equals(right); + + /// + /// Determines whether the current instance is equal to another specified instance. + /// + /// The other instance to compare with the current instance. + /// A boolean value indicating whether the two instances are equal. + public bool Equals(SimplePipelineDescription other) { + return this.BlendState.Equals(other.BlendState) && + this.DepthStencilState.Equals(other.DepthStencilState) && + this.RasterizerState.Equals(other.RasterizerState) && + this.PrimitiveTopology == other.PrimitiveTopology && + this.Buffers.Select(buffer => buffer.Name).SequenceEqual(other.Buffers.Select(buffer => buffer.Name)) && + this.TextureLayouts.Select(layout => layout.Name).SequenceEqual(other.TextureLayouts.Select(layout => layout.Name)) && + this.ShaderSet.Equals(other.ShaderSet) && + this.Outputs.Equals(other.Outputs) && + this.ResourceBindingModel == other.ResourceBindingModel; + } + + /// + /// Determines whether the specified object is equal to the current instance. + /// + /// The object to compare with the current instance. + /// A boolean value indicating whether the specified object is equal to the current instance. + public override bool Equals(object? obj) { + return obj is SimplePipelineDescription other && this.Equals(other); + } + + /// + /// Returns a hash code for this instance of . + /// + /// A 32-bit signed integer hash code that is representative of the object's current state and its members. + public override int GetHashCode() { + HashCode hashCode = new HashCode(); + hashCode.Add(this.BlendState); + hashCode.Add(this.DepthStencilState); + hashCode.Add(this.RasterizerState); + hashCode.Add((int) this.PrimitiveTopology); + + foreach (ISimpleBuffer buffer in this.Buffers) { + hashCode.Add(buffer.Name); + } + + foreach (SimpleTextureLayout layout in this.TextureLayouts) { + hashCode.Add(layout.Name); + } + + hashCode.Add(this.ShaderSet); + hashCode.Add(this.Outputs); + hashCode.Add(this.ResourceBindingModel); + return hashCode.ToHashCode(); + } + + /// + /// Returns a string representation of the instance, detailing its configuration and properties. + /// + /// A string that includes the blend state, depth-stencil state, rasterizer state, primitive topology, buffers, texture layouts, shader set, outputs, and resource binding model of the pipeline description. + public override string ToString() { + return $"SimplePipelineDescription: \n" + + $"\t> BlendState = {this.BlendState}, \n" + + $"\t> DepthStencilState = {this.DepthStencilState}, \n" + + $"\t> RasterizerState = {this.RasterizerState}, \n" + + $"\t> PrimitiveTopology = {this.PrimitiveTopology}, \n" + + $"\t> Buffers = [{string.Join(", ", this.Buffers.Select(buffer => buffer.Name))}], \n" + + $"\t> TextureLayouts = [{string.Join(", ", this.TextureLayouts.Select(layout => layout.Name))}], \n" + + $"\t> ShaderSet = {this.ShaderSet}, \n" + + $"\t> Outputs = {this.Outputs}, \n" + + $"\t> ResourceBindingModel = {(this.ResourceBindingModel.HasValue ? this.ResourceBindingModel.Value : "NULL")}"; + } } \ No newline at end of file diff --git a/src/Bliss/CSharp/Graphics/Rendering/Batches/Primitives/PrimitiveBatch.cs b/src/Bliss/CSharp/Graphics/Rendering/Batches/Primitives/PrimitiveBatch.cs index 5b43bb9..3a08498 100644 --- a/src/Bliss/CSharp/Graphics/Rendering/Batches/Primitives/PrimitiveBatch.cs +++ b/src/Bliss/CSharp/Graphics/Rendering/Batches/Primitives/PrimitiveBatch.cs @@ -118,7 +118,7 @@ public PrimitiveBatch(GraphicsDevice graphicsDevice, IWindow window, OutputDescr this.Capacity = capacity; // Create effects. - this._effect = new Effect(graphicsDevice.ResourceFactory, PrimitiveVertex2D.VertexLayout, "content/shaders/primitive.vert", "content/shaders/primitive.frag"); + this._effect = new Effect(graphicsDevice, PrimitiveVertex2D.VertexLayout, "content/shaders/primitive.vert", "content/shaders/primitive.frag"); // Create projection view buffer. this._projViewBuffer = new SimpleBuffer(graphicsDevice, "ProjectionViewBuffer", 2, SimpleBufferType.Uniform, ShaderStages.Vertex); diff --git a/src/Bliss/CSharp/Graphics/Rendering/Batches/Sprites/SpriteBatch.cs b/src/Bliss/CSharp/Graphics/Rendering/Batches/Sprites/SpriteBatch.cs index c6a374e..6580557 100644 --- a/src/Bliss/CSharp/Graphics/Rendering/Batches/Sprites/SpriteBatch.cs +++ b/src/Bliss/CSharp/Graphics/Rendering/Batches/Sprites/SpriteBatch.cs @@ -181,7 +181,7 @@ public SpriteBatch(GraphicsDevice graphicsDevice, IWindow window, OutputDescript this._cachedPipelines = new Dictionary<(Effect, BlendState), SimplePipeline>(); // Create default effect. - this._defaultEffect = new Effect(this.GraphicsDevice.ResourceFactory, SpriteVertex2D.VertexLayout, "content/shaders/sprite.vert", "content/shaders/sprite.frag"); + this._defaultEffect = new Effect(graphicsDevice, SpriteVertex2D.VertexLayout, "content/shaders/sprite.vert", "content/shaders/sprite.frag"); // Create vertex buffer. this._vertices = new SpriteVertex2D[capacity * VerticesPerQuad]; diff --git a/src/Bliss/CSharp/Graphics/Rendering/Passes/FullScreenRenderPass.cs b/src/Bliss/CSharp/Graphics/Rendering/Passes/FullScreenRenderPass.cs index d59838e..35c2528 100644 --- a/src/Bliss/CSharp/Graphics/Rendering/Passes/FullScreenRenderPass.cs +++ b/src/Bliss/CSharp/Graphics/Rendering/Passes/FullScreenRenderPass.cs @@ -60,7 +60,7 @@ public FullScreenRenderPass(GraphicsDevice graphicsDevice, OutputDescription out this.GraphicsDevice = graphicsDevice; this.Output = output; - this._effect = new Effect(graphicsDevice.ResourceFactory, SpriteVertex2D.VertexLayout, "content/shaders/full_screen_render_pass.vert", "content/shaders/full_screen_render_pass.frag"); + this._effect = new Effect(graphicsDevice, SpriteVertex2D.VertexLayout, "content/shaders/full_screen_render_pass.vert", "content/shaders/full_screen_render_pass.frag"); // Create texture layout. this._textureLayout = new SimpleTextureLayout(graphicsDevice, "fTexture"); diff --git a/src/Bliss/CSharp/Materials/Material.cs b/src/Bliss/CSharp/Materials/Material.cs index 93b74b7..d670bc4 100644 --- a/src/Bliss/CSharp/Materials/Material.cs +++ b/src/Bliss/CSharp/Materials/Material.cs @@ -26,11 +26,11 @@ public class Material : Disposable { /// The effect (shader program) applied to this material. /// public Effect Effect { get; private set; } - + /// /// Specifies the blend state for rendering, determining how colors are blended on the screen. /// - public BlendState BlendState { get; private set; } + public BlendState BlendState; /// /// A list of floating-point parameters for configuring material properties. @@ -63,7 +63,7 @@ public Material(GraphicsDevice graphicsDevice, Effect effect, BlendState? blendS this._textureLayouts = new Dictionary(); this._maps = new Dictionary(); } - + /// /// Retrieves a associated with the specified layout and map name. /// diff --git a/src/Bliss/content/shaders/default_model.vert b/src/Bliss/content/shaders/default_model.vert index 78921e1..937d6e4 100644 --- a/src/Bliss/content/shaders/default_model.vert +++ b/src/Bliss/content/shaders/default_model.vert @@ -33,7 +33,11 @@ layout (location = 2) out vec3 fNormal; layout (location = 3) out vec3 fTangent; layout (location = 4) out vec4 fColor; -mat4x4 getBoneTransformation() { // TODO: Do a second shader and Vertex3D one with skinned mesh and one without to fix the issue that no project is rendered. +mat4x4 getBoneTransformation() { + if (length(vBoneWeights) == 0.0F) { + return mat4x4(1.0F); + } + mat4x4 boneTransformation = uBonesTransformations[vBoneIndices.x] * vBoneWeights.x; boneTransformation += uBonesTransformations[vBoneIndices.y] * vBoneWeights.y; boneTransformation += uBonesTransformations[vBoneIndices.z] * vBoneWeights.z;