9

Summary (TL:DR version)

Ultimately our goal is to be able to utilize OpenGL ES code in a WPF application natively (i.e. not SharpGL, etc.) and without Airspace or driver issues, possible using Google's ANGLE project.

Background:

One of the things I like about OpenGL over DirectX is its cross-platform capability. It has excellent support on both OS X and Linux, and also on Android and iOS via ES. However, on Windows, using it is marred with driver issues, or worse, a lot of cards simply don't implement it properly.

Enter Google's ANGLE project, or Almost-Native-Graphics-Layer-Engine.

ANGLE is an OpenGL ES 2.0 wrapper around a Direct3D implementation, meaning you can write OpenGL ES 2.0 code to be run on Windows without the need for actual OpenGL drivers. It not only passes the ES compatibility tests, but it's actually how Chrome does all of its graphics rendering, including WebGL so it definitely is a proven technology.

The Question:

We know WPF has a D3DImage control which lets you host Direct3D rendering within WPF and it supposedly does away with the airspace issues by properly composting its output to the WPF render thread. My question is since ANGLE is implemented via Direct3D, and D3DImage is a target for Direct3D rendering, is it possible to combine the two, allowing us to write OpenGL ES code and host it in a WPF application on Windows, all without driver or airspace issues?

This would be the 'Holy Grail' for us.

However, I keep hitting a wall around getting ANGLE to target its rendering on the D3D surface created by the D3DImage control since ANGLE wants to use its own. I'm not sure this is even possible. I can't find a single article or reference anywhere of anyone even discussing this, let alone attempting it.

Again to be clear though, the goal is to get our shared, cross-platform OpenGL (or ES) code to work in a WPF application without airspace issues or OpenGL driver requirements. My suggestion of using ANGLE/D3DImage is just that... an attempt. It's the 'means' I've come up with so far, but that's just a potential means to our goal, not the goal itself. Anything else that would get us to the same solution would be more than welcome.

Mark A. Donohoe
  • 23,825
  • 17
  • 116
  • 235
  • Do you still need help with this question? If so, do you need to be able to combine WPF and OpenGL rendering on the same region (i.e. blend OpenGL with WPF) or do you just wish to embed OpenGL inside a WPF window? The latter would be trivial with [OpenTK.GLControl](http://www.opentk.com) and a WindowsFormsHost. The former requires some work (but is still possible.) – The Fiddler Mar 13 '14 at 15:56
  • Yes, I'd still appreciate assistance here. And while no, we don't need to combine WPF rendering and OpenGL in the same region, if I'm correct, your WinFormsHost approach still falls victim to AirSpace issues. Then again, if our WPF portions within that same window wouldn't overlap with the OpenGL portions, that may be a solution. Not sure without trying it. Can you post a proper andswer with an example of using OpenTK.GLControl? If so, I'll mark yours as accepted. – Mark A. Donohoe Mar 14 '14 at 14:19
  • One other comment... again, we want to simply reuse our already existing OpenGL ES rendering code. We don't want to translate it to another library, etc. (The general setup code of course can, and usually is somewhat platform-specific so that's fine. I mean the actual drawing calls themselves so it looks identical on WPF, iOS, Android, etc. and runs as close as possible to native speeds. – Mark A. Donohoe Mar 14 '14 at 14:22
  • I am preparing an example project that shows how to use OpenGL *and* OpenGL ES / ANGLE using OpenTK.GLControl inside WPF. – The Fiddler Mar 14 '14 at 16:36

1 Answers1

4

I have uploaded a github project that demonstrates how to integrate OpenGL rendering into a WPF application via OpenTK.GLControl.

The code is surprisingly simple:

  1. Add a WindowsFormsHost to the WPF application
  2. Construct an OpenTK.GLControl and attach it to the WindowsFormsHost
    • Pass GraphicsContextFlags.Default for a desktop OpenGL context
    • Pass GraphicsContextFlags.Embedded for an OpenGL ES (ANGLE) context
  3. Render using normal OpenGL or OpenGL ES commands

Hint: OpenTK and OpenTK.GLControl are also available as NuGet packages. There is a new release due tomorrow with improved ANGLE support.

Note that the WindowsFormsHost approach is subject to airspace restrictions. If this is an issue, see my answer here for a solution.

// This code is public domain
#define USE_ANGLE

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using OpenTK;
using OpenTK.Graphics;

#if USE_ANGLE
using OpenTK.Graphics.ES20;
#else
using OpenTK.Graphics.OpenGL;
#endif

namespace WPF.Angle
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        GLControl glControl;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void WindowsFormsHost_Initialized(object sender, EventArgs e)
        {
            var flags = GraphicsContextFlags.Default;
#if USE_ANGLE
            flags = GraphicsContextFlags.Embedded;
#endif
            glControl = new GLControl(new GraphicsMode(32, 24), 2, 0, flags);
            glControl.MakeCurrent();
            glControl.Paint += GLControl_Paint;
            glControl.Dock = DockStyle.Fill;
            (sender as WindowsFormsHost).Child = glControl;
        }

        private void GLControl_Paint(object sender, PaintEventArgs e)
        {
            GL.ClearColor(
                (float)Red.Value,
                (float)Green.Value,
                (float)Blue.Value,
                1);
            GL.Clear(
                ClearBufferMask.ColorBufferBit |
                ClearBufferMask.DepthBufferBit |
                ClearBufferMask.StencilBufferBit);

            glControl.SwapBuffers();
        }

        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            glControl.Invalidate();
        }
    }
}
Community
  • 1
  • 1
