如何在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元素的画面。