diff --git a/Mafia2Libs/Forms/MapEditor.cs b/Mafia2Libs/Forms/MapEditor.cs index 7e5d9fcd..05d4ab33 100644 --- a/Mafia2Libs/Forms/MapEditor.cs +++ b/Mafia2Libs/Forms/MapEditor.cs @@ -1138,7 +1138,7 @@ private void BuildRenderObjects() translokatorRoot.Nodes.Add(gridNode); dSceneTree.AddToTree(translokatorRoot); - //Graphics.SetTranslokatorGrid(SceneData.Translokator); + Graphics.SetTranslokatorGrid(SceneData.Translokator); } } diff --git a/Mafia2Libs/Rendering/Graphics/GraphicsClass.cs b/Mafia2Libs/Rendering/Graphics/GraphicsClass.cs index 8a6ee4d9..f71b9e66 100644 --- a/Mafia2Libs/Rendering/Graphics/GraphicsClass.cs +++ b/Mafia2Libs/Rendering/Graphics/GraphicsClass.cs @@ -50,7 +50,7 @@ public class GraphicsClass private DirectX11Class D3D; - private SpatialGrid translokatorGrid; + private TranslokatorSpatialGrid translokatorGrid; private SpatialGrid[] navigationGrids; // Local batches for objects passed through @@ -68,7 +68,7 @@ public GraphicsClass() Profile = new Profiler(); Assets = new Dictionary(); selectionBox = new RenderBoundingBox(); - translokatorGrid = new SpatialGrid(); + translokatorGrid = new TranslokatorSpatialGrid(); navigationGrids = new SpatialGrid[0]; OurPrimitiveManager = new PrimitiveManager(); @@ -153,11 +153,11 @@ public bool InitScene(int width, int height) return true; } - public TreeNode SetTranslokatorGrid(TranslokatorLoader translokator) + public void SetTranslokatorGrid(TranslokatorLoader translokator) { - translokatorGrid = new SpatialGrid(this, translokator); + translokatorGrid = new TranslokatorSpatialGrid(translokator); translokatorGrid.Initialise(D3D.Device, D3D.DeviceContext); - return translokatorGrid.GetTreeNodes(); + //return translokatorGrid.GetTreeNodes(); } public TreeNode SetNavigationGrid(ResourceTypes.Navigation.OBJData[] data) diff --git a/Mafia2Libs/Rendering/Graphics/RenderTypes/IRenderer.cs b/Mafia2Libs/Rendering/Graphics/RenderTypes/IRenderer.cs index e83c21cd..efe56f8a 100644 --- a/Mafia2Libs/Rendering/Graphics/RenderTypes/IRenderer.cs +++ b/Mafia2Libs/Rendering/Graphics/RenderTypes/IRenderer.cs @@ -15,6 +15,7 @@ public abstract class IRenderer protected ID3D11ShaderResourceView instanceBufferView; public bool DoRender { get; set; } + public bool DoRenderInstancesOnly { get; set; } public Matrix4x4 Transform { get; protected set; } public BoundingBox BoundingBox { get; protected set; } diff --git a/Mafia2Libs/Rendering/Graphics/RenderTypes/RenderBoundingBox.cs b/Mafia2Libs/Rendering/Graphics/RenderTypes/RenderBoundingBox.cs index db0471ca..c9621e64 100644 --- a/Mafia2Libs/Rendering/Graphics/RenderTypes/RenderBoundingBox.cs +++ b/Mafia2Libs/Rendering/Graphics/RenderTypes/RenderBoundingBox.cs @@ -1,5 +1,9 @@ -using System.Numerics; +using Rendering.Core; +using System; +using System.Collections.Generic; +using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using Vortice; using Vortice.Direct3D; using Vortice.Direct3D11; @@ -22,6 +26,7 @@ public class RenderBoundingBox : IRenderer private VertexLayouts.BasicLayout.Vertex[] vertices; private Color CurrentColour; private Color UnselectedColour; + private List InstanceTransforms = new(); public RenderBoundingBox() { @@ -73,6 +78,73 @@ public override void InitBuffers(ID3D11Device d3d, ID3D11DeviceContext deviceCon { vertexBuffer = d3d.CreateBuffer(BindFlags.VertexBuffer, vertices, 0, ResourceUsage.Dynamic, CpuAccessFlags.Write); indexBuffer = d3d.CreateBuffer(BindFlags.IndexBuffer, Indices, 0, ResourceUsage.Dynamic, CpuAccessFlags.Write); + + InitInstanceBuffer(d3d); + } + + public void InitInstanceBuffer(ID3D11Device d3d) + { + int newSize = InstanceTransforms.Count * Marshal.SizeOf(); + + if (InstanceTransforms.Count == 0) + { + return; + } + + // Create or update buffer only if necessary + if (instanceBuffer == null || instanceBuffer.Description.SizeInBytes < newSize) + { + // Buffer description for instance buffer + var bufferDescription = new BufferDescription + { + SizeInBytes = newSize, + Usage = ResourceUsage.Dynamic, + BindFlags = BindFlags.ShaderResource, + OptionFlags = ResourceOptionFlags.BufferStructured, + CpuAccessFlags = CpuAccessFlags.Write, + StructureByteStride = Marshal.SizeOf(), + }; + + var viewDescription = new ShaderResourceViewDescription() + { + Format = Vortice.DXGI.Format.Unknown, + ViewDimension = ShaderResourceViewDimension.Buffer, + }; + + viewDescription.Buffer.FirstElement = 0; + viewDescription.Buffer.NumElements = InstanceTransforms.Count; + + // Dispose old buffer if necessary + instanceBuffer?.Dispose(); + + // Convert list to array + Matrix4x4[] transformsArray = InstanceTransforms.ToArray(); + + // Pin the array in memory + GCHandle handle = GCHandle.Alloc(transformsArray, GCHandleType.Pinned); + try + { + IntPtr pointer = handle.AddrOfPinnedObject(); + // Update the instance buffer + instanceBuffer = d3d.CreateBuffer(bufferDescription, pointer); + + instanceBufferView = d3d.CreateShaderResourceView(instanceBuffer, viewDescription); + } + finally + { + handle.Free(); + } + } + } + + public void ReloadInstanceBuffer(ID3D11Device d3d) + { + instanceBuffer?.Dispose(); + instanceBuffer = null; + instanceBufferView?.Dispose(); + instanceBufferView = null; + + InitInstanceBuffer(d3d); } public void SetColour(Color newColour, bool update = false) @@ -95,18 +167,51 @@ public override void Render(ID3D11Device device, ID3D11DeviceContext deviceConte return; } + bool BuffersSet = false; + + if (InstanceTransforms.Count > 0) + { + VertexBufferView VertexBufferView = new VertexBufferView(vertexBuffer, Unsafe.SizeOf(), 0); + deviceContext.IASetVertexBuffers(0, VertexBufferView); + deviceContext.IASetIndexBuffer(indexBuffer, Vortice.DXGI.Format.R32_UInt, 0); + deviceContext.IASetPrimitiveTopology(PrimitiveTopology.LineList); + + BuffersSet = true; + + RenderInstances(deviceContext, camera, device); + } + + if (DoRenderInstancesOnly) + { + return; + } + if (!camera.CheckBBoxFrustum(Transform, BoundingBox)) return; - VertexBufferView VertexBufferView = new VertexBufferView(vertexBuffer, Unsafe.SizeOf(), 0); - deviceContext.IASetVertexBuffers(0, VertexBufferView); - deviceContext.IASetIndexBuffer(indexBuffer, Vortice.DXGI.Format.R32_UInt, 0); - deviceContext.IASetPrimitiveTopology(PrimitiveTopology.LineList); + if (!BuffersSet) + { + VertexBufferView VertexBufferView = new VertexBufferView(vertexBuffer, Unsafe.SizeOf(), 0); + deviceContext.IASetVertexBuffers(0, VertexBufferView); + deviceContext.IASetIndexBuffer(indexBuffer, Vortice.DXGI.Format.R32_UInt, 0); + deviceContext.IASetPrimitiveTopology(PrimitiveTopology.LineList); + BuffersSet = true; + } shader.SetSceneVariables(deviceContext, Transform, camera); shader.Render(deviceContext, PrimitiveTopology.LineList, ReadOnlyIndices.Length, 0); } + public void RenderInstances(ID3D11DeviceContext deviceContext, Camera camera, ID3D11Device device) + { + deviceContext.VSSetShaderResource(0, instanceBufferView); + + shader.SetSceneVariables(deviceContext, Transform, camera); + + shader.RenderInstanced(deviceContext, PrimitiveTopology.LineList, Indices.Length, 0, InstanceTransforms.Count); + Profiler.NumDrawCallsThisFrame++; + } + public override void Shutdown() { vertices = null; @@ -165,5 +270,10 @@ public VertexLayouts.BasicLayout.Vertex[] GetTransformVertices() return NewVertices; } + + public void SetInstanceTransforms(List Transforms) + { + InstanceTransforms = Transforms; + } } } \ No newline at end of file diff --git a/Mafia2Libs/Rendering/Graphics/ShaderManager.cs b/Mafia2Libs/Rendering/Graphics/ShaderManager.cs index 6dea6d1c..e06282a8 100644 --- a/Mafia2Libs/Rendering/Graphics/ShaderManager.cs +++ b/Mafia2Libs/Rendering/Graphics/ShaderManager.cs @@ -24,7 +24,7 @@ public bool Init(ID3D11Device device) DebugInitParams.Elements = VertexLayouts.BasicLayout.GetLayout(); DebugInitParams.PixelShaderFile = new ShaderInitParams.ShaderFileEntryPoint("DebugPS.hlsl", "DebugPixelShader", "ps_5_0"); DebugInitParams.VertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("DebugVS.hlsl", "DebugVertexShader", "vs_5_0"); - DefaultInitParams.InstancedVertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightVS.hlsl", "LightInstanceVertexShader", "vs_5_0"); + DebugInitParams.InstancedVertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("DebugVS.hlsl", "DebugInstanceVertexShader", "vs_5_0"); DebugShader OurDebugShader = new DebugShader(device, DebugInitParams); @@ -33,7 +33,7 @@ public bool Init(ID3D11Device device) CollisionInitParams.Elements = VertexLayouts.CollisionLayout.GetLayout(); CollisionInitParams.PixelShaderFile = new ShaderInitParams.ShaderFileEntryPoint("CollisionPS.hlsl", "CollisionShader", "ps_5_0"); CollisionInitParams.VertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("CollisionVS.hlsl", "CollisionShader", "vs_5_0"); - DefaultInitParams.InstancedVertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightVS.hlsl", "LightInstanceVertexShader", "vs_5_0"); + CollisionInitParams.InstancedVertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightVS.hlsl", "LightInstanceVertexShader", "vs_5_0"); CollisionShader OurCollisionShader = new CollisionShader(device, CollisionInitParams); @@ -42,7 +42,7 @@ public bool Init(ID3D11Device device) Shader601151254_InitParams.Elements = VertexLayouts.NormalLayout.GetLayout(); Shader601151254_InitParams.PixelShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightPS.hlsl", "PS_601151254", "ps_5_0"); Shader601151254_InitParams.VertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightVS.hlsl", "LightVertexShader", "vs_5_0"); - DefaultInitParams.InstancedVertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightVS.hlsl", "LightInstanceVertexShader", "vs_5_0"); + Shader601151254_InitParams.InstancedVertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightVS.hlsl", "LightInstanceVertexShader", "vs_5_0"); Shader_601151254 OurShader601151254 = new Shader_601151254(device, Shader601151254_InitParams); @@ -51,7 +51,7 @@ public bool Init(ID3D11Device device) Shader_50760736_InitParams.Elements = VertexLayouts.NormalLayout.GetLayout(); Shader_50760736_InitParams.PixelShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightPS.hlsl", "PS_50760736", "ps_5_0"); Shader_50760736_InitParams.VertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightVS.hlsl", "LightVertexShader", "vs_5_0"); - DefaultInitParams.InstancedVertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightVS.hlsl", "LightInstanceVertexShader", "vs_5_0"); + Shader_50760736_InitParams.InstancedVertexShaderFile = new ShaderInitParams.ShaderFileEntryPoint("LightVS.hlsl", "LightInstanceVertexShader", "vs_5_0"); Shader_50760736 OurShader50760736 = new Shader_50760736(device, Shader_50760736_InitParams); diff --git a/Mafia2Libs/Rendering/Graphics/Shaders/DebugShader.cs b/Mafia2Libs/Rendering/Graphics/Shaders/DebugShader.cs index d9b02da2..196ef8fe 100644 --- a/Mafia2Libs/Rendering/Graphics/Shaders/DebugShader.cs +++ b/Mafia2Libs/Rendering/Graphics/Shaders/DebugShader.cs @@ -35,6 +35,37 @@ public override void Render(ID3D11DeviceContext deviceContext, PrimitiveTopology Profiler.NumDrawCallsThisFrame++; } + public override void RenderInstanced(ID3D11DeviceContext context, PrimitiveTopology type, int size, int offset, int count) + { + context.IASetInputLayout(Layout); + + // set shaders only if available + if (OurInstanceVertexShader != null) + { + context.VSSetShader(OurInstanceVertexShader); + } + + if (OurInstanceVertexShader != null) + { + context.PSSetShader(OurPixelShader); + } + + switch (type) + { + case PrimitiveTopology.LineList: + case PrimitiveTopology.TriangleList: + context.DrawIndexedInstanced(size, count, offset, 0, 0); + break; + case PrimitiveTopology.LineStrip: + //context.Draw(size, 0); + break; + default: + break; + } + + Profiler.NumDrawCallsThisFrame++; + } + public override void SetShaderParameters(ID3D11Device device, ID3D11DeviceContext context, MaterialParameters material) { //empty diff --git a/Mafia2Libs/Rendering/Spatial/TranslokatorSpatialGrid.cs b/Mafia2Libs/Rendering/Spatial/TranslokatorSpatialGrid.cs new file mode 100644 index 00000000..098284d3 --- /dev/null +++ b/Mafia2Libs/Rendering/Spatial/TranslokatorSpatialGrid.cs @@ -0,0 +1,163 @@ +using Rendering.Graphics; +using ResourceTypes.Translokator; +using System.Collections.Generic; +using System.Numerics; +using Vortice.Direct3D11; +using Vortice.Mathematics; + +namespace Rendering.Core +{ + public class TranslokatorSpatialGrid + { + // TODO: Make cells selectable and toggleable + // Right now all cells render at once and you can't see anything + + private BoundingBox gridBounds; + private BoundingBox[] cellBounds = new BoundingBox[0]; + private RenderBoundingBox boundingBox; + private RenderBoundingBox[] cellBoundingBox = new RenderBoundingBox[0]; + private bool bIsReady = false; + public TranslokatorSpatialGrid() + { + + } + + public TranslokatorSpatialGrid(TranslokatorLoader translokator) + { + bIsReady = true; + + gridBounds = translokator.Bounds; + Vector3 origin = gridBounds.Min; + + cellBounds = new BoundingBox[translokator.Grids.Length]; + cellBoundingBox = new RenderBoundingBox[translokator.Grids.Length]; + + for (int k = 0; k < translokator.Grids.Length; k++) + { + List CellTransforms = new(); + + int width = translokator.Grids[k].Width; + int height = translokator.Grids[k].Height; + var cellSize = translokator.Grids[k].CellSize; + + Vector3 Min = new Vector3(0.0f); + Vector3 Max = new Vector3(cellSize.X, cellSize.Y, gridBounds.Depth); + + cellBounds[k] = new(Min, Max); + cellBoundingBox[k] = new(); + + for (int i = 0; i < height; i++) + { + for (int x = 0; x < width; x++) + { + Vector3 Position = new Vector3(origin.X + cellSize.X * x, origin.Y + cellSize.Y * i, origin.Z); + Matrix4x4 transform = Matrix4x4.Identity; + transform.Translation = Position; + CellTransforms.Add(Matrix4x4.Transpose(transform)); + } + } + + cellBoundingBox[k].SetInstanceTransforms(CellTransforms); + } + + + /*for (int i = 0; i != translokator.ObjectGroups.Length; i++) + { + ObjectGroup objectGroup = translokator.ObjectGroups[i]; + + for (int x = 0; x != objectGroup.NumObjects; x++) + { + ResourceTypes.Translokator.Object obj = objectGroup.Objects[x]; + + for (int y = 0; y != obj.NumInstances; y++) + { + Instance instance = obj.Instances[y]; + var cell = GetCell(instance.Position); + RenderBoundingBox box = new RenderBoundingBox(); + box.SetTransform(Matrix4x4.CreateTranslation(instance.Position)); + box.Init(new BoundingBox(-Vector3.One, Vector3.One)); + cells[cell].AddAsset(box, RefManager.GetNewRefID()); + } + } + }*/ + } + + public void Initialise(ID3D11Device device, ID3D11DeviceContext deviceContext) + { + if (bIsReady) + { + boundingBox = new RenderBoundingBox(); + boundingBox.SetColour(System.Drawing.Color.Red, true); + boundingBox.Init(gridBounds); + boundingBox.InitBuffers(device, deviceContext); + + + for (int i = 0; i < cellBoundingBox.Length; i++) + { + cellBoundingBox[i].SetColour(System.Drawing.Color.Blue, true); + cellBoundingBox[i].Init(cellBounds[i]); + cellBoundingBox[i].InitBuffers(device, deviceContext); + cellBoundingBox[i].DoRenderInstancesOnly = true; + } + } + } + + public void Render(ID3D11Device device, ID3D11DeviceContext deviceContext, Camera camera) + { + foreach (var cell in cellBoundingBox) + { + cell.Render(device, deviceContext, camera); + //break; + } + + boundingBox.Render(device, deviceContext, camera); + } + + public void Shutdown() + { + boundingBox?.Shutdown(); + + foreach (var cell in cellBoundingBox) + { + cell?.Shutdown(); + } + } + + //private int GetCell(Vector3 position) + //{ + // var offsetX = position.X - origin.X; + // var offsetY = position.Y - origin.Y; + // var gridX = Math.Abs(Math.Floor(offsetX / cellSize.X)); + // var gridY = Math.Abs(Math.Floor(offsetY / cellSize.Y)); + // var intX = Convert.ToUInt32(Math.Min(gridX, width - 1)); + // var intY = Convert.ToUInt32(Math.Min(gridY, height - 1)); + // return (int)(intX + (int)(intY * width)); + //} + + //public void SetSelectedCell(int index) + //{ + // currentCell = index; + //} + + //public TreeNode GetTreeNodes() + //{ + // TreeNode[] ChildCells = new TreeNode[cells.Length]; + // + // for (int i = 0; i < cells.Length; i++) + // { + // TreeNode Child = new TreeNode(); + // Child.Text = string.Format("CELL {0}", i); + // Child.Name = cells[i].GetRefID().ToString(); + // Child.Tag = cells[i]; + // ChildCells[i] = Child; + // } + // + // TreeNode Parent = new TreeNode(); + // Parent.Text = string.Format("Parent"); + // Parent.Tag = this; + // Parent.Nodes.AddRange(ChildCells); + // + // return Parent; + //} + } +} diff --git a/Mafia2Libs/Shaders/DebugVS.hlsl b/Mafia2Libs/Shaders/DebugVS.hlsl index d8f1328e..84358f11 100644 --- a/Mafia2Libs/Shaders/DebugVS.hlsl +++ b/Mafia2Libs/Shaders/DebugVS.hlsl @@ -4,6 +4,9 @@ cbuffer MatrixBuffer matrix viewProjectionMatrix; }; +// Instance transformation matrix buffer +StructuredBuffer InstanceBuffer : register(t0); + struct VS_INPUT { float4 Position : POSITION; @@ -28,5 +31,23 @@ VS_OUTPUT DebugVertexShader(VS_INPUT input) output.Position = mul(output.Position, viewProjectionMatrix); output.Colour = input.Colour.bgra; + return output; +} + +VS_OUTPUT DebugInstanceVertexShader(VS_INPUT input, uint InstanceId : SV_InstanceID) +{ + VS_OUTPUT output; + + // Fetch the instance transformation matrix using InstanceID + matrix instanceMatrix = InstanceBuffer[InstanceId]; + + // Change the position vector to be 4 units for proper matrix calculations. + input.Position.w = 1.0f; + + // Calculate the position of the vertex against the instance, view, and projection matrices. + output.Position = mul(input.Position, instanceMatrix); + output.Position = mul(output.Position, viewProjectionMatrix); + output.Colour = input.Colour.bgra; + return output; } \ No newline at end of file