D3D11Host.cs 17 KB

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