如何在UWP中使用SharpDX(查看github库 SharpDX-Samples-master总结)
使用 Windows.UI.Xaml.Media.Imaging.SurfaceImageSource 给前台的control显示。
新建一个对象ImageSource2D继承SurfaceImageSource,通过使用sharpdx绘制SurfaceImageSource
显示在前端xaml元素。(可以是UIElement的fill或者image的source)
----------
xaml前端有控件Image1,Ellipse1绘制他们的SurfaceImageSource,代码如下
namespace MyFirstDxGame { /// <summary> /// win2d 测试 /// </summary> public sealed partial class BlankPage1 : Page { private ImageSource2D MyDrawing; public BlankPage1() { this.InitializeComponent(); MyDrawing = new ImageSource2D((int)Image1.Width, (int)Image1.Height, true); // Use Scenario1Drawing as a source for the Image control Image1.Source = MyDrawing; // Use Scenario1Drawing as a source for the Ellipse shape's fill Ellipse1.Fill = new Windows.UI.Xaml.Media.ImageBrush() { ImageSource = MyDrawing }; } protected override void OnNavigatedTo(NavigationEventArgs e) { Image1_Tapped(null,null); } private void Image1_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e) { // Begin updating the SurfaceImageSource MyDrawing.BeginDraw(); // Clear background MyDrawing.Clear(Colors.Bisque); // Create a new pseudo-random number generator Random randomGenerator = new Random(); byte[] pixelValues = new byte[3]; // Represents the red, green, and blue channels of a color // Draw 50 random retangles for (int i = 0; i < 50; i++) { // Generate a new random color randomGenerator.NextBytes(pixelValues); Windows.UI.Color color = new Windows.UI.Color() { R = pixelValues[0], G = pixelValues[1], B = pixelValues[2], A = 255 }; // Add a new randomly colored 50x50 rectangle that will fit somewhere within the bounds of the Image1 control MyDrawing.FillSolidRect( color, new Rect(randomGenerator.Next((int)Image1.Width - 50), randomGenerator.Next((int)Image1.Height - 50), 50, 50) ); } // Stop updating the SurfaceImageSource and draw its contents MyDrawing.EndDraw(); } } }
ImageSource2D 代码如下:
using Windows.UI.Xaml; using SharpDX; using SharpDX.Direct2D1; using SharpDX.Direct3D; using SharpDX.Direct3D11; using SharpDX.DXGI; using SharpDX.Mathematics.Interop; using Device = SharpDX.Direct3D11.Device; using FeatureLevel = SharpDX.Direct3D.FeatureLevel; namespace MyFirstDxGame { public sealed class ImageSource2D : Windows.UI.Xaml.Media.Imaging.SurfaceImageSource { private Device d3dDevice; private SharpDX.Direct2D1.Device d2dDevice; private SharpDX.Direct2D1.DeviceContext d2dContext; private readonly int width; private readonly int height; public ImageSource2D(int pixelWidth, int pixelHeight, bool isOpaque) : base(pixelWidth, pixelHeight, isOpaque) { width = pixelWidth; height = pixelHeight; CreateDeviceResources(); Application.Current.Suspending += OnSuspending; } // Initialize hardware-dependent resources. private void CreateDeviceResources() { // Unlike the original C++ sample, we don't have smart pointers so we need to // dispose Direct3D objects explicitly Utilities.Dispose(ref d3dDevice); Utilities.Dispose(ref d2dDevice); Utilities.Dispose(ref d2dContext); // This flag adds support for surfaces with a different color channel ordering // than the API default. It is required for compatibility with Direct2D. var creationFlags = DeviceCreationFlags.BgraSupport; #if DEBUG // If the project is in a debug build, enable debugging via SDK Layers. creationFlags |= DeviceCreationFlags.Debug; #endif // This array defines the set of DirectX hardware feature levels this app will support. // Note the ordering should be preserved. // Don't forget to declare your application's minimum required feature level in its // description. All applications are assumed to support 9.1 unless otherwise stated. FeatureLevel[] featureLevels = { FeatureLevel.Level_11_1, FeatureLevel.Level_11_0, FeatureLevel.Level_10_1, FeatureLevel.Level_10_0, FeatureLevel.Level_9_3, FeatureLevel.Level_9_2, FeatureLevel.Level_9_1, }; // Create the Direct3D 11 API device object. d3dDevice = new Device(DriverType.Hardware, creationFlags, featureLevels); // Get the Direct3D 11.1 API device. using (var dxgiDevice = d3dDevice.QueryInterface<SharpDX.DXGI.Device>()) { // Create the Direct2D device object and a corresponding context. d2dDevice = new SharpDX.Direct2D1.Device(dxgiDevice); d2dContext = new SharpDX.Direct2D1.DeviceContext(d2dDevice, DeviceContextOptions.None); // Query for ISurfaceImageSourceNative interface. using (var sisNative = ComObject.QueryInterface<ISurfaceImageSourceNative>(this)) sisNative.Device = dxgiDevice; } } public void BeginDraw() { BeginDraw(new Windows.Foundation.Rect(0, 0, width, height)); } public void BeginDraw(Windows.Foundation.Rect updateRect) { // Express target area as a native RECT type. var updateRectNative = new Rectangle { Left = (int)updateRect.Left, Top = (int)updateRect.Top, Right = (int)updateRect.Right, Bottom = (int)updateRect.Bottom }; // Query for ISurfaceImageSourceNative interface. using (var sisNative = ComObject.QueryInterface<ISurfaceImageSourceNative>(this)) { // Begin drawing - returns a target surface and an offset to use as the top left origin when drawing. try { RawPoint offset; using (var surface = sisNative.BeginDraw(updateRectNative, out offset)) { // Create render target. using (var bitmap = new Bitmap1(d2dContext, surface)) { // Set context's render target. d2dContext.Target = bitmap; } // Begin drawing using D2D context. d2dContext.BeginDraw(); // Apply a clip and transform to constrain updates to the target update area. // This is required to ensure coordinates within the target surface remain // consistent by taking into account the offset returned by BeginDraw, and // can also improve performance by optimizing the area that is drawn by D2D. // Apps should always account for the offset output parameter returned by // BeginDraw, since it may not match the passed updateRect input parameter's location. d2dContext.PushAxisAlignedClip( new RectangleF( (offset.X), (offset.Y), (offset.X + (float)updateRect.Width), (offset.Y + (float)updateRect.Height) ), AntialiasMode.Aliased ); d2dContext.Transform = Matrix3x2.Translation(offset.X, offset.Y); } } catch (SharpDXException ex) { if (ex.ResultCode == SharpDX.DXGI.ResultCode.DeviceRemoved || ex.ResultCode == SharpDX.DXGI.ResultCode.DeviceReset) { // If the device has been removed or reset, attempt to recreate it and continue drawing. CreateDeviceResources(); BeginDraw(updateRect); } else { throw; } } } } public void EndDraw() { // Remove the transform and clip applied in BeginDraw since // the target area can change on every update. d2dContext.Transform = Matrix3x2.Identity; d2dContext.PopAxisAlignedClip(); // Remove the render target and end drawing. d2dContext.EndDraw(); d2dContext.Target = null; // Query for ISurfaceImageSourceNative interface. using (var sisNative = ComObject.QueryInterface<ISurfaceImageSourceNative>(this)) sisNative.EndDraw(); } public void Clear(Windows.UI.Color color) { d2dContext.Clear(ConvertToColorF(color)); } public void FillSolidRect(Windows.UI.Color color, Windows.Foundation.Rect rect) { // Create a solid color D2D brush. using (var brush = new SolidColorBrush(d2dContext, ConvertToColorF(color))) { // Draw a filled rectangle. d2dContext.FillRectangle(ConvertToRectF(rect), brush); } } private void OnSuspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e) { // Hints to the driver that the app is entering an idle state and that its memory can be used temporarily for other apps. using (var dxgiDevice = d3dDevice.QueryInterface<SharpDX.DXGI.Device3>()) dxgiDevice.Trim(); } private static Color ConvertToColorF(Windows.UI.Color color) { return new Color(color.R, color.G, color.B, color.A); } private static RectangleF ConvertToRectF(Windows.Foundation.Rect rect) { return new RectangleF((float)rect.X, (float)rect.Y, (float)rect.Width, (float)rect.Height); } } }
经过测试,改变imagesource可以实时更新xaml元素的画面。