-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRenderer.cs
More file actions
246 lines (199 loc) · 8.35 KB
/
Renderer.cs
File metadata and controls
246 lines (199 loc) · 8.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
using Veldrid;
using Veldrid.SPIRV;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
namespace VeldridRaylib
{
/// <summary>
/// Vertex structure for rendering
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Vertex
{
public Vector2 Position;
public Vector4 Color;
public Vertex(Vector2 position, Vector4 color)
{
Position = position;
Color = color;
}
}
/// <summary>
/// Projection matrix uniform buffer
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ProjectionBuffer
{
public Matrix4x4 Projection;
public ProjectionBuffer(Matrix4x4 projection)
{
Projection = projection;
}
}
/// <summary>
/// Core renderer for 2D graphics using Veldrid interfaces for maximum cross-compatibility
/// </summary>
public class Renderer : IDisposable
{
private readonly GraphicsDevice _graphicsDevice;
private readonly CommandList _commandList;
private readonly DeviceBuffer _vertexBuffer;
private readonly DeviceBuffer _indexBuffer;
private readonly DeviceBuffer _projectionBuffer;
private readonly ResourceSet _projectionResourceSet;
private readonly Pipeline _pipeline;
private readonly ResourceLayout _projectionLayout;
private readonly List<Vertex> _vertices = new();
private readonly List<uint> _indices = new();
private uint _currentIndex = 0;
private RgbaFloat _clearColor = RgbaFloat.Black;
public Renderer(GraphicsDevice graphicsDevice)
{
_graphicsDevice = graphicsDevice ?? throw new ArgumentNullException(nameof(graphicsDevice));
// Initialize command list
_commandList = _graphicsDevice.ResourceFactory.CreateCommandList();
// Create shaders using cross-platform approach
var shaderSet = CreateShaders(_graphicsDevice);
// Create vertex buffer
_vertexBuffer = _graphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription(
1024 * (uint)Marshal.SizeOf<Vertex>(), BufferUsage.VertexBuffer | BufferUsage.Dynamic));
// Create index buffer
_indexBuffer = _graphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription(
1024 * sizeof(uint), BufferUsage.IndexBuffer | BufferUsage.Dynamic));
// Create projection buffer
_projectionBuffer = _graphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription(
(uint)Marshal.SizeOf<ProjectionBuffer>(), BufferUsage.UniformBuffer | BufferUsage.Dynamic));
// Create resource layout - use consistent naming for all backends
_projectionLayout = _graphicsDevice.ResourceFactory.CreateResourceLayout(
new ResourceLayoutDescription(
new ResourceLayoutElementDescription("ProjectionBuffer", ResourceKind.UniformBuffer, ShaderStages.Vertex)));
_projectionResourceSet = _graphicsDevice.ResourceFactory.CreateResourceSet(new ResourceSetDescription(
_projectionLayout, _projectionBuffer));
// Create pipeline using cross-compatible vertex layout
var vertexLayout = new VertexLayoutDescription(
new VertexElementDescription("Position", VertexElementSemantic.Position, VertexElementFormat.Float2),
new VertexElementDescription("Color", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float4));
var pipelineDescription = new GraphicsPipelineDescription()
{
BlendState = BlendStateDescription.SingleAlphaBlend,
DepthStencilState = DepthStencilStateDescription.Disabled,
RasterizerState = RasterizerStateDescription.Default,
PrimitiveTopology = PrimitiveTopology.TriangleList,
ResourceLayouts = new[] { _projectionLayout },
ShaderSet = new Veldrid.ShaderSetDescription(
new[] { vertexLayout },
shaderSet),
Outputs = _graphicsDevice.SwapchainFramebuffer.OutputDescription
};
_pipeline = _graphicsDevice.ResourceFactory.CreateGraphicsPipeline(pipelineDescription);
}
private Shader[] CreateShaders(GraphicsDevice device)
{
// Use GLSL 450 shaders compiled to SPIR-V for maximum cross-platform compatibility
string vertexShaderSource = @"
#version 450
layout(location = 0) in vec2 Position;
layout(location = 1) in vec4 Color;
layout(set = 0, binding = 0) uniform ProjectionBuffer
{
mat4 Projection;
};
layout(location = 0) out vec4 fsin_Color;
void main()
{
gl_Position = Projection * vec4(Position, 0, 1);
fsin_Color = Color;
}";
string fragmentShaderSource = @"
#version 450
layout(location = 0) in vec4 fsin_Color;
layout(location = 0) out vec4 fsout_Color;
void main()
{
fsout_Color = fsin_Color;
}";
// Compile GLSL to SPIR-V using Veldrid.SPIRV
var vertexShaderDesc = new ShaderDescription(
ShaderStages.Vertex,
Encoding.UTF8.GetBytes(vertexShaderSource),
"main");
var fragmentShaderDesc = new ShaderDescription(
ShaderStages.Fragment,
Encoding.UTF8.GetBytes(fragmentShaderSource),
"main");
// Use SPIR-V cross-compilation
var shaders = device.ResourceFactory.CreateFromSpirv(vertexShaderDesc, fragmentShaderDesc);
return shaders;
}
public void SetProjection(Matrix4x4 projection)
{
_graphicsDevice.UpdateBuffer(_projectionBuffer, 0, new ProjectionBuffer(projection));
}
public void SetClearColor(RgbaFloat clearColor)
{
_clearColor = clearColor;
}
public RgbaFloat GetClearColor()
{
return _clearColor;
}
public void BeginFrame()
{
_vertices.Clear();
_indices.Clear();
_currentIndex = 0;
}
public void DrawTriangle(Vector2 p1, Vector2 p2, Vector2 p3, Color color)
{
var colorVec = color.ToVector4();
_vertices.Add(new Vertex(p1, colorVec));
_vertices.Add(new Vertex(p2, colorVec));
_vertices.Add(new Vertex(p3, colorVec));
_indices.Add(_currentIndex);
_indices.Add(_currentIndex + 1);
_indices.Add(_currentIndex + 2);
_currentIndex += 3;
}
public void DrawQuad(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, Color color)
{
var colorVec = color.ToVector4();
_vertices.Add(new Vertex(p1, colorVec));
_vertices.Add(new Vertex(p2, colorVec));
_vertices.Add(new Vertex(p3, colorVec));
_vertices.Add(new Vertex(p4, colorVec));
// First triangle
_indices.Add(_currentIndex);
_indices.Add(_currentIndex + 1);
_indices.Add(_currentIndex + 2);
// Second triangle
_indices.Add(_currentIndex);
_indices.Add(_currentIndex + 2);
_indices.Add(_currentIndex + 3);
_currentIndex += 4;
}
public void Flush(CommandList commandList)
{
if (_vertices.Count == 0) return;
// Update buffers
_graphicsDevice.UpdateBuffer(_vertexBuffer, 0, _vertices.ToArray());
_graphicsDevice.UpdateBuffer(_indexBuffer, 0, _indices.ToArray());
// Draw
commandList.SetVertexBuffer(0, _vertexBuffer);
commandList.SetIndexBuffer(_indexBuffer, IndexFormat.UInt32);
commandList.SetPipeline(_pipeline);
commandList.SetGraphicsResourceSet(0, _projectionResourceSet);
commandList.DrawIndexed((uint)_indices.Count);
}
public CommandList GetCommandList() => _commandList;
public void Dispose()
{
_vertexBuffer?.Dispose();
_indexBuffer?.Dispose();
_projectionBuffer?.Dispose();
_projectionResourceSet?.Dispose();
_pipeline?.Dispose();
_commandList?.Dispose();
}
}
}