diff --git a/src/Bliss.Test/Game.cs b/src/Bliss.Test/Game.cs index 7b5ee02..f7e800a 100644 --- a/src/Bliss.Test/Game.cs +++ b/src/Bliss.Test/Game.cs @@ -31,16 +31,16 @@ public Game() { public void Run() { Logger.Info("Hello World! Bliss start..."); - this.Vk = Vk.GetApi(); Logger.Info("Initialize Vulkan..."); + this.Vk = Vk.GetApi(); + Logger.Info("Initialize Window..."); this.Window = SilkWindow.Create(WindowOptions.DefaultVulkan with { Title = "Test Game!", Size = new Vector2D(1270, 720) }); - - this.Window.Load += this.Init; - this.Window.Update += this.Update; + + this.Window.Update += this.RunLoop; this.Window.Render += this.Draw; this.Window.Initialize(); @@ -49,30 +49,27 @@ public void Run() { throw new PlatformNotSupportedException("Windowing platform doesn't support Vulkan."); } - Logger.Info("Initialize Window..."); - - this.Device = new BlissDevice(this.Vk, this.Window); Logger.Info("Initialize Device..."); + this.Device = new BlissDevice(this.Vk, this.Window); - this.Renderer = new BlissRenderer(this.Vk, this.Window, this.Device, false); Logger.Info("Initialize Renderer..."); + this.Renderer = new BlissRenderer(this.Vk, this.Window, this.Device, false); + Logger.Info("Initialize Global Pool..."); this.GlobalPool = new BlissDescriptorPoolBuilder(this.Vk, this.Device) .SetMaxSets(BlissSwapChain.MaxDefaultFramesInFlight) .AddSize(DescriptorType.UniformBuffer, BlissSwapChain.MaxDefaultFramesInFlight) .Build(); - Logger.Info("Initialize Global Pool..."); + + this.Init(); Logger.Info("Start main Loop..."); this.Window.Run(); this.Vk.DeviceWaitIdle(this.Device.GetVkDevice()); } - - protected virtual void Init() { - - } - - protected virtual void Update(double delta) { + + protected virtual void RunLoop(double delta) { + this.Update(delta); this.AfterUpdate(delta); this._timer += delta; @@ -82,17 +79,15 @@ protected virtual void Update(double delta) { } } - protected virtual void AfterUpdate(double delta) { - - } + protected virtual void Init() { } - protected virtual void FixedUpdate() { - - } + protected virtual void Update(double delta) { } - protected virtual void Draw(double delta) { - - } + protected virtual void AfterUpdate(double delta) { } + + protected virtual void FixedUpdate() { } + + protected virtual void Draw(double delta) { } protected override void Dispose(bool disposing) { if (disposing) { diff --git a/src/Bliss/CSharp/Rendering/Renderable.cs b/src/Bliss/CSharp/Rendering/Renderable.cs new file mode 100644 index 0000000..6f12dfb --- /dev/null +++ b/src/Bliss/CSharp/Rendering/Renderable.cs @@ -0,0 +1,22 @@ +using Bliss.CSharp.Colors; +using Bliss.CSharp.Geometry; +using Bliss.CSharp.Transformations; + +namespace Bliss.CSharp.Rendering; + +public class Renderable { + + public Model Model; + public Color Color; + public Transform Transform; + + public readonly uint Id; + private static uint _ids; + + public Renderable(Model model, Color color, Transform transform) { + this.Id = ++_ids; + this.Model = model; + this.Color = color; + this.Transform = transform; + } +} \ No newline at end of file diff --git a/src/Bliss/CSharp/Rendering/Systems/SimplePushConstantData.cs b/src/Bliss/CSharp/Rendering/Systems/SimplePushConstantData.cs new file mode 100644 index 0000000..0549d24 --- /dev/null +++ b/src/Bliss/CSharp/Rendering/Systems/SimplePushConstantData.cs @@ -0,0 +1,17 @@ +using System.Numerics; + +namespace Bliss.CSharp.Rendering.Systems; + +public struct SimplePushConstantData { + + public Matrix4x4 ModelMatrix; + public Matrix4x4 NormalMatrix; + + /// + /// Represents a container class for simple push constant data used in rendering systems. + /// + public SimplePushConstantData() { + this.ModelMatrix = Matrix4x4.Identity; + this.NormalMatrix = Matrix4x4.Identity; + } +} \ No newline at end of file diff --git a/src/Bliss/CSharp/Rendering/Systems/SimpleRenderSystem.cs b/src/Bliss/CSharp/Rendering/Systems/SimpleRenderSystem.cs new file mode 100644 index 0000000..98610c3 --- /dev/null +++ b/src/Bliss/CSharp/Rendering/Systems/SimpleRenderSystem.cs @@ -0,0 +1,86 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using Bliss.CSharp.Rendering.Vulkan; +using Silk.NET.Vulkan; + +namespace Bliss.CSharp.Rendering.Systems; + +public class SimpleRenderSystem : Disposable { + + public readonly Vk Vk; + public readonly BlissDevice Device; + + private BlissPipeline _pipeline; + private PipelineLayout _pipelineLayout; + + public SimpleRenderSystem(Vk vk, BlissDevice device, RenderPass renderPass, DescriptorSetLayout globalSetLayout) { + this.Vk = vk; + this.Device = device; + + this.CreatePipelineLayout(globalSetLayout); + this.CreatePipeline(renderPass); + } + + public unsafe void Render(FrameInfo frameInfo) { + this._pipeline.Bind(frameInfo.CommandBuffer); + this.Vk.CmdBindDescriptorSets(frameInfo.CommandBuffer, PipelineBindPoint.Graphics, this._pipelineLayout, 0, 1, frameInfo.GlobalDescriptorSet, 0, null); + + foreach (Renderable renderable in frameInfo.RenderableObjects) { + SimplePushConstantData push = new() { + ModelMatrix = renderable.Transform.GetMatrix(), + NormalMatrix = renderable.Transform.GetNormalMatrix() + }; + + this.Vk.CmdPushConstants(frameInfo.CommandBuffer, this._pipelineLayout, ShaderStageFlags.VertexBit | ShaderStageFlags.FragmentBit, 0, (uint) Marshal.SizeOf(), ref push); + + renderable.Model.Bind(frameInfo.CommandBuffer); + renderable.Model.Draw(frameInfo.CommandBuffer); + } + } + + private unsafe void CreatePipelineLayout(DescriptorSetLayout globalSetLayout) { + DescriptorSetLayout[] descriptorSetLayouts = new DescriptorSetLayout[] { + globalSetLayout + }; + + PushConstantRange pushConstantRange = new() { + StageFlags = ShaderStageFlags.VertexBit | ShaderStageFlags.FragmentBit, + Offset = 0, + Size = (uint) Marshal.SizeOf() + }; + + fixed (DescriptorSetLayout* descriptorSetLayoutPtr = descriptorSetLayouts) { + PipelineLayoutCreateInfo pipelineLayoutInfo = new() { + SType = StructureType.PipelineLayoutCreateInfo, + SetLayoutCount = (uint) descriptorSetLayouts.Length, + PSetLayouts = descriptorSetLayoutPtr, + PushConstantRangeCount = 1, + PPushConstantRanges = &pushConstantRange, + }; + + if (this.Vk.CreatePipelineLayout(this.Device.GetVkDevice(), pipelineLayoutInfo, null, out this._pipelineLayout) != Result.Success) { + throw new Exception("Failed to create pipeline layout!"); + } + } + } + + private void CreatePipeline(RenderPass renderPass) { + Debug.Assert(this._pipelineLayout.Handle != 0, "Cannot create pipeline before pipeline layout"); + + PipelineConfigInfo pipelineConfig = new(); + BlissPipeline.GetDefaultPipelineConfigInfo(ref pipelineConfig); + BlissPipeline.EnableMultiSampling(ref pipelineConfig, this.Device.MsaaSamples); + + pipelineConfig.RenderPass = renderPass; + pipelineConfig.PipelineLayout = this._pipelineLayout; + + this._pipeline = new BlissPipeline(this.Vk, this.Device, "simpleShader.vert.spv", "simpleShader.frag.spv", pipelineConfig); + } + + protected override unsafe void Dispose(bool disposing) { + if (disposing) { + this._pipeline.Dispose(); + this.Vk.DestroyPipelineLayout(this.Device.GetVkDevice(), this._pipelineLayout, null); + } + } +} \ No newline at end of file diff --git a/src/Bliss/CSharp/Rendering/Vulkan/BlissPipeline.cs b/src/Bliss/CSharp/Rendering/Vulkan/BlissPipeline.cs index 4c424ce..8f39661 100644 --- a/src/Bliss/CSharp/Rendering/Vulkan/BlissPipeline.cs +++ b/src/Bliss/CSharp/Rendering/Vulkan/BlissPipeline.cs @@ -35,7 +35,7 @@ public BlissPipeline(Vk vk, BlissDevice device, string vertPath, string fragPath /// Retrieves the default pipeline configuration information. /// /// The pipeline configuration information. - public unsafe void GetDefaultPipelineConfigInfo(ref PipelineConfigInfo configInfo) { + public static unsafe void GetDefaultPipelineConfigInfo(ref PipelineConfigInfo configInfo) { configInfo.InputAssemblyInfo.SType = StructureType.PipelineInputAssemblyStateCreateInfo; configInfo.InputAssemblyInfo.Topology = PrimitiveTopology.TriangleList; configInfo.InputAssemblyInfo.PrimitiveRestartEnable = Vk.False; diff --git a/src/Bliss/CSharp/Rendering/Vulkan/FrameInfo.cs b/src/Bliss/CSharp/Rendering/Vulkan/FrameInfo.cs index f361143..cbb07a8 100644 --- a/src/Bliss/CSharp/Rendering/Vulkan/FrameInfo.cs +++ b/src/Bliss/CSharp/Rendering/Vulkan/FrameInfo.cs @@ -9,6 +9,6 @@ public struct FrameInfo { public float FrameTime; public CommandBuffer CommandBuffer; public ICam Camera; - public DescriptorSet DescriptorSet; - //public Dictionary RenderObjects; + public DescriptorSet GlobalDescriptorSet; + public List RenderableObjects; } \ No newline at end of file diff --git a/src/Bliss/CSharp/Transformations/Transform.cs b/src/Bliss/CSharp/Transformations/Transform.cs index d96d7ce..04050cf 100644 --- a/src/Bliss/CSharp/Transformations/Transform.cs +++ b/src/Bliss/CSharp/Transformations/Transform.cs @@ -7,7 +7,7 @@ public struct Transform { /// /// Represents the position of an object in 3D space. /// - public Vector3 Position; + public Vector3 Translation; /// /// Represents the rotation of an object in 3D space. @@ -18,4 +18,38 @@ public struct Transform { /// Represents the scale of an object in 3D space. /// public Vector3 Scale; + + /// + /// Initializes a new instance of the class with default values. + /// + public Transform() { + this.Translation = Vector3.Zero; + this.Rotation = Quaternion.Identity; + this.Scale = Vector3.Zero; + } + + /// + /// Returns the transformation matrix for the current Transform object. + /// + /// The transformation matrix. + public Matrix4x4 GetMatrix() { + Matrix4x4 matTranslate = Matrix4x4.CreateTranslation(this.Translation); + Matrix4x4 matRot = Matrix4x4.CreateFromQuaternion(this.Rotation); + Matrix4x4 matScale = Matrix4x4.CreateScale(this.Scale); + + return matTranslate * matRot * matScale; + } + + /// + /// Returns the normal transformation matrix for the current Transform object. + /// + /// The normal transformation matrix. + public Matrix4x4 GetNormalMatrix() { + Vector3 invScale = new Vector3(1.0F / this.Scale.X, 1.0F / this.Scale.Y, 1.0F / this.Scale.Z); + + Matrix4x4 matScale = Matrix4x4.CreateScale(invScale); + Matrix4x4 matRot = Matrix4x4.CreateFromQuaternion(this.Rotation); + + return matScale * matRot; + } } \ No newline at end of file