Skip to content

Commit ae35ac8

Browse files
authored
Merge pull request #11 from DarthAffe/DisplayRotation
Display rotation
2 parents 3e7550a + 466f844 commit ae35ac8

File tree

5 files changed

+122
-11
lines changed

5 files changed

+122
-11
lines changed

ScreenCapture.NET/DirectX/DX11ScreenCapture.cs

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4-
using System.Runtime.InteropServices;
4+
using System.Runtime.CompilerServices;
55
using System.Threading;
66
using SharpGen.Runtime;
77
using Vortice.Direct3D;
@@ -184,13 +184,26 @@ private void UpdateZones()
184184
captureZone.Y + captureZone.UnscaledHeight, 1));
185185

186186
MappedSubresource mapSource = _context.Map(stagingTexture, 0, MapMode.Read, MapFlags.None);
187-
IntPtr sourcePtr = mapSource.DataPointer;
188187
lock (captureZone.Buffer)
189188
{
190-
for (int y = 0; y < captureZone.Height; y++)
189+
Span<byte> source = mapSource.AsSpan(captureZone.Stride * captureZone.Height);
190+
switch (Display.Rotation)
191191
{
192-
Marshal.Copy(sourcePtr, captureZone.Buffer, y * captureZone.Stride, captureZone.Stride);
193-
sourcePtr += mapSource.RowPitch;
192+
case Rotation.Rotation90:
193+
CopyRotate90(source, captureZone);
194+
break;
195+
196+
case Rotation.Rotation180:
197+
CopyRotate180(source, captureZone);
198+
break;
199+
200+
case Rotation.Rotation270:
201+
CopyRotate270(source, captureZone);
202+
break;
203+
204+
default:
205+
CopyRotate0(source, captureZone);
206+
break;
194207
}
195208
}
196209

@@ -200,11 +213,74 @@ private void UpdateZones()
200213
}
201214
}
202215