The Fiddler
  • 2,566
  • 18
  • 23
  • Two things... one, you didn't provide a link to your GitHub project, and two, again, we want to use our already existing C files, not a compatible toolkit (unless that lets us use our existing code.) Again, the issue is cross-platform code, not OpenGL for OpenGL's sake. Hope that makes sense, and if so, you can address it. – Mark A. Donohoe Mar 16 '14 at 06:49
  • You are right, I have added the [missing link to github](https://github.com/thefiddler/opentk-wpf). This code demonstrates how to create an OpenGL / OpenGL ES context inside a WPF window. How your render afterwards is up to you - the context does not care if you are using C, C# or something else entirely. For example, you could call into your C renderer via a [DllImport]. Does this answer your question? – The Fiddler Mar 16 '14 at 17:50
  • Hmmm... I believe so, but I'll have to look at your sample project and see what it does. Still, I'll give you the answer anyway because of the information that you did provide. Any chance you could provide contact info in your GitHub project in case I have any questions? If we use what you provided, we'll even give you attribution if you want it. – Mark A. Donohoe Mar 18 '14 at 05:20
  • @TheFiddler You say: "you could call into your C renderer via a [DllImport]". Do you think it's possible in the other way around, like passing a window handle of the WPF (GLControl) to the C++ render. Basically I have the rendering code, I just want a window where to render. – boli May 22 '14 at 10:04
  • OpenGL uses thread-local storage to store its context. Once you call `GLControl.MakeCurrent()` on a specific thread, you can issue OpenGL commands on that thread from either C# or C++ without any issue. The window handle is not required. Check the [GraphicsContext documentation](http://www.opentk.com/doc/graphics/graphicscontext) for more information. – The Fiddler May 30 '14 at 06:41
  • Is this still the best way to integrate an OpenGL window into a WPF project? I require WPF widgets alongside my OpenGL window including - text boxes, buttons, lists etc. – Fra Dec 03 '15 at 23:38
  • @TheFiddler Hi Fiddler, Thank you very much for your answer, I accidentally ended up here searching for alternative solutions to SkiaSharp for rendering in 2D objects in WPF. Can you please point me in the right direction whether this library can be used for 2D? And if so where should I start! For example how can I create a simple line. I am totally new to OpenGL and OpenTK. Thank you. – Vahid Nov 03 '18 at 19:31