在Windows 8客户预览版中,开发者可以利用Visual Studio.NET 2011 Beta和SharpDX for Win8 Preview组件,将DirectX或Direct2D绘图注入Metro视觉树。本文将介绍如何实现这一功能,以及相关的代码示例。
为了实现这一功能,需要以下工具和组件:
建议阅读"Combining XAML andDirectX"文章以获得更深入的理解。
"SurfaceImageSource Manager"解决方案提供了一个WinRTC++组件的代码,以及一个C#Metro应用程序的测试代码,展示了如何使用该组件。
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允许执行Direct2D绘图会话,通过调用BeginDraw2D方法开始,然后通过调用EndDraw2D方法结束。
{
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类提供了Get_ID3D11Device方法,该方法返回一个句柄,用于创建SharpDX.Direct3D11.Device1类的包装实例。
{
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));
// initiating 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 therefore 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 returned 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);
}
}