65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (6投票s)

2012年3月21日

CPOL

2分钟阅读

viewsIcon

45866

downloadIcon

1332

SurfaceImageSource管理器是一个C++ WinRT组件,可以轻松生成随时可用的SurfaceImageSource实例,然后使用DirectX或Direct2D在C# Metro应用程序中定义它们的外观。

Sample Image

引言

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可以作为其SourceImage.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打开,并在稍后通过调用EndDraw3DSurfaceImageSource上关闭。

每次调用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.fxoCompile_FX.bat批处理文件
  • 文件嵌入为项目中的资源
  • 它展示了如何提取这些.fxo资源,然后将它们转换为分配给SharpDX.Direct3D11.DeviceContext上下文的SharpDX.Direct3D11.VertexShader/PixelShader实例
  • ...
© . All rights reserved.