Inhaltsverzeichnis

    Kommentare

    D3DImage und SlimDX

    Autor: SteveKr
    Mit dem SP1 für .Net 3.5 sind auch neue Klassen für die WPF hinzugekommen. Eine davon heißt D3DImage (System.Windows.Interop.D3DImage), wird von ImageSource abgeleitet und bietet die Möglichkeit ein “eigenes” DirectX Surface in einer WPF-Anwendung darzustellen. Im Folgenden soll gezeigt werden, wie man die Klasse zusammen mit SlimDX einsetzt.

    Zunächst erstellen wir ein Image-Control in unserem Fenster und geben diesem als Quelle das neue D3DImage:
    <Window x:Class="WpfApplication1_d3dimage.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:System.Windows.Interop;assembly=PresentationCore"
        Title="Window1" Height="436" Width="468" Loaded="Window_Loaded">

        <Grid>
            <Image x:Name="output">
                <Image.Source>
                    <i:D3DImage x:Name="d3dimage">
                    </i:D3DImage>
                </Image.Source>
            </Image>
        </Grid>
    </Window>

    Anschließend wechseln wir in die Codeansicht und erstellen die benötigten SlimDX-Objekte (Device und ggf. Sprite, Texture, etc.). Da wir einen Handle benötigen erstellen wir zudem ein HwndSource-Objekt.
    Device device;
    Sprite sprite;
    Texture texture;

    public void InitializeD3D()
    {
        HwndSource hwnd = new HwndSource(0, 0, 0, 0, 0, "test", IntPtr.Zero);

        PresentParameters pp = new PresentParameters();
        pp.SwapEffect = SwapEffect.Discard;
        pp.DeviceWindowHandle = hwnd.Handle;
        pp.Windowed = true;
        pp.BackBufferWidth = 400;
        pp.BackBufferHeight = 400;
        pp.BackBufferFormat = Format.X8R8G8B8;

        device = new Device(
            0,
            DeviceType.Hardware,
            hwnd.Handle,
            CreateFlags.HardwareVertexProcessing,
            pp
            );

        sprite = new Sprite(device);
        texture = Texture.FromFile(device, "test.png");
    }

    Die D3DImage-Klasse besitzt eine SetBackbuffer mit der wir das Surface angeben können, das letztlich im Image-Control angezeigt werden soll. In diesem Fall haben wir kein extra Surface erstellt, sondern begnügen uns mit dem Backbuffer.

    Wir erstellen nun im Loaded-Event des Fensters Device und konsorten durch den Aufruf der InitializeD3D-Methode und weisen anschließend dem D3D-Image unseren Backbuffer zu. Außerdem registrieren wir einen neuen EventHandler für das Rendering-Event, um später bei jedem Rendern des Fensters, auch unser Sprite neu zu zeichnen.
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        InitializeD3D();
        CompositionTarget.Rendering += OnRendering;

        d3dimage.Lock();
        d3dimage.SetBackBuffer(
          D3DResourceType.IDirect3DSurface9,
          device.GetBackBuffer(0, 0).ComPointer
          );
        d3dimage.Unlock();
    }

    private void OnRendering(object sender, EventArgs e)
    {
        RenderD3D();
    }

    Der Code zum Zeichnen des Sprites unterliegt keiner Änderung und schaut wie gewohnt aus:
    public void RenderD3D()
    {
        device.Clear(ClearFlags.Target, new Color4(System.Drawing.Color.Black), 0, 0);
        device.BeginScene();

        sprite.Begin(SpriteFlags.AlphaBlend);
        sprite.Draw(texture, Vector3.Zero, Vector3.Zero, new Color4(System.Drawing.Color.White));
        sprite.End();

        device.EndScene();
        device.Present();
    }

    Damit die Änderungen im Backbuffer auch im Image sichtbar werden muss zudem die AddDirtyRect-Methode der D3DImage-Klasse aufgerufen werden. Abschließend schaut die OnRendering-Methode folgendermaßen aus:
    private void OnRendering(object sender, EventArgs e)
    {
        d3dimage.Lock();

        RenderD3D();
        d3dimage.AddDirtyRect(new Int32Rect(0, 0, d3dimage.PixelWidth, d3dimage.PixelHeight));

        d3dimage.Unlock();
    }


    Quellen/Weitere Infos:


    Für die Verwendung von D3DImage mit XNA: XNA und WPF