Click here to Skip to main content
15,892,809 members
Articles / Desktop Programming / WPF

Introduction to D3DImage

Rate me:
Please Sign up or sign in to vote.
5.00/5 (77 votes)
11 Aug 2008CPOL24 min read 418.1K   18.4K   219  
.NET 3.5 SP1 is here! It's time to break out your DirectX skills. This article provides the information necessary to get started using a new DirectX interop feature in WPF called D3DImage.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace D3DImageSample
{
    public partial class Window1 : Window
    {
        [StructLayout(LayoutKind.Sequential)]
        public class SIZE
        {
            public int Width = 0;
            public int Height = 0;
        }

        [DllImport("D3DScene.dll")]
        private static extern IntPtr InitializeScene();

        [DllImport("D3DScene.dll")]
        private static extern void RenderScene([In, Out] SIZE size);

        [DllImport("D3DScene.dll")]
        private static extern void ReleaseScene();

        private D3DImage _di;
        private IntPtr _scene;

        public Window1()
        {
            // create a D3DImage to host the scene and
            // monitor it for changes in front buffer availability
            _di = new D3DImage();
            _di.IsFrontBufferAvailableChanged 
                += new DependencyPropertyChangedEventHandler(OnIsFrontBufferAvailableChanged);

            // make a brush of the scene available as a resource on the window
            Resources["RotatingTriangleScene"] = new ImageBrush(_di);

            // begin rendering the custom D3D scene into the D3DImage
            BeginRenderingScene();

            // parse the XAML
            InitializeComponent();
        }

        private void OnIsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            // if the front buffer is available, then WPF has just created a new
            // D3D device, so we need to start rendering our custom scene
            if (_di.IsFrontBufferAvailable)
            {
                BeginRenderingScene();
            }
            else
            {
                // If the front buffer is no longer available, then WPF has lost its
                // D3D device so there is no reason to waste cycles rendering our
                // custom scene until a new device is created.
                StopRenderingScene();
            }
        }

        private void BeginRenderingScene()
        {
            if (_di.IsFrontBufferAvailable)
            {
                // create a custom D3D scene and get a pointer to its surface
                _scene = InitializeScene();

                // set the back buffer using the new scene pointer
                _di.Lock();
                _di.SetBackBuffer(D3DResourceType.IDirect3DSurface9, _scene);
                _di.Unlock();

                // leverage the Rendering event of WPF's composition target to
                // update the custom D3D scene
                CompositionTarget.Rendering += OnRendering;
            }
        }

        private void StopRenderingScene()
        {
            // This method is called when WPF loses its D3D device.
            // In such a circumstance, it is very likely that we have lost 
            // our custom D3D device also, so we should just release the scene.
            // We will create a new scene when a D3D device becomes 
            // available again.
            CompositionTarget.Rendering -= OnRendering;
            ReleaseScene();
            _scene = IntPtr.Zero;
        }

        private void OnRendering(object sender, EventArgs e)
        {
            // when WPF's composition target is about to render, we update our 
            // custom render target so that it can be blended with the WPF target
            UpdateScene();
        }

        private void UpdateScene()
        {
            if (_di.IsFrontBufferAvailable && _scene != IntPtr.Zero)
            {
                // lock the D3DImage
                _di.Lock();

                // update the scene (via a call into our custom library)
                SIZE size = new SIZE();
                RenderScene(size); 

                // invalidate the updated region of the D3DImage (in this case, the whole image)
                _di.AddDirtyRect(new Int32Rect(0, 0, size.Width, size.Height));

                // unlock the D3DImage
                _di.Unlock();
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
Dr. WPF is a WPF Disciple! Check out the doctor's blog and bio for more information.

Comments and Discussions