Skip to content

Commit 4bebea1

Browse files
authored
Merge pull request #1 from d2phap/feature/hybrid-graphics
Add support for drawing hybrid graphics by `IGraphics` interface
2 parents 00fba5c + fb0bd3a commit 4bebea1

16 files changed

+1172
-800
lines changed

README.md

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# D2Phap.DXControl
22

3-
- A WinForms hybrid control that supports Direct2D and GDI+ drawing thanks to [DirectN](https://github.com/smourier/DirectN) and [WicNet](https://github.com/smourier/WicNet).
3+
- A WinForms hybrid control that supports both Direct2D and GDI+ drawing thanks to [WicNet](https://github.com/smourier/WicNet).
44
- This control is used in [ImageGlass](https://github.com/d2phap/ImageGlass) software since version 9.0.
55

66
![Nuget](https://img.shields.io/nuget/dt/D2Phap.DXControl?color=%2300a8d6&logo=nuget)
@@ -30,18 +30,19 @@ Install-Package D2Phap.DXControl
3030

3131

3232
## Example
33-
Draw 2 rectangles by Direct2D and GDI+ graphics, then animate it to the right side.
3433

35-
<img src="https://user-images.githubusercontent.com/3154213/181906424-27418cfd-5f41-4380-8ae9-0ea577c91b16.png" width="500" />
3634

35+
<img src="https://user-images.githubusercontent.com/3154213/185740243-6a3cb1b6-13e6-4888-8c57-ce8ac9998c6e.png" width="500" />
36+
37+
Draws a rectangle, then moves it to the right side.
3738

3839
```cs
3940
using D2Phap;
4041

4142
// create a WinForms custom control that extends from DXControl
4243
public class DXCanvas : DXControl
4344
{
44-
private D2D_RECT_F animatableRectangle = new(100f, 100f, new(400, 200));
45+
private RectangleF animatableRectangle = new(100, 100, 400, 200);
4546

4647
public DXCanvas()
4748
{
@@ -51,21 +52,11 @@ public class DXCanvas : DXControl
5152
UseHardwareAcceleration = true;
5253
}
5354

54-
// use Direct2D graphics
55-
protected override void OnDirect2DRender(DXGraphics g)
56-
{
57-
// draw a yellow rectangle with green border
58-
g.FillRectangle(rectText, _D3DCOLORVALUE.FromCOLORREF(_D3DCOLORVALUE.Yellow.Int32Value, 100));
59-
g.DrawRectangle(rectText, _D3DCOLORVALUE.Green);
60-
}
61-
62-
63-
// Use GDI+ graphics
64-
protected override void OnGdiPlusRender(Graphics g)
55+
protected override void OnRender(IGraphics g)
6556
{
6657
// draw a yellow rectangle with green border
67-
using var pen = new Pen(Color.Red, 5);
68-
g.DrawRectangle(pen, new Rectangle((int)rectText.left, (int)rectText.top - 50, (int)rectText.Width, (int)rectText.Height));
58+
g.FillRectangle(rectText, Color.FromArgb(100, Yellow));
59+
g.DrawRectangle(rectText, Color.Green);
6960
}
7061

7162

Source/DXControl/D2Phap.DXControl.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<IncludeSymbols>True</IncludeSymbols>
2121
<PackageReleaseNotes></PackageReleaseNotes>
2222
<Authors>Duong Dieu Phap</Authors>
23-
<VersionPrefix>1.1.0</VersionPrefix>
23+
<VersionPrefix>2.0.0</VersionPrefix>
2424
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
2525
<PublishRepositoryUrl>true</PublishRepositoryUrl>
2626
<EmbedUntrackedSources>true</EmbedUntrackedSources>

Source/DXControl/DXControl.cs

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ public class DXControl : Control
2727
private readonly IComObject<IDWriteFactory> _dWriteFactory = DWriteFunctions.DWriteCreateFactory(DWRITE_FACTORY_TYPE.DWRITE_FACTORY_TYPE_SHARED);
2828
private ID2D1HwndRenderTarget? _renderTarget;
2929
private ID2D1DeviceContext? _device;
30-
private DXGraphics? _graphics;
30+
private D2DGraphics? _graphicsD2d;
31+
private GdipGraphics? _graphicsGdi;
3132

3233

3334
private bool _useHardwardAcceleration = true;
@@ -86,10 +87,10 @@ public ID2D1DeviceContext Device
8687

8788

8889
/// <summary>
89-
/// Gets the <see cref='DXGraphics'/> object used to draw in <see cref="OnDirect2DRender(DXGraphics)"/>.
90+
/// Gets the <see cref='D2DGraphics'/> object used to draw in <see cref="Render"/>.
9091
/// </summary>
9192
[Browsable(false)]
92-
public DXGraphics? D2Graphics => _graphics;
93+
public D2DGraphics? D2Graphics => _graphicsD2d;
9394

9495

9596
/// <summary>
@@ -189,15 +190,9 @@ public bool EnableAnimation
189190

190191

191192
/// <summary>
192-
/// Occurs when the control is being rendered by Direct2D <see cref="DXGraphics"/>.
193+
/// Occurs when the control is being rendered by <see cref="IGraphics"/>.
193194
/// </summary>
194-
public event EventHandler<RenderByDirect2DEventArgs>? RenderByDirect2D;
195-
196-
197-
/// <summary>
198-
/// Occurs when the control is being rendered by GDI+ <see cref="Graphics"/>.
199-
/// </summary>
200-
public event EventHandler<RenderByGdiPlusEventArgs>? RenderByGdiPLus;
195+
public event EventHandler<RenderEventArgs>? Render;
201196

202197

203198
/// <summary>
@@ -259,8 +254,8 @@ protected override void Dispose(bool disposing)
259254
_ticker.Stop(1000);
260255
_ticker.Tick -= Ticker_Tick;
261256

262-
_graphics?.Dispose();
263-
_graphics = null;
257+
_graphicsD2d?.Dispose();
258+
_graphicsD2d = null;
264259

265260
// '_device' must be disposed in DestroyHandle()
266261
}
@@ -359,9 +354,8 @@ protected override void OnPaintBackground(PaintEventArgs e)
359354

360355

361356
/// <summary>
362-
/// <b>Do use</b> <see cref="OnDirect2DRender(DXGraphics)"/> if you want to draw on the control.
357+
/// <b>Do use</b> <see cref="OnRender(IGraphics)"/> if you want to draw on the control.
363358
/// </summary>
364-
/// <param name="e"></param>
365359
protected override void OnPaint(PaintEventArgs e)
366360
{
367361
if (DesignMode)
@@ -382,18 +376,29 @@ protected override void OnPaint(PaintEventArgs e)
382376
{
383377
DoubleBuffered = false;
384378

385-
_graphics ??= new DXGraphics(_device, _dWriteFactory);
379+
_graphicsD2d ??= new D2DGraphics(_device, _dWriteFactory);
386380

387381
_device.BeginDraw();
388382
_device.Clear(_D3DCOLORVALUE.FromColor(BackColor));
389-
OnDirect2DRender(_graphics);
383+
OnRender(_graphicsD2d);
390384
_device.EndDraw();
391385
}
386+
392387
// use GDI+ graphics
393388
else
394389
{
395390
DoubleBuffered = true;
396-
OnGdiPlusRender(e.Graphics);
391+
392+
if (_graphicsGdi == null)
393+
{
394+
_graphicsGdi = new GdipGraphics(e.Graphics);
395+
}
396+
else
397+
{
398+
_graphicsGdi.Graphics = e.Graphics;
399+
}
400+
401+
OnRender(_graphicsGdi);
397402
}
398403

399404

@@ -428,29 +433,17 @@ protected override void OnPaint(PaintEventArgs e)
428433
#region New / Virtual functions
429434

430435
/// <summary>
431-
/// Draws control by Direct2D <see cref="D2Graphics"/> object.
432-
/// </summary>
433-
protected virtual void OnDirect2DRender(DXGraphics g)
434-
{
435-
if (!IsReady) return;
436-
437-
RenderByDirect2D?.Invoke(this, new(g));
438-
}
439-
440-
441-
/// <summary>
442-
/// Draws control by GDI+ <see cref="Graphics"/> object.
436+
/// Triggers <see cref="Render"/> event to paint the control.
443437
/// </summary>
444-
protected virtual void OnGdiPlusRender(Graphics g)
438+
protected virtual void OnRender(IGraphics g)
445439
{
446440
if (!IsReady) return;
447-
448-
RenderByGdiPLus?.Invoke(this, new(g));
441+
Render?.Invoke(this, new(g));
449442
}
450443

451444

452445
/// <summary>
453-
/// Process animation logic when frame changes
446+
/// Triggers <see cref="Frame"/> event to process animation logic when frame changes.
454447
/// </summary>
455448
protected virtual void OnFrame(FrameEventArgs e)
456449
{
@@ -461,7 +454,7 @@ protected virtual void OnFrame(FrameEventArgs e)
461454

462455

463456
/// <summary>
464-
/// Happens when control is ready.
457+
/// Triggers <see cref="Loaded"/> event when the control is ready.
465458
/// </summary>
466459
protected virtual void OnLoaded()
467460
{
@@ -532,7 +525,7 @@ public void CreateDevice()
532525
_renderTarget.Resize(new((uint)ClientSize.Width, (uint)ClientSize.Height));
533526

534527
_device = (ID2D1DeviceContext)_renderTarget;
535-
_graphics = new DXGraphics(_device, _dWriteFactory);
528+
_graphicsD2d = new D2DGraphics(_device, _dWriteFactory);
536529
}
537530

538531

Source/DXControl/DXHelper.cs

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ MIT License
44
Project & license info: https://github.com/d2phap/DXControl
55
*/
66
using DirectN;
7+
using System.Runtime.InteropServices;
8+
using WicNet;
79

810
namespace D2Phap;
911

@@ -35,10 +37,10 @@ public static _D3DCOLORVALUE FromColor(Color color, byte? alpha = null)
3537
public static D2D_RECT_F ToD2DRectF(Rectangle rect)
3638
{
3739
return new D2D_RECT_F(
38-
(float)rect.Left,
39-
(float)rect.Top,
40-
(float)rect.Right,
41-
(float)rect.Bottom);
40+
rect.Left,
41+
rect.Top,
42+
rect.Right,
43+
rect.Bottom);
4244
}
4345

4446

@@ -63,4 +65,84 @@ public static D2D_RECT_F ToD2DRectF(float x, float y, float width, float height)
6365
return new D2D_RECT_F(x, y, x + width, y + height);
6466
}
6567

68+
69+
/// <summary>
70+
/// Converts <see cref="D2D_RECT_F"/> to <see cref="RectangleF"/>
71+
/// </summary>
72+
public static RectangleF ToRectangle(D2D_RECT_F rect)
73+
{
74+
return new RectangleF(rect.left, rect.top, rect.Width, rect.Height);
75+
}
76+
77+
78+
/// <summary>
79+
/// Converts <see cref="D2D_SIZE_F"/> to <see cref="SizeF"/>
80+
/// </summary>
81+
public static SizeF ToSize(D2D_SIZE_F size)
82+
{
83+
return new SizeF(size.width, size.height);
84+
}
85+
86+
87+
/// <summary>
88+
/// Converts <see cref="D2D_POINT_2F"/> to <see cref="PointF"/>
89+
/// </summary>
90+
public static PointF ToPoint(D2D_POINT_2F point)
91+
{
92+
return new PointF(point.x, point.y);
93+
}
94+
95+
96+
/// <summary>
97+
/// Creates default <see cref="D2D1_BITMAP_PROPERTIES"/>.
98+
/// </summary>
99+
public static D2D1_BITMAP_PROPERTIES CreateDefaultBitmapProps()
100+
{
101+
return new D2D1_BITMAP_PROPERTIES()
102+
{
103+
pixelFormat = new D2D1_PIXEL_FORMAT()
104+
{
105+
alphaMode = D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_PREMULTIPLIED,
106+
format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM,
107+
},
108+
dpiX = 96.0f,
109+
dpiY = 96.0f,
110+
};
111+
}
112+
113+
114+
115+
/// <summary>
116+
/// Converts <see cref="WicBitmapSource"/> to <see cref="ID2D1Bitmap"/> COM object.
117+
/// </summary>
118+
public static ComObject<ID2D1Bitmap>? ToD2D1Bitmap(ID2D1DeviceContext? dc, WicBitmapSource? wicSrc)
119+
{
120+
if (dc == null || wicSrc == null)
121+
{
122+
return null;
123+
}
124+
125+
wicSrc.ConvertTo(WicPixelFormat.GUID_WICPixelFormat32bppPBGRA);
126+
127+
// create D2D1Bitmap from WICBitmapSource
128+
var bitmapPropsPtr = new D2D1_BITMAP_PROPERTIES()
129+
{
130+
pixelFormat = new D2D1_PIXEL_FORMAT()
131+
{
132+
alphaMode = D2D1_ALPHA_MODE.D2D1_ALPHA_MODE_PREMULTIPLIED,
133+
format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM,
134+
},
135+
dpiX = 96.0f,
136+
dpiY = 96.0f,
137+
}.StructureToPtr();
138+
139+
_ = dc.CreateBitmapFromWicBitmap(wicSrc.ComObject.Object, bitmapPropsPtr, out ID2D1Bitmap? bmp).ThrowOnError();
140+
141+
var comBmp = new ComObject<ID2D1Bitmap>(bmp);
142+
143+
Marshal.FreeHGlobal(bitmapPropsPtr);
144+
145+
return comBmp;
146+
}
147+
66148
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// c:\program files (x86)\windows kits\10\include\10.0.22000.0\um\d2d1.h(329,9)
2+
using System.Runtime.InteropServices;
3+
4+
namespace DirectN
5+
{
6+
/// <summary>
7+
/// Describes the extend modes and the interpolation mode of an ID2D1BitmapBrush.
8+
/// </summary>
9+
[StructLayout(LayoutKind.Sequential)]
10+
public partial struct D2D1_BITMAP_BRUSH_PROPERTIES
11+
{
12+
public D2D1_EXTEND_MODE extendModeX;
13+
public D2D1_EXTEND_MODE extendModeY;
14+
public D2D1_BITMAP_INTERPOLATION_MODE interpolationMode;
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// c:\program files (x86)\windows kits\10\include\10.0.22000.0\um\d2d1_1.h(506,9)
2+
using System.Runtime.InteropServices;
3+
4+
namespace DirectN
5+
{
6+
/// <summary>
7+
/// Describes the extend modes and the interpolation mode of an ID2D1BitmapBrush.
8+
/// </summary>
9+
[StructLayout(LayoutKind.Sequential)]
10+
public partial struct D2D1_BITMAP_BRUSH_PROPERTIES1
11+
{
12+
public D2D1_EXTEND_MODE extendModeX;
13+
public D2D1_EXTEND_MODE extendModeY;
14+
public D2D1_INTERPOLATION_MODE interpolationMode;
15+
}
16+
}

Source/DXControl/Events/RenderByDirect2DEventArgs.cs

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)