I know the terminology of this question must be all wrong, but please bear with me and try to see things from my layman's point of view (I have no formation in computer technology, I'm a self taught enthusiast. The closest I get from a formal education in programming language is my school's robotics club).
What I want is to be able to use managed DirectX 12 as the "background" of my application, with a game loop and all. And, if possible, to be able to have WPF controls like a ribbon or a toolbox or a menu around the actual directX game. I've been looking all over the internet and all I find is very old stuff for Windows and DirectX 9.0; i'm hoping there's something new these days.
I tryed the Windows Form approach, which is basically this:
using System;
using System.Windows;
using System.Windows.Interop;
using Microsoft.DirectX.Direct3D;
using DColor = System.Drawing.Color;
public partial class MainWindow : Window
{
Device device;
public MainWindow()
{
InitializeComponent();
initDevice();
}
private void initDevice()
{
try
{
PresentParameters parameters = new PresentParameters();
parameters.Windowed = true;
parameters.SwapEffect = SwapEffect.Discard;
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
device = new Device(0, DeviceType.Hardware, windowHandle, CreateFlags.HardwareVertexProcessing, parameters);
}
catch(Exception e)
{
MessageBox.Show("initDevice threw an Exception\n" + e.Message, "ERROR", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void render()
{
device.Clear(ClearFlags.Target, DColor.LightGreen, 0f, 1);
device.Present();
}
}
No exception is thrown, the window is never rendered at all. The application runs, but the window doesn't show up. I didn't think this would work, because there's no game loop and render
doesn't get invoked from anywhere, but I didn't expect the window not even being displayed. If I comment out the line that invokes initDevice(), WPF's blank window is shown normally
Then I that discovered the CompositionTarget.Rendering
event gets called once every frame (or tick?), so the handler for this event must be used as the game loop.
and so I tried this:
using System;
using System.Drawing;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Forms.Integration;
using Microsoft.DirectX.Direct3D;
using DColor = System.Drawing.Color;
using System.Windows.Forms;
public partial class MainWindow : Window
{
Device device = null;
MemoryStream stream;
PictureBox display;
WindowsFormsHost host;
public MainWindow()
{
InitializeComponent();
initDevice();
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
render();
}
private void initDevice()
{
try
{
PresentParameters parameters = new PresentParameters();
parameters.Windowed = true;
parameters.SwapEffect = SwapEffect.Discard;
device = new Device(0, DeviceType.Hardware, display, CreateFlags.HardwareVertexProcessing, parameters);
stream = new MemoryStream();
device.SetRenderTarget(0, new Surface(device, stream, Pool.Managed));
}
catch(Exception e)
{
System.Windows.MessageBox.Show("initDevice threw an Exception\n" + e.Message, "ERROR", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void render()
{
device.Clear(ClearFlags.Target, DColor.LightGreen, 0f, 1);
device.Present();
display.Image = Image.FromStream(stream);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
host = new WindowsFormsHost();
display = new PictureBox();
host.Child = display;
mainGrid.Children.Add(host);
}
}
Still no window is shown, even though the application is running and not crashing.
Finally I tried the same thing but without handling CompositionTarget.Rendering
, but using a DispatcherTimer instead, and called render from inside its Tick
event handler. Same result: no Window.
Can anyone point me to the right direction?