216+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
217+
private static void CopyRotate0(in Span<byte> source, in CaptureZone captureZone) => source.CopyTo(captureZone.Buffer.AsSpan());
218+
219+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
220+
private static void CopyRotate90(in Span<byte> source, in CaptureZone captureZone)
221+
{
222+
int width = captureZone.Width;
223+
int height = captureZone.Height;
224+
Span<byte> destination = captureZone.Buffer.AsSpan();
225+
226+
for (int y = 0; y < height; y++)
227+
for (int x = 0; x < width; x++)
228+
{
229+
int offset = ((y * width) + x) * BPP;
230+
int destinationOffset = ((x * height) + ((height - 1) - y)) * BPP;
231+
destination[destinationOffset] = source[offset];
232+
destination[destinationOffset + 1] = source[offset + 1];
233+
destination[destinationOffset + 2] = source[offset + 2];
234+
destination[destinationOffset + 3] = source[offset + 3];
235+
}
236+
}
237+
238+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
239+
private static void CopyRotate180(in Span<byte> source, in CaptureZone captureZone)
240+
{
241+
int width = captureZone.Width;
242+
int height = captureZone.Height;
243+
Span<byte> destination = captureZone.Buffer.AsSpan();
244+
245+
for (int y = 0; y < height; y++)
246+
for (int x = 0; x < width; x++)
247+
{
248+
int offset = ((y * width) + x) * BPP;
249+
int destinationOffset = destination.Length - offset;
250+
destination[destinationOffset - 4] = source[offset];
251+
destination[destinationOffset - 3] = source[offset + 1];
252+
destination[destinationOffset - 2] = source[offset + 2];
253+
destination[destinationOffset - 1] = source[offset + 3];
254+
}
255+
}
256+
257+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
258+
private static void CopyRotate270(in Span<byte> source, in CaptureZone captureZone)
259+
{
260+
int width = captureZone.Width;
261+
int height = captureZone.Height;
262+
Span<byte> destination = captureZone.Buffer.AsSpan();
263+
264+
for (int y = 0; y < height; y++)
265+
for (int x = 0; x < width; x++)
266+
{
267+
int offset = ((y * width) + x) * BPP;
268+
int destinationOffset = ((((width - 1) - x) * height) + y) * BPP;
269+
destination[destinationOffset] = source[offset];
270+
destination[destinationOffset + 1] = source[offset + 1];
271+
destination[destinationOffset + 2] = source[offset + 2];
272+
destination[destinationOffset + 3] = source[offset + 3];
273+
}
274+
}
275+
203276
/// <inheritdoc />
204277
public CaptureZone RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel = 0)
205278
{
206279
ValidateCaptureZoneAndThrow(x, y, width, height);
207280

281+
if (Display.Rotation is Rotation.Rotation90 or Rotation.Rotation270)
282+
(x, y, width, height) = (y, x, height, width);
283+
208284
int unscaledWidth = width;
209285
int unscaledHeight = height;
210286
(width, height) = CalculateScaledSize(unscaledWidth, unscaledHeight, downscaleLevel);
@@ -252,6 +328,9 @@ public void UpdateCaptureZone(CaptureZone captureZone, int? x = null, int? y = n
252328

253329
ValidateCaptureZoneAndThrow(newX, newY, newUnscaledWidth, newUnscaledHeight);
254330

331+
if (Display.Rotation is Rotation.Rotation90 or Rotation.Rotation270)
332+
(newX, newY, newUnscaledWidth, newUnscaledHeight) = (newY, newX, newUnscaledHeight, newUnscaledWidth);
333+
255334
captureZone.X = newX;
256335
captureZone.Y = newY;
257336

@@ -361,13 +440,18 @@ public void Restart()
361440
_output = adapter.GetOutput(Display.Index) ?? throw new ApplicationException("Couldn't get DirectX-Output.");
362441
using IDXGIOutput5 output = _output.QueryInterface<IDXGIOutput5>();
363442

443+
int width = Display.Width;
444+
int height = Display.Height;
445+
if (Display.Rotation is Rotation.Rotation90 or Rotation.Rotation270)
446+
(width, height) = (height, width);
447+
364448
Texture2DDescription captureTextureDesc = new()
365449
{
366450
CPUAccessFlags = CpuAccessFlags.None,
367451
BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
368452
Format = Format.B8G8R8A8_UNorm,
369-
Width = Display.Width,
370-
Height = Display.Height,
453+
Width = width,
454+
Height = height,
371455
MiscFlags = ResourceOptionFlags.None,
372456
MipLevels = 1,
373457
ArraySize = 1,

ScreenCapture.NET/DirectX/DX11ScreenCaptureService.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,20 @@ public IEnumerable<Display> GetDisplays(GraphicsCard graphicsCard)
5353
{
5454
int width = output.Description.DesktopCoordinates.Right - output.Description.DesktopCoordinates.Left;
5555
int height = output.Description.DesktopCoordinates.Bottom - output.Description.DesktopCoordinates.Top;
56-
yield return new Display(i, output.Description.DeviceName, width, height, graphicsCard);
56+
yield return new Display(i, output.Description.DeviceName, width, height, GetRotation(output.Description.Rotation), graphicsCard);
5757
output.Dispose();
5858
i++;
5959
}
6060
}
6161

62+
private Rotation GetRotation(ModeRotation rotation) => rotation switch
63+
{
64+
ModeRotation.Rotate90 => Rotation.Rotation90,
65+
ModeRotation.Rotate180 => Rotation.Rotation180,
66+
ModeRotation.Rotate270 => Rotation.Rotation270,
67+
_ => Rotation.None
68+
};
69+
6270
/// <inheritdoc />
6371
public IScreenCapture GetScreenCapture(Display display)
6472
{

ScreenCapture.NET/Model/Display.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ public readonly struct Display
3131
/// </summary>
3232
public int Height { get; }
3333

34+
/// <summary>
35+
/// Gets the rotation of the <see cref="Display"/>.
36+
/// </summary>
37+
public Rotation Rotation { get; }
38+
3439
/// <summary>
3540
/// Gets the <see cref="GraphicsCard"/> this <see cref="Display"/> is connected to.
3641
/// </summary>
@@ -47,13 +52,15 @@ public readonly struct Display
4752
/// <param name="deviceName">The name of the <see cref="Display"/>.</param>
4853
/// <param name="width">The with of the <see cref="Display"/>.</param>
4954
/// <param name="height">The height of the <see cref="Display"/>.</param>
55+
/// <param name="rotation">The rotation of the <see cref="Display"/>.</param>
5056
/// <param name="graphicsCard">The <see cref="GraphicsCard"/> this <see cref="Display"/> is connected to.</param>
51-
public Display(int index, string deviceName, int width, int height, GraphicsCard graphicsCard)
57+
public Display(int index, string deviceName, int width, int height, Rotation rotation, GraphicsCard graphicsCard)
5258
{
5359
this.Index = index;
5460
this.DeviceName = deviceName;
5561
this.Width = width;
5662
this.Height = height;
63+
this.Rotation = rotation;
5764
this.GraphicsCard = graphicsCard;
5865
}
5966

@@ -73,7 +80,7 @@ public Display(int index, string deviceName, int width, int height, GraphicsCard
7380

7481
/// <inheritdoc />
7582
public override int GetHashCode() => HashCode.Combine(Index, GraphicsCard);
76-
83+
7784
/// <summary>
7885
/// Determines whether two <see cref="Display"/> are equal.
7986
/// </summary>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace ScreenCapture.NET;
2+
3+
/// <summary>
4+
/// Represents a display-rotation.
5+
/// </summary>
6+
public enum Rotation
7+
{
8+
None = 0,
9+
Rotation90 = 90,
10+
Rotation180 = 180,
11+
Rotation270 = 270
12+
}

ScreenCapture.NET/ScreenCapture.NET.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
</ItemGroup>
6363

6464
<ItemGroup>
65-
<PackageReference Include="Vortice.Direct3D11" Version="2.3.0" />
65+
<PackageReference Include="Vortice.Direct3D11" Version="2.4.2" />
6666
</ItemGroup>
6767

6868
</Project>

0 commit comments

Comments
 (0)