D3D11Host.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. using System;
  2. using System.ComponentModel;
  3. using System.Diagnostics;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Media;
  7. using Microsoft.Xna.Framework;
  8. using Microsoft.Xna.Framework.Graphics;
  9. using Color = Microsoft.Xna.Framework.Color;
  10. using Matrix = Microsoft.Xna.Framework.Matrix;
  11. namespace WpfInteropSample
  12. {
  13. /// <summary>
  14. /// Host a Direct3D 11 scene.
  15. /// </summary>
  16. public class D3D11Host : Image
  17. {
  18. #region Fields
  19. // The Direct3D 11 device (shared by all D3D11Host elements):
  20. private static GraphicsDevice _graphicsDevice;
  21. private static int _referenceCount;
  22. private static readonly object _graphicsDeviceLock = new object();
  23. // Image source:
  24. private RenderTarget2D _renderTarget;
  25. private D3D11Image _d3D11Image;
  26. private bool _resetBackBuffer;
  27. // Render timing:
  28. private readonly Stopwatch _timer;
  29. private TimeSpan _lastRenderingTime;
  30. #endregion
  31. #region Properties
  32. /// <summary>
  33. /// Gets a value indicating whether the controls runs in the context of a designer (e.g.
  34. /// Visual Studio Designer or Expression Blend).
  35. /// </summary>
  36. /// <value>
  37. /// <see langword="true" /> if controls run in design mode; otherwise,
  38. /// <see langword="false" />.
  39. /// </value>
  40. public static bool IsInDesignMode
  41. {
  42. get
  43. {
  44. if (!_isInDesignMode.HasValue)
  45. _isInDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(FrameworkElement)).Metadata.DefaultValue;
  46. return _isInDesignMode.Value;
  47. }
  48. }
  49. private static bool? _isInDesignMode;
  50. /// <summary>
  51. /// Gets the graphics device.
  52. /// </summary>
  53. /// <value>The graphics device.</value>
  54. public GraphicsDevice GraphicsDevice
  55. {
  56. get { return _graphicsDevice; }
  57. }
  58. #endregion
  59. #region Constructors
  60. /// <summary>
  61. /// Initializes a new instance of the <see cref="D3D11Host"/> class.
  62. /// </summary>
  63. public D3D11Host()
  64. {
  65. _timer = new Stopwatch();
  66. Loaded += OnLoaded;
  67. Unloaded += OnUnloaded;
  68. }
  69. #endregion
  70. #region Methods
  71. private void OnLoaded(object sender, RoutedEventArgs eventArgs)
  72. {
  73. if (IsInDesignMode)
  74. return;
  75. InitializeGraphicsDevice();
  76. InitializeImageSource();
  77. Initialize();
  78. StartRendering();
  79. }
  80. private void OnUnloaded(object sender, RoutedEventArgs eventArgs)
  81. {
  82. if (IsInDesignMode)
  83. return;
  84. StopRendering();
  85. Unitialize();
  86. UnitializeImageSource();
  87. UninitializeGraphicsDevice();
  88. }
  89. private static void InitializeGraphicsDevice()
  90. {
  91. lock (_graphicsDeviceLock)
  92. {
  93. _referenceCount++;
  94. if (_referenceCount == 1)
  95. {
  96. // Create Direct3D 11 device.
  97. var presentationParameters = new PresentationParameters
  98. {
  99. // Do not associate graphics device with window.
  100. DeviceWindowHandle = IntPtr.Zero,
  101. };
  102. _graphicsDevice = new GraphicsDevice(GraphicsProfile.HiDef, presentationParameters);
  103. }
  104. }
  105. }
  106. private static void UninitializeGraphicsDevice()
  107. {
  108. lock (_graphicsDeviceLock)
  109. {
  110. _referenceCount--;
  111. if (_referenceCount == 0)
  112. {
  113. _graphicsDevice.Dispose();
  114. _graphicsDevice = null;
  115. }
  116. }
  117. }
  118. private void InitializeImageSource()
  119. {
  120. _d3D11Image = new D3D11Image();
  121. _d3D11Image.IsFrontBufferAvailableChanged += OnIsFrontBufferAvailableChanged;
  122. CreateBackBuffer();
  123. Source = _d3D11Image;
  124. }
  125. private void UnitializeImageSource()
  126. {
  127. _d3D11Image.IsFrontBufferAvailableChanged -= OnIsFrontBufferAvailableChanged;
  128. Source = null;
  129. if (_d3D11Image != null)
  130. {
  131. _d3D11Image.Dispose();
  132. _d3D11Image = null;
  133. }
  134. if (_renderTarget != null)
  135. {
  136. _renderTarget.Dispose();
  137. _renderTarget = null;
  138. }
  139. }
  140. private void CreateBackBuffer()
  141. {
  142. _d3D11Image.SetBackBuffer(null);
  143. if (_renderTarget != null)
  144. {
  145. _renderTarget.Dispose();
  146. _renderTarget = null;
  147. }
  148. int width = Math.Max((int)ActualWidth, 1);
  149. int height = Math.Max((int)ActualHeight, 1);
  150. _renderTarget = new RenderTarget2D(_graphicsDevice, width, height, false, SurfaceFormat.Bgr32, DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.DiscardContents, true);
  151. _d3D11Image.SetBackBuffer(_renderTarget);
  152. }
  153. private void StartRendering()
  154. {
  155. if (_timer.IsRunning)
  156. return;
  157. CompositionTarget.Rendering += OnRendering;
  158. _timer.Start();
  159. }
  160. private void StopRendering()
  161. {
  162. if (!_timer.IsRunning)
  163. return;
  164. CompositionTarget.Rendering -= OnRendering;
  165. _timer.Stop();
  166. }
  167. private void OnRendering(object sender, EventArgs eventArgs)
  168. {
  169. if (!_timer.IsRunning)
  170. return;
  171. // Recreate back buffer if necessary.
  172. if (_resetBackBuffer)
  173. CreateBackBuffer();
  174. // CompositionTarget.Rendering event may be raised multiple times per frame
  175. // (e.g. during window resizing).
  176. var renderingEventArgs = (RenderingEventArgs)eventArgs;
  177. if (_lastRenderingTime != renderingEventArgs.RenderingTime || _resetBackBuffer)
  178. {
  179. _lastRenderingTime = renderingEventArgs.RenderingTime;
  180. GraphicsDevice.SetRenderTarget(_renderTarget);
  181. Render(_timer.Elapsed);
  182. GraphicsDevice.Flush();
  183. }
  184. _d3D11Image.Invalidate(); // Always invalidate D3DImage to reduce flickering
  185. // during window resizing.
  186. _resetBackBuffer = false;
  187. }
  188. /// <summary>
  189. /// Raises the <see cref="FrameworkElement.SizeChanged" /> event, using the specified
  190. /// information as part of the eventual event data.
  191. /// </summary>
  192. /// <param name="sizeInfo">Details of the old and new size involved in the change.</param>
  193. protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
  194. {
  195. _resetBackBuffer = true;
  196. base.OnRenderSizeChanged(sizeInfo);
  197. }
  198. private void OnIsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs eventArgs)
  199. {
  200. if (_d3D11Image.IsFrontBufferAvailable)
  201. {
  202. StartRendering();
  203. _resetBackBuffer = true;
  204. }
  205. else
  206. {
  207. StopRendering();
  208. }
  209. }
  210. #region ----- Example Scene -----
  211. // Source: http://msdn.microsoft.com/en-us/library/bb203926(v=xnagamestudio.40).aspx
  212. // Note: This is just an example. To improve the D3D11Host make the methods
  213. // Initialize(), Unitialize(), and Render() protected virtual or call an
  214. // external "renderer".
  215. Matrix _worldMatrix;
  216. Matrix _viewMatrix;
  217. Matrix _projectionMatrix;
  218. VertexDeclaration vertexDeclaration;
  219. VertexBuffer _vertexBuffer;
  220. BasicEffect _basicEffect;
  221. private void Initialize()
  222. {
  223. float tilt = MathHelper.ToRadians(0); // 0 degree angle
  224. // Use the world matrix to tilt the cube along x and y axes.
  225. _worldMatrix = Matrix.CreateRotationX(tilt) * Matrix.CreateRotationY(tilt);
  226. _viewMatrix = Matrix.CreateLookAt(new Vector3(5, 5, 5), Vector3.Zero, Vector3.Up);
  227. _projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
  228. MathHelper.ToRadians(45), // 45 degree angle
  229. (float)GraphicsDevice.Viewport.Width /
  230. (float)GraphicsDevice.Viewport.Height,
  231. 1.0f, 100.0f);
  232. _basicEffect = new BasicEffect(GraphicsDevice);
  233. _basicEffect.World = _worldMatrix;
  234. _basicEffect.View = _viewMatrix;
  235. _basicEffect.Projection = _projectionMatrix;
  236. // primitive color
  237. _basicEffect.AmbientLightColor = new Vector3(0.1f, 0.1f, 0.1f);
  238. _basicEffect.DiffuseColor = new Vector3(1.0f, 1.0f, 1.0f);
  239. _basicEffect.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f);
  240. _basicEffect.SpecularPower = 5.0f;
  241. _basicEffect.Alpha = 1.0f;
  242. _basicEffect.LightingEnabled = true;
  243. if (_basicEffect.LightingEnabled)
  244. {
  245. _basicEffect.DirectionalLight0.Enabled = true; // enable each light individually
  246. if (_basicEffect.DirectionalLight0.Enabled)
  247. {
  248. // x direction
  249. _basicEffect.DirectionalLight0.DiffuseColor = new Vector3(1, 0, 0); // range is 0 to 1
  250. _basicEffect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(-1, 0, 0));
  251. // points from the light to the origin of the scene
  252. _basicEffect.DirectionalLight0.SpecularColor = Vector3.One;
  253. }
  254. _basicEffect.DirectionalLight1.Enabled = true;
  255. if (_basicEffect.DirectionalLight1.Enabled)
  256. {
  257. // y direction
  258. _basicEffect.DirectionalLight1.DiffuseColor = new Vector3(0, 0.75f, 0);
  259. _basicEffect.DirectionalLight1.Direction = Vector3.Normalize(new Vector3(0, -1, 0));
  260. _basicEffect.DirectionalLight1.SpecularColor = Vector3.One;
  261. }
  262. _basicEffect.DirectionalLight2.Enabled = true;
  263. if (_basicEffect.DirectionalLight2.Enabled)
  264. {
  265. // z direction
  266. _basicEffect.DirectionalLight2.DiffuseColor = new Vector3(0, 0, 0.5f);
  267. _basicEffect.DirectionalLight2.Direction = Vector3.Normalize(new Vector3(0, 0, -1));
  268. _basicEffect.DirectionalLight2.SpecularColor = Vector3.One;
  269. }
  270. }
  271. vertexDeclaration = new VertexDeclaration(new[]
  272. {
  273. new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
  274. new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
  275. new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0)
  276. });
  277. Vector3 topLeftFront = new Vector3(-1.0f, 1.0f, 1.0f);
  278. Vector3 bottomLeftFront = new Vector3(-1.0f, -1.0f, 1.0f);
  279. Vector3 topRightFront = new Vector3(1.0f, 1.0f, 1.0f);
  280. Vector3 bottomRightFront = new Vector3(1.0f, -1.0f, 1.0f);
  281. Vector3 topLeftBack = new Vector3(-1.0f, 1.0f, -1.0f);
  282. Vector3 topRightBack = new Vector3(1.0f, 1.0f, -1.0f);
  283. Vector3 bottomLeftBack = new Vector3(-1.0f, -1.0f, -1.0f);
  284. Vector3 bottomRightBack = new Vector3(1.0f, -1.0f, -1.0f);
  285. Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
  286. Vector2 textureTopRight = new Vector2(1.0f, 0.0f);
  287. Vector2 textureBottomLeft = new Vector2(0.0f, 1.0f);
  288. Vector2 textureBottomRight = new Vector2(1.0f, 1.0f);
  289. Vector3 frontNormal = new Vector3(0.0f, 0.0f, 1.0f);
  290. Vector3 backNormal = new Vector3(0.0f, 0.0f, -1.0f);
  291. Vector3 topNormal = new Vector3(0.0f, 1.0f, 0.0f);
  292. Vector3 bottomNormal = new Vector3(0.0f, -1.0f, 0.0f);
  293. Vector3 leftNormal = new Vector3(-1.0f, 0.0f, 0.0f);
  294. Vector3 rightNormal = new Vector3(1.0f, 0.0f, 0.0f);
  295. var cubeVertices = new VertexPositionNormalTexture[36];
  296. // Front face.
  297. cubeVertices[0] = new VertexPositionNormalTexture(topLeftFront, frontNormal, textureTopLeft);
  298. cubeVertices[1] = new VertexPositionNormalTexture(bottomLeftFront, frontNormal, textureBottomLeft);
  299. cubeVertices[2] = new VertexPositionNormalTexture(topRightFront, frontNormal, textureTopRight);
  300. cubeVertices[3] = new VertexPositionNormalTexture(bottomLeftFront, frontNormal, textureBottomLeft);
  301. cubeVertices[4] = new VertexPositionNormalTexture(bottomRightFront, frontNormal, textureBottomRight);
  302. cubeVertices[5] = new VertexPositionNormalTexture(topRightFront, frontNormal, textureTopRight);
  303. // Back face.
  304. cubeVertices[6] = new VertexPositionNormalTexture(topLeftBack, backNormal, textureTopRight);
  305. cubeVertices[7] = new VertexPositionNormalTexture(topRightBack, backNormal, textureTopLeft);
  306. cubeVertices[8] = new VertexPositionNormalTexture(bottomLeftBack, backNormal, textureBottomRight);
  307. cubeVertices[9] = new VertexPositionNormalTexture(bottomLeftBack, backNormal, textureBottomRight);
  308. cubeVertices[10] = new VertexPositionNormalTexture(topRightBack, backNormal, textureTopLeft);
  309. cubeVertices[11] = new VertexPositionNormalTexture(bottomRightBack, backNormal, textureBottomLeft);
  310. // Top face.
  311. cubeVertices[12] = new VertexPositionNormalTexture(topLeftFront, topNormal, textureBottomLeft);
  312. cubeVertices[13] = new VertexPositionNormalTexture(topRightBack, topNormal, textureTopRight);
  313. cubeVertices[14] = new VertexPositionNormalTexture(topLeftBack, topNormal, textureTopLeft);
  314. cubeVertices[15] = new VertexPositionNormalTexture(topLeftFront, topNormal, textureBottomLeft);
  315. cubeVertices[16] = new VertexPositionNormalTexture(topRightFront, topNormal, textureBottomRight);
  316. cubeVertices[17] = new VertexPositionNormalTexture(topRightBack, topNormal, textureTopRight);
  317. // Bottom face.
  318. cubeVertices[18] = new VertexPositionNormalTexture(bottomLeftFront, bottomNormal, textureTopLeft);
  319. cubeVertices[19] = new VertexPositionNormalTexture(bottomLeftBack, bottomNormal, textureBottomLeft);
  320. cubeVertices[20] = new VertexPositionNormalTexture(bottomRightBack, bottomNormal, textureBottomRight);
  321. cubeVertices[21] = new VertexPositionNormalTexture(bottomLeftFront, bottomNormal, textureTopLeft);
  322. cubeVertices[22] = new VertexPositionNormalTexture(bottomRightBack, bottomNormal, textureBottomRight);
  323. cubeVertices[23] = new VertexPositionNormalTexture(bottomRightFront, bottomNormal, textureTopRight);
  324. // Left face.
  325. cubeVertices[24] = new VertexPositionNormalTexture(topLeftFront, leftNormal, textureTopRight);
  326. cubeVertices[25] = new VertexPositionNormalTexture(bottomLeftBack, leftNormal, textureBottomLeft);
  327. cubeVertices[26] = new VertexPositionNormalTexture(bottomLeftFront, leftNormal, textureBottomRight);
  328. cubeVertices[27] = new VertexPositionNormalTexture(topLeftBack, leftNormal, textureTopLeft);
  329. cubeVertices[28] = new VertexPositionNormalTexture(bottomLeftBack, leftNormal, textureBottomLeft);
  330. cubeVertices[29] = new VertexPositionNormalTexture(topLeftFront, leftNormal, textureTopRight);
  331. // Right face.
  332. cubeVertices[30] = new VertexPositionNormalTexture(topRightFront, rightNormal, textureTopLeft);
  333. cubeVertices[31] = new VertexPositionNormalTexture(bottomRightFront, rightNormal, textureBottomLeft);
  334. cubeVertices[32] = new VertexPositionNormalTexture(bottomRightBack, rightNormal, textureBottomRight);
  335. cubeVertices[33] = new VertexPositionNormalTexture(topRightBack, rightNormal, textureTopRight);
  336. cubeVertices[34] = new VertexPositionNormalTexture(topRightFront, rightNormal, textureTopLeft);
  337. cubeVertices[35] = new VertexPositionNormalTexture(bottomRightBack, rightNormal, textureBottomRight);
  338. _vertexBuffer = new VertexBuffer(GraphicsDevice, vertexDeclaration, cubeVertices.Length, BufferUsage.None);
  339. _vertexBuffer.SetData(cubeVertices);
  340. }
  341. private void Unitialize()
  342. {
  343. _vertexBuffer.Dispose();
  344. _vertexBuffer = null;
  345. vertexDeclaration.Dispose();
  346. vertexDeclaration = null;
  347. _basicEffect.Dispose();
  348. _basicEffect = null;
  349. }
  350. private void Render(TimeSpan time)
  351. {
  352. GraphicsDevice.Clear(Color.SteelBlue);
  353. GraphicsDevice.RasterizerState = RasterizerState.CullNone;
  354. GraphicsDevice.SetVertexBuffer(_vertexBuffer);
  355. // Rotate cube around up-axis.
  356. _basicEffect.World = Matrix.CreateRotationY((float)time.Milliseconds / 1000 * MathHelper.TwoPi) * _worldMatrix;
  357. foreach (var pass in _basicEffect.CurrentTechnique.Passes)
  358. {
  359. pass.Apply();
  360. GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 12);
  361. }
  362. }
  363. #endregion
  364. #endregion
  365. }
  366. }