Skip to content

Commit 085a430

Browse files
committed
Initial Direct2D Support
Initial stab at integrated Direct2D support.
1 parent c067a51 commit 085a430

19 files changed

+689
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>WinExe</OutputType>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<ProjectReference Include="..\..\..\thirtytwo\thirtytwo.csproj" />
9+
</ItemGroup>
10+
11+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Drawing;
5+
using System.Numerics;
6+
using Windows;
7+
using Windows.Win32.Foundation;
8+
using Windows.Win32.Graphics.Direct2D;
9+
10+
namespace Direct2dDemo;
11+
12+
internal class Program
13+
{
14+
[STAThread]
15+
private static void Main() => Application.Run(new Direct2dDemo());
16+
17+
private class Direct2dDemo : MainWindow
18+
{
19+
private SolidColorBrush? _lightSlateGrayBrush;
20+
private SolidColorBrush? _cornflowerBlueBrush;
21+
22+
public Direct2dDemo() : base(title: "Simple Direct2D Application", features: Features.EnableDirect2d)
23+
{
24+
}
25+
26+
protected override void RenderTargetCreated(HwndRenderTarget renderTarget)
27+
{
28+
_lightSlateGrayBrush?.Dispose();
29+
_cornflowerBlueBrush?.Dispose();
30+
_lightSlateGrayBrush = renderTarget.CreateSolidColorBrush(Color.LightSlateGray);
31+
_cornflowerBlueBrush = renderTarget.CreateSolidColorBrush(Color.CornflowerBlue);
32+
base.RenderTargetCreated(renderTarget);
33+
}
34+
35+
protected override LRESULT WindowProcedure(HWND window, MessageType message, WPARAM wParam, LPARAM lParam)
36+
{
37+
switch (message)
38+
{
39+
case MessageType.Paint:
40+
if (IsDirect2dEnabled(out var renderTarget))
41+
{
42+
renderTarget.SetTransform(Matrix3x2.Identity);
43+
renderTarget.Clear(Color.White);
44+
45+
SizeF size = renderTarget.Size();
46+
47+
for (int x = 0; x < size.Width; x += 10)
48+
{
49+
renderTarget.DrawLine(
50+
new(x, 0), new(x, size.Height),
51+
_lightSlateGrayBrush!,
52+
0.5f);
53+
}
54+
55+
for (int y = 0; y < size.Height; y += 10)
56+
{
57+
renderTarget.DrawLine(
58+
new(0, y), new(size.Width, y),
59+
_lightSlateGrayBrush!,
60+
0.5f);
61+
}
62+
63+
RectangleF rectangle1 = RectangleF.FromLTRB(
64+
size.Width / 2 - 50,
65+
size.Height / 2 - 50,
66+
size.Width / 2 + 50,
67+
size.Height / 2 + 50);
68+
69+
RectangleF rectangle2 = RectangleF.FromLTRB(
70+
size.Width / 2 - 100,
71+
size.Height / 2 - 100,
72+
size.Width / 2 + 100,
73+
size.Height / 2 + 100);
74+
75+
renderTarget.FillRectangle(rectangle1, _lightSlateGrayBrush!);
76+
renderTarget.DrawRectangle(rectangle2, _cornflowerBlueBrush!);
77+
}
78+
return (LRESULT)0;
79+
}
80+
81+
return base.WindowProcedure(window, message, wParam, lParam);
82+
}
83+
}
84+
}

src/thirtytwo/MainWindow.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ public MainWindow(
1818
WindowClass? windowClass = default,
1919
nint parameters = default,
2020
HMENU menuHandle = default,
21-
HBRUSH backgroundBrush = default) : base(
21+
HBRUSH backgroundBrush = default,
22+
Features features = default) : base(
2223
bounds,
2324
title,
2425
style,
@@ -27,6 +28,7 @@ public MainWindow(
2728
windowClass,
2829
parameters,
2930
menuHandle,
30-
backgroundBrush)
31+
backgroundBrush,
32+
features)
3133
{ }
3234
}

src/thirtytwo/NativeMethods.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -347,4 +347,7 @@ VIRTUAL_KEY
347347
WIN32_ERROR
348348
WINDOWPOS
349349
WM_*
350-
XFORMCOORDS
350+
XFORMCOORDS
351+
ID2D1Factory
352+
D2D1CreateFactory
353+
D2DERR_RECREATE_TARGET
+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Runtime.CompilerServices;
5+
6+
namespace System;
7+
8+
internal static class EnumExtensions
9+
{
10+
/// <summary>
11+
/// Returns true if the given flag or flags are set.
12+
/// </summary>
13+
/// <remarks>
14+
/// Simple wrapper for <see cref="Enum.HasFlag(Enum)"/> that gives you better intellisense.
15+
/// </remarks>
16+
[SkipLocalsInit]
17+
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
18+
public static unsafe bool AreFlagsSet<T>(this T value, T flags) where T : unmanaged, Enum => value.HasFlag(flags);
19+
20+
/// <summary>
21+
/// Sets the given flag or flags.
22+
/// </summary>
23+
[SkipLocalsInit]
24+
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
25+
public static unsafe void SetFlags<T>(this ref T value, T flags) where T : unmanaged, Enum
26+
{
27+
fixed (T* v = &value)
28+
{
29+
// Note that the non-relevant if clauses will be omitted by the JIT so these become one statement.
30+
if (sizeof(T) == sizeof(byte))
31+
{
32+
*(byte*)v |= *(byte*)&flags;
33+
}
34+
else if (sizeof(T) == sizeof(short))
35+
{
36+
*(short*)v |= *(short*)&flags;
37+
}
38+
else if (sizeof(T) == sizeof(int))
39+
{
40+
*(int*)v |= *(int*)&flags;
41+
}
42+
else if (sizeof(T) == sizeof(long))
43+
{
44+
*(long*)v |= *(long*)&flags;
45+
}
46+
else
47+
{
48+
throw new InvalidOperationException();
49+
}
50+
}
51+
}
52+
53+
[SkipLocalsInit]
54+
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
55+
public static unsafe void ClearFlags<T>(this ref T value, T flags) where T : unmanaged, Enum
56+
{
57+
fixed (T* v = &value)
58+
{
59+
// Note that the non-relevant if clauses will be omitted by the JIT so these become one statement.
60+
if (sizeof(T) == sizeof(byte))
61+
{
62+
*(byte*)v &= (byte)~*(byte*)&flags;
63+
}
64+
else if (sizeof(T) == sizeof(short))
65+
{
66+
*(short*)v &= (short)~*(short*)&flags;
67+
}
68+
else if (sizeof(T) == sizeof(int))
69+
{
70+
*(int*)v &= ~*(int*)&flags;
71+
}
72+
else if (sizeof(T) == sizeof(long))
73+
{
74+
*(long*)v &= ~*(long*)&flags;
75+
}
76+
else
77+
{
78+
throw new InvalidOperationException();
79+
}
80+
}
81+
}
82+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Windows.Support;
5+
6+
namespace Windows.Win32.Graphics.Direct2D;
7+
8+
public unsafe class Brush : Resource, IPointer<ID2D1Brush>
9+
{
10+
public unsafe new ID2D1Brush* Pointer { get; private set; }
11+
12+
public Brush(ID2D1Brush* brush) : base((ID2D1Resource*)brush) => Pointer = brush;
13+
14+
protected override void Dispose(bool disposing)
15+
{
16+
Pointer = null;
17+
base.Dispose(disposing);
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Drawing;
5+
6+
namespace Windows.Win32.Graphics.Direct2D.Common;
7+
8+
public partial struct D2D1_COLOR_F
9+
{
10+
public D2D1_COLOR_F(float r, float g, float b, float a)
11+
{
12+
this.r = r;
13+
this.g = g;
14+
this.b = b;
15+
this.a = a;
16+
}
17+
18+
public static explicit operator D2D1_COLOR_F(Color value) =>
19+
new(value.R / 255.0f, value.G / 255.0f, value.B / 255.0f, value.A / 255.0f);
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Drawing;
5+
6+
namespace Windows.Win32.Graphics.Direct2D.Common;
7+
8+
public partial struct D2D_RECT_F
9+
{
10+
public D2D_RECT_F(float left, float top, float right, float bottom)
11+
{
12+
this.left = left;
13+
this.top = top;
14+
this.right = right;
15+
this.bottom = bottom;
16+
}
17+
18+
public static implicit operator D2D_RECT_F(RectangleF value) =>
19+
new(value.Left, value.Top, value.Right, value.Bottom);
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Drawing;
5+
6+
namespace Windows.Win32.Graphics.Direct2D.Common;
7+
8+
public partial struct D2D_SIZE_U
9+
{
10+
public D2D_SIZE_U(uint width, uint height)
11+
{
12+
this.width = width;
13+
this.height = height;
14+
}
15+
16+
public static explicit operator D2D_SIZE_U(Size value) =>
17+
new(checked((uint)value.Width), checked((uint)value.Height));
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) Jeremy W. Kuhne. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Windows.Support;
5+
using Windows.Win32.System.Com;
6+
7+
namespace Windows.Win32.Graphics.Direct2D;
8+
9+
public unsafe class Factory : DisposableBase.Finalizable, IPointer<ID2D1Factory>
10+
{
11+
private readonly AgileComPointer<ID2D1Factory> _factory;
12+
13+
public unsafe ID2D1Factory* Pointer { get; private set; }
14+
15+
public Factory(
16+
D2D1_FACTORY_TYPE factoryType = D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED,
17+
D2D1_DEBUG_LEVEL factoryOptions = D2D1_DEBUG_LEVEL.D2D1_DEBUG_LEVEL_NONE)
18+
{
19+
ID2D1Factory* factory;
20+
Interop.D2D1CreateFactory(
21+
factoryType,
22+
IID.Get<ID2D1Factory>(),
23+
(D2D1_FACTORY_OPTIONS*)&factoryOptions,
24+
(void**)&factory).ThrowOnFailure();
25+
26+
Pointer = factory;
27+
28+
// Ensure that this can be disposed on the finalizer thread by giving the "last" ref count
29+
// to an agile pointer.
30+
_factory = new AgileComPointer<ID2D1Factory>(factory, takeOwnership: true);
31+
}
32+
33+
protected override void Dispose(bool disposing)
34+
{
35+
Pointer = null;
36+
37+
if (disposing)
38+
{
39+
_factory.Dispose();
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)