forked from terrafx/terrafx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
HelloTransform.cs
174 lines (139 loc) · 8.34 KB
/
HelloTransform.cs
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
// Copyright © Tanner Gooding and Contributors. Licensed under the MIT License (MIT). See License.md in the repository root for more information.
using System;
using System.Reflection;
using TerraFX.ApplicationModel;
using TerraFX.Graphics;
using TerraFX.Numerics;
using static TerraFX.Utilities.UnsafeUtilities;
namespace TerraFX.Samples.Graphics
{
public sealed class HelloTransform : HelloWindow
{
private GraphicsPrimitive _trianglePrimitive = null!;
private GraphicsBuffer _constantBuffer = null!;
private GraphicsBuffer _vertexBuffer = null!;
private float _trianglePrimitiveTranslationX;
public HelloTransform(string name, params Assembly[] compositionAssemblies)
: base(name, compositionAssemblies)
{
}
public override void Cleanup()
{
_trianglePrimitive?.Dispose();
_constantBuffer?.Dispose();
_vertexBuffer?.Dispose();
base.Cleanup();
}
/// <summary>Initializes the GUI for this sample.</summary>
/// <param name="application">The hosting <see cref="Application" />.</param>
/// <param name="timeout">The <see cref="TimeSpan" /> after which this sample should stop running.</param>
/// <param name="windowLocation">The <see cref="Vector2" /> that defines the initial window location.</param>
/// <param name="windowSize">The <see cref="Vector2" /> that defines the initial window client rectangle size.</param>
public override void Initialize(Application application, TimeSpan timeout, Vector2? windowLocation, Vector2? windowSize)
{
base.Initialize(application, timeout, windowLocation, windowSize);
var graphicsDevice = GraphicsDevice;
var currentGraphicsContext = graphicsDevice.CurrentContext;
using var vertexStagingBuffer = graphicsDevice.MemoryAllocator.CreateBuffer(GraphicsBufferKind.Default, GraphicsResourceCpuAccess.CpuToGpu, 64 * 1024);
_constantBuffer = graphicsDevice.MemoryAllocator.CreateBuffer(GraphicsBufferKind.Constant, GraphicsResourceCpuAccess.CpuToGpu, 64 * 1024);
_vertexBuffer = graphicsDevice.MemoryAllocator.CreateBuffer(GraphicsBufferKind.Vertex, GraphicsResourceCpuAccess.GpuOnly, 64 * 1024);
currentGraphicsContext.BeginFrame();
_trianglePrimitive = CreateTrianglePrimitive(currentGraphicsContext, vertexStagingBuffer);
currentGraphicsContext.EndFrame();
graphicsDevice.Signal(currentGraphicsContext.Fence);
graphicsDevice.WaitForIdle();
}
protected override void Draw(GraphicsContext graphicsContext)
{
graphicsContext.Draw(_trianglePrimitive);
base.Draw(graphicsContext);
}
protected override unsafe void Update(TimeSpan delta)
{
const float TranslationSpeed = 1.0f;
const float OffsetBounds = 1.25f;
var trianglePrimitiveTranslationX = _trianglePrimitiveTranslationX;
{
trianglePrimitiveTranslationX += (float)(TranslationSpeed * delta.TotalSeconds);
if (trianglePrimitiveTranslationX > OffsetBounds)
{
trianglePrimitiveTranslationX = -OffsetBounds;
}
}
_trianglePrimitiveTranslationX = trianglePrimitiveTranslationX;
var constantBufferRegion = _trianglePrimitive.InputResourceRegions[1];
var constantBuffer = _constantBuffer;
var pConstantBuffer = constantBuffer.Map<Matrix4x4>(in constantBufferRegion);
// Shaders take transposed matrices, so we want to set X.W
pConstantBuffer[0] = Matrix4x4.Identity.WithX(
new Vector4(1.0f, 0.0f, 0.0f, trianglePrimitiveTranslationX)
);
constantBuffer.UnmapAndWrite(in constantBufferRegion);
}
private unsafe GraphicsPrimitive CreateTrianglePrimitive(GraphicsContext graphicsContext, GraphicsBuffer vertexStagingBuffer)
{
var graphicsDevice = GraphicsDevice;
var graphicsSurface = graphicsDevice.Surface;
var graphicsPipeline = CreateGraphicsPipeline(graphicsDevice, "Transform", "main", "main");
var constantBuffer = _constantBuffer;
var vertexBuffer = _vertexBuffer;
var vertexBufferRegion = CreateVertexBufferRegion(graphicsContext, vertexBuffer, vertexStagingBuffer, aspectRatio: graphicsSurface.Width / graphicsSurface.Height);
graphicsContext.Copy(vertexBuffer, vertexStagingBuffer);
var inputResourceRegions = new GraphicsMemoryRegion<GraphicsResource>[2] {
CreateConstantBufferRegion(graphicsContext, constantBuffer),
CreateConstantBufferRegion(graphicsContext, constantBuffer),
};
return graphicsDevice.CreatePrimitive(graphicsPipeline, vertexBufferRegion, SizeOf<IdentityVertex>(), inputResourceRegions: inputResourceRegions);
static GraphicsMemoryRegion<GraphicsResource> CreateConstantBufferRegion(GraphicsContext graphicsContext, GraphicsBuffer constantBuffer)
{
var constantBufferRegion = constantBuffer.Allocate(SizeOf<Matrix4x4>(), alignment: 256);
var pConstantBuffer = constantBuffer.Map<Matrix4x4>(in constantBufferRegion);
pConstantBuffer[0] = Matrix4x4.Identity;
constantBuffer.UnmapAndWrite(in constantBufferRegion);
return constantBufferRegion;
}
static GraphicsMemoryRegion<GraphicsResource> CreateVertexBufferRegion(GraphicsContext graphicsContext, GraphicsBuffer vertexBuffer, GraphicsBuffer vertexStagingBuffer, float aspectRatio)
{
var vertexBufferRegion = vertexBuffer.Allocate(SizeOf<IdentityVertex>() * 3, alignment: 16);
var pVertexBuffer = vertexStagingBuffer.Map<IdentityVertex>(in vertexBufferRegion);
pVertexBuffer[0] = new IdentityVertex {
Position = new Vector3(0.0f, 0.25f * aspectRatio, 0.0f),
Color = new Vector4(1.0f, 0.0f, 0.0f, 1.0f)
};
pVertexBuffer[1] = new IdentityVertex {
Position = new Vector3(0.25f, -0.25f * aspectRatio, 0.0f),
Color = new Vector4(0.0f, 1.0f, 0.0f, 1.0f)
};
pVertexBuffer[2] = new IdentityVertex {
Position = new Vector3(-0.25f, -0.25f * aspectRatio, 0.0f),
Color = new Vector4(0.0f, 0.0f, 1.0f, 1.0f)
};
vertexStagingBuffer.UnmapAndWrite(in vertexBufferRegion);
return vertexBufferRegion;
}
GraphicsPipeline CreateGraphicsPipeline(GraphicsDevice graphicsDevice, string shaderName, string vertexShaderEntryPoint, string pixelShaderEntryPoint)
{
var signature = CreateGraphicsPipelineSignature(graphicsDevice);
var vertexShader = CompileShader(graphicsDevice, GraphicsShaderKind.Vertex, shaderName, vertexShaderEntryPoint);
var pixelShader = CompileShader(graphicsDevice, GraphicsShaderKind.Pixel, shaderName, pixelShaderEntryPoint);
return graphicsDevice.CreatePipeline(signature, vertexShader, pixelShader);
}
static GraphicsPipelineSignature CreateGraphicsPipelineSignature(GraphicsDevice graphicsDevice)
{
var inputs = new GraphicsPipelineInput[1] {
new GraphicsPipelineInput(
new GraphicsPipelineInputElement[2] {
new GraphicsPipelineInputElement(typeof(Vector3), GraphicsPipelineInputElementKind.Position, size: 12),
new GraphicsPipelineInputElement(typeof(Vector4), GraphicsPipelineInputElementKind.Color, size: 16),
}
),
};
var resources = new GraphicsPipelineResource[2] {
new GraphicsPipelineResource(GraphicsPipelineResourceKind.ConstantBuffer, GraphicsShaderVisibility.Vertex),
new GraphicsPipelineResource(GraphicsPipelineResourceKind.ConstantBuffer, GraphicsShaderVisibility.Vertex),
};
return graphicsDevice.CreatePipelineSignature(inputs, resources);
}
}
}
}