SurfaceImageSource管理器:使用WinRT/Metro SurfaceImageSource类,通过一个小型C++组件连接C#和DirectX/Direct2D






4.88/5 (6投票s)
SurfaceImageSource管理器是一个C++ WinRT组件,可以轻松生成随时可用的SurfaceImageSource实例,然后使用DirectX或Direct2D在C# Metro应用程序中定义它们的外观。
引言
WinRT包含一个从ImageSource
派生的SurfaceImageSource
类,可以很容易地将DirectX或Direct2D图形注入Metro视觉树中,如本文所述:“结合使用XAML和DirectX”。SurfaceImageSource完全可用于C++,但不可用于C#。
背景
该项目需要Windows 8 Customer Preview、VS.NET 2011 Beta和SharpDX for Win8 Preview程序集。“结合使用XAML和DirectX”一文是推荐阅读的。
使用代码
SurfaceImageSource Manager解决方案提供了用于KSurfaceImageSourceManager WinRT C++组件的代码以及Test_SurfaceImageSourceManager C# Metro应用程序,展示了如何使用它。Test_SurfaceImageSourceManager依赖于DXSharp来利用KSurfaceImageSourceManager
组件生成和返回的DirectX和Direct2D对象。
描述KSurfaceImageSourceManager WinRT C++组件
KSurfaceImageSourceManager
组件的作用是
- 给定一个(
pixelWidth
,pixelHeight
) 大小 (NewSurfaceImageSource
),生成随时可用的、完全连接的SurfaceImageSource
WinRT类实例,并在以后取消注册该实例 (DeleteSurfaceImageSource
)。 - 在给定的
SurfaceImageSource
上初始化和终止Direct2D绘图会话 (BeginDraw2D
/EndDraw2D
)。 - 在给定的
SurfaceImageSource
上初始化和终止DirectX绘图会话 (BeginDraw3D
/EndDraw3D
)。 - 提供由给定的
KSurfaceImageSourceManager
拥有的各种Direct2D/DirectX设备、上下文句柄 (Get_ID3D11Device
,Get_ID3D11DeviceContext
, ...)。
KSurfaceImageSourceManager
类的公共签名如下所示
public ref class KSurfaceImageSourceManager sealed
{
public:
KSurfaceImageSourceManager();
int Get_ID3D11Device();
int Get_ID3D11DeviceContext();
int Get_IDXGIDevice();
int Get_ID2D1Factory1();
int Get_ID2D1Device();
int Get_ID2D1DeviceContext();
SurfaceImageSource^ NewSurfaceImageSource(int pixelWidth, int pixelHeight);
void DeleteSurfaceImageSource(SurfaceImageSource^ pSurfaceImageSource);
int GetSurfaceImageSourceSize(SurfaceImageSource^ pSurfaceImageSource, int* pWidth, int* pHeight);
int ClearSurfaceImageSource(SurfaceImageSource^ pSurfaceImageSource, float R, float G, float B, float A);
int BeginDraw2D(SurfaceImageSource^ pSurfaceImageSource, int* pOffsetX, int* pOffsetY, int* pSurfaceWidth, int* pSurfaceHeight);
void EndDraw2D(SurfaceImageSource^ pSurfaceImageSource);
int BeginDraw3D(SurfaceImageSource^ pSurfaceImageSource, int* pOffsetX, int* pOffsetY, int* pSurfaceWidth, int* pSurfaceHeight);
void EndDraw3D(SurfaceImageSource^ pSurfaceImageSource); };
};
由KSurfaceImageSourceManager
生成的SurfaceImageSource
可以作为其Source
(Image.Source
属性)连接到Image
组件。
// Creating a KSurfaceImageSourceManager instance
KSurfaceImageSourceManager _pKSurfaceImageSourceManager = new KSurfaceImageSourceManager();
// Using the KSurfaceImageSourceManager to create a (512 * 512) SurfaceImageSource
SurfaceImageSource _pSurfaceImageSource = _pKSurfaceImageSourceManager.NewSurfaceImageSource(512, 512);
// Connecting the SurfaceImageSource to a 'im2D' Image component.
im2D.Source = _pSurfaceImageSource;
使用KSurfaceImageSourceManager管理以SurfaceImageSource为目标的Direct2D绘图会话
KSurfaceImageSourceManager
使得可以执行Direct2D绘图会话,通过调用BeginDraw2D
打开,并在稍后通过调用EndDraw2D
关闭,在SurfaceImageSource
上进行。
每次调用KSurfaceImageSourceManager
BeginDraw2D
方法都会返回一个句柄,该句柄用于生成SharpDX.Direct2D1.RenderTarget
类的实例,并执行任何以给定的SurfaceImageSource
拥有的DXGI表面为目标的Direct2D绘制操作,如下所示
{
int _hrenderTarget = 0;
int _offsetx = 0;
int _offsety = 0;
int _surfacewidth = 0;
int _surfaceheight = 0;
try
{
// initiating a Direct2D drawing session: BeginDraw2D
_hrenderTarget = _pKSurfaceImageSourceManager.BeginDraw2D(_pSurfaceImageSource, out _offsetx,
out _offsety, out _surfacewidth, out _surfaceheight);
// connecting the _hrenderTarget handle returned by BeginDraw2D to a RenderTarget instance
RenderTarget _pRenderTarget = new RenderTarget(new IntPtr(_hrenderTarget));
// Direct2D drawing session targetting _pRenderTarget
{
_pRenderTarget.BeginDraw();
SharpDX.Direct2D1.SolidColorBrush _brush = null;
int _left = _offsetx;
int _top = _offsety;
int _right = _surfacewidth;
int _bottom = _surfaceheight;
// border
_brush = new SharpDX.Direct2D1.SolidColorBrush(_pRenderTarget, new SharpDX.Color4(1, 0, 0, 1));
_pRenderTarget.FillRectangle(new SharpDX.RectangleF(_left, _top, _right, _bottom), _brush);
// fill
int _border = 2;
float _shade = 0.25f;
_brush = new SharpDX.Direct2D1.SolidColorBrush(_pRenderTarget, new SharpDX.Color4(_shade, _shade, _shade, 1));
_pRenderTarget.FillRectangle(new SharpDX.RectangleF(_left + _border,
_top + _border, _right - 2 * _border, _bottom - 2 * _border), _brush);
_pRenderTarget.EndDraw();
}
}
catch (Exception E)
{
}
finally
{
// terminating the Direct2D drawing session
_pKSurfaceImageSourceManager.EndDraw2D(_pSurfaceImageSource);
}
}
使用KSurfaceImageSourceManager管理以SurfaceImageSource为目标的DirectX11绘图会话
KSurfaceImageSourceManager
类公开了一个Get_ID3D11Device
方法,该方法返回一个句柄,用于创建SharpDX.Direct3D11.Device1
类的包装实例。
KSurfaceImageSourceManager
使得可以执行DirectX11绘图会话,通过调用BeginDraw3D
打开,并在稍后通过调用EndDraw3D
在SurfaceImageSource
上关闭。
每次调用KSurfaceImageSourceManager BeginDraw3D
方法都会返回一个句柄,该句柄用于生成SharpDX.Direct3D11.Texture2D
包装类的一个实例,如下面的代码所示
// a complete Direct3D11 drawing session targetting a _pSurfaceImageSource SurfaceImageSource
// produced by a _pKSurfaceImageSourceManager KSurfaceImageSourceManager
{
int _hdevice = 0;
int _pID3D11Texture2D = 0;
int _offsetx = 0;
int _offsety = 0;
int _surfacewidth = 0;
int _surfaceheight = 0;
try
{
// retrieving the handle of the ID3D11Device used by _pKSurfaceImageSourceManager
// and wrapping it with a SharpDX.Direct3D11.Device1 instance
_hdevice = _pKSurfaceImageSourceManager.Get_ID3D11Device();
SharpDX.Direct3D11.Device1 _device = new SharpDX.Direct3D11.Device1(new IntPtr(_hdevice));
// initating a DirectX drawing session on _pSurfaceImageSource,
// and wrapping the returned _pID3D11Texture2D ID3D11Texture2D handle
// in a SharpDX.Direct3D11.Texture2D instance
_pID3D11Texture2D = _pKSurfaceImageSourceManager.BeginDraw3D(_pSurfaceImageSource,
out _offsetx, out _offsety, out _surfacewidth, out _surfaceheight);
Texture2D _pTexture2D = new Texture2D(new IntPtr(_pID3D11Texture2D));
// preparing the _device.ImmediateContext context
SharpDX.Direct3D11.DeviceContext _context = _device.ImmediateContext;
// making _pTexture2D, and thefore the _pSurfaceImageSource
// DXGI surface, the _context current RenderTarget
var _renderView = new RenderTargetView(_device, _pTexture2D);
_context.OutputMerger.SetTargets(_renderView);
// clearing the _context context
_context.ClearRenderTargetView(_renderView, new Color4(0, 0, 1, 1f));
// IMPORTANT: adapting the context ViewPort to the effective
// position (_offsetx, _offsety, _surfacewidth, _surfaceheight)
// of the drawing session retruned by BeginDraw3D
{
int _x = _offsetx;
int _y = _offsety;
int _dx = (_surfacewidth - _offsetx);
int _dy = (_surfaceheight - _offsety);
_context.Rasterizer.SetViewports(new Viewport(_x, _y, _dx, _dy, 0.0f, 1.0f));
}
// Perform some DirectX drawing operations in the SharpDX.Direct3D11.Device1 _device
render(_device, _context);
}
catch (Exception E)
{
}
finally
{
// Completing the DirectX drawing session
_pKSurfaceImageSourceManager.EndDraw3D(_pSurfaceImageSource);
}
}
额外的好处
Test_SurfaceImageSourceManager项目C#源代码提供了一些额外的好处
- 它给出了一个简单的顶点/像素着色器对的2D_Color.fx源代码,以及用于生成2D_Color_vs.fxo / 2D_Color_ps.fxo的Compile_FX.bat批处理文件
- 文件嵌入为项目中的资源
- 它展示了如何提取这些.fxo资源,然后将它们转换为分配给
SharpDX.Direct3D11.DeviceContext
上下文的SharpDX.Direct3D11.VertexShader
/PixelShader
实例 - ...