using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Interop;
using System.Runtime.InteropServices;
namespace IE_WPF_D3D
{
///
/// Tool object for output OCCT rendering with Direct3D.
///
class D3DViewer
{
/// Direct3D renderer.
private IntPtr myD3DRender;
/// Direct3D output image.
private D3DImage myD3DImage = new D3DImage ();
/// Direct3D color surface.
private IntPtr myColorSurf;
public OCCViewer Viewer;
/// Creates new Direct3D-based OCCT viewer.
public D3DViewer ()
{
myD3DImage.IsFrontBufferAvailableChanged
+= new DependencyPropertyChangedEventHandler (OnIsFrontBufferAvailableChanged);
BeginRenderingScene ();
}
/// Creates new Direct3D-based OCCT viewer.
private void OnIsFrontBufferAvailableChanged (object sender, DependencyPropertyChangedEventArgs e)
{
// If the front buffer is available, then WPF has just created a new
// Direct3D device, thus we need to start rendering our custom scene
if (myD3DImage.IsFrontBufferAvailable)
{
BeginRenderingScene ();
}
else
{
// If the front buffer is no longer available, then WPF has lost Direct3D
// device, thus we need to stop rendering until the new device is created
StopRenderingScene ();
}
}
private bool myIsFailed = false;
/// Initializes Direct3D-OCCT rendering.
private void BeginRenderingScene ()
{
if (myIsFailed)
{
return;
}
if (myD3DImage.IsFrontBufferAvailable)
{
IntPtr aWinHandle;
IntPtr aD3DDevice;
// Initialize Direct3D device and render target
myD3DRender = Direct3DProxy.InitRender(out aWinHandle, out aD3DDevice);
Viewer = new OCCViewer();
if (!Viewer.InitInterop (aWinHandle, aD3DDevice))
{
MessageBox.Show ("Failed to initialize OpenGL-Direct3D interoperability!",
"Error", MessageBoxButton.OK, MessageBoxImage.Error);
myIsFailed = true;
if (myD3DRender != IntPtr.Zero)
Direct3DProxy.ReleaseRender(ref myD3DRender);
return;
}
// Leverage the Rendering event of WPF composition
// target to update the our custom Direct3D scene
CompositionTarget.Rendering += OnRendering;
}
}
/// Initializes Direct3D-OCCT rendering.
public void StopRenderingScene ()
{
// This method is called when WPF loses its Direct3D device,
// so we should just release our custom Direct3D scene
CompositionTarget.Rendering -= OnRendering;
if (myD3DRender != IntPtr.Zero)
Direct3DProxy.ReleaseRender(ref myD3DRender);
myColorSurf = IntPtr.Zero;
}
/// Initializes Direct3D-OCCT rendering.
private void OnRendering (object sender, EventArgs e)
{
UpdateScene ();
}
/// Current size of rendering window.
private WndSize mySize = new WndSize(1, 1);
/// Initializes Direct3D-OCCT rendering.
private void UpdateScene ()
{
if (!myIsFailed && myD3DImage.IsFrontBufferAvailable && myColorSurf != IntPtr.Zero)
{
myD3DImage.Lock ();
{
// Update the scene (via a call into our custom library)
Viewer.View.RedrawView ();
// Invalidate the updated region of the D3DImage
myD3DImage.AddDirtyRect(new Int32Rect(0, 0, mySize.cx, mySize.cy));
}
myD3DImage.Unlock ();
}
}
/// Resizes Direct3D surfaces and OpenGL FBO.
public void Resize (int theSizeX, int theSizeY)
{
mySize = new WndSize(theSizeX, theSizeY);
if (!myIsFailed && myD3DImage.IsFrontBufferAvailable)
{
IntPtr aColorSurfShare;
// Initialize Direct3D device and render target
Direct3DProxy.ResizeWindow(ref myD3DRender, ref mySize, out myColorSurf, out aColorSurfShare);
// Set the back buffer for Direct3D WPF image
myD3DImage.Lock ();
{
myD3DImage.SetBackBuffer (D3DResourceType.IDirect3DSurface9, myColorSurf);
}
myD3DImage.Unlock ();
Viewer.View.ResizeBridgeFBO(mySize.cx, mySize.cy, myColorSurf, aColorSurfShare);
}
}
public D3DImage Image
{
get
{
return myD3DImage;
}
}
}
}