Can QOpenGLWidget be integrated with third party OpenGL library? - c++

Legacy QGLWidget could be integrated with rendering libraries (like SFML) by passing winId() result to the rendering library. But I can't make QOpenGLWidget work that way. After making it MainWindow's central widget I get series of warnings like QOpenGLWidget cannot be used as a native child widget. Consider setting Qt::AA_DontCreateNativeWidgetAncestors and Siblings.. Furthermore, the documentation says "QGLWidget on the other hand uses a native window and surface. (...) QOpenGLWidget avoids this by not creating a separate native window.". Can QOpenGLWidget be integrated with third party OpenGL software at all, or is it unsupported now?

You need to create a QWindow, initialize it and integrate into application with QWidget::createWindowContainer
class MyNativeWindow : QWindow
{
MyNativeWindow() : QWindow
{
setSurfaceType(QWindow::OpenGLSurface);
}
};
MyNativeWindow *nativeW = new MyNativeWindow();
QWidget *w = QWidget::createWindowContainer( nativeW );
// Use w as a simple QWidget
In some cases you don't need to use winId to get HWND. It is enough to know OpenGL context id. For custom gl context manipulation you may use QOpenGLContext class.
Be careful, because if your third party libraries will create native windows (in OS X) by themselves, you will have a lot of bugs with Qt. We are tied to fix bugs in our project. (Undockable docks, keyboard focus lost, impossibility of opening menus, errors with fullscreen etc.)
You may look at this code sample. And a custom context code sample.

Related

How to embed opencascade V3d_View in gtkmm widget

I'm trying to port the code from https://github.com/eryar/occQt to gtkmm, by creating a custom widget and overriding the Gtk::widget::on_realize() method like
void OccView::on_realize() {
// Create Aspect_DisplayConnection
Handle(Aspect_DisplayConnection) display_connection = new Aspect_DisplayConnection();
// Get graphic driver if it exists, otherwise initialize it.
Handle(Graphic3d_GraphicDriver) graphic_driver;
if (!graphic_driver) {
graphic_driver = new OpenGl_GraphicDriver(display_connection);
}
// Get window handle. This returns something suitable for all platforms.
Window x_window = GDK_SURFACE_XID(get_native()->get_surface()->gobj());
// Create window for platform.
Handle(Xw_Window) xw_window = new Xw_Window(display_connection, x_window);
// Create V3dViewer and V3d_View
mViewer = new V3d_Viewer(graphic_driver, Standard_ExtString("viewer3d"));
mView = mViewer->CreateView();
// Set window for the view
mView->SetWindow(xw_window);
if (!xw_window->IsMapped()) {
xw_window->Map();
}
// Create AISInteractiveContext
mContext = new AIS_InteractiveContext(mViewer);
// Set up lights etc
mViewer->SetDefaultLights();
mViewer->SetLightOn();
mView->SetBackgroundColor(Quantity_NOC_BLACK);
mView->MustBeResized();
mView->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_ZBUFFER);
mContext->SetDisplayMode(AIS_Shaded, Standard_True);
// Call base method
Gtk::Widget::on_realize();
}
but the Gtk::Window stays empty after appending the OccView object. What am I doing wrong? Is there a working example on how to integrate the Opencascade V3d_View into a Gtk::Widget, or the gtkmm framework in general?
I haven't used GTK since university, so my experience is pretty basic here.
There are two basic approaches for embedding OpenGL-based viewer into GTK:
Ask OCCT to create OpenGL context for a native window taken from a normal Widget or entire window.
Wrap existing OpenGL context created by GUI library itself, e.g. Gtk::GLArea.
Your current code tries to follow the first approach used by conventional samples for Qt Widgets and MFC coming with OCCT. I guess it should be feasible, but implies some limitations and issues with mixing GTK widgets, as GTK will not be aware of OpenGL usage.
In contrast, Gtk::GLArea looks like a "modern" way for embedding OpenGL renderer designed by GTK developers and expected to work transparently.
Therefore, I've tried implementing a Hello-World sample using Gtk::GLArea (based on a development snapshot of OCCT 7.6.0dev):
https://github.com/gkv311/occt-samples-gtk
I don't bring the whole code of the sample here, as it is quite large in size.
Putting OCCT Viewer into Gtk::GLArea includes some tricky parts like:
Wrapping native Window into Aspect_Window (it could be also Xw_Window like in your sample, more general Aspect_NeutralWindow or another subclass).
Wrapping OpenGL context created by Gtk::GLArea into Aspect_RenderingContext/OpenGl_Context.
Wrapping offscreen buffer (FBO) used by Gtk::GLArea for rendering content into OpenGl_FrameBuffer.
Putting all viewer redraws into dedicated callback for Gtk::GLArea::signal_render().
Redirecting user input to viewer (with help of AIS_ViewController).
It is important to note, that GTK may be run in different context:
X11 server - X Window is created and GLX is used for OpenGL.
This is default OCCT configuration for Linux;
Wayland - native window is not X Window and EGL is used for OpenGL context.
OCCT does support EGL but as a dedicated configuration as alternative to GLX, while GTK handles this in runtime somehow. In addition, OCCT does not (yet) provide any wrapper for a Wayland native window, though it might be not critical for using.
GTK also has an option to use OpenGL ES instead of OpenGL.
Initially I expected Gtk::GLArea to work natively, but instead a very basic sample (without OCCT viewer) displays artifacts to me (widgets randomly blacked) on Xubuntu 18.04, though it works as expected on Ubuntu 21.04 (within Xorg session). I don't know if it is a bug fixed in GTK implementation, or there is something that should be fixed in a sample to workaround problem on older Linux.

QOpenGLWidget: retrieving window handle for 3rdparty library

I'm creating an application, which interacts with OpenGL via QOpenGL* classes. The graphics is shown through a QOpenGLWidget, which is placed in a UI-form.
Now, there is a library for CAD purposes (Open CASCADE), an OpenGL interface of which requires a handle to the render window. The question is: can I somehow say the library to render everything to the mentioned widget?
In other words, is there a way to interpret the widget as a native, probably, platform-specific (HWND here) window, so that the library renders its own stuff exactly there?
Thanks
QOpenGLWidget is not the same thing as QGLWidget.
The classical approach for embedding OCCT 3D viewer, which you can find in Qt IESample coming with OCCT, creates QWidget with unique window handle flag, takes this window handle and ask OCCT to take care about OpenGL context creation for this window. This is most straightforward, robust and portable way with one limitation - Qt will not be able drawing semitransparent widgets on top of this QWidget. This is not a limitation of OCCT, but rather limitation of Qt Widgets design.
QOpenGLWidget was intended to solve this limitation by allowing to mix custom OpenGL rendering and normal widgets. The integration of external OpenGL graphics engine, however, became more complicated and fragile. It is not very helpful stealing winId() from QOpenGLWidget, as rendering content is expected to be drawn not into window itself, but rather into OpenGL framebufer object (FBO), created by QOpenGLWidget - see QOpenGLWidget::defaultFramebufferObject() property.
External renderer is expected to render into this FBO for proper composition of Qt widgets. Luckily, OCCT is flexible enough to allow such integration. Unluckily, such integration requires some knowledge of OpenGL, as well as its usage by Qt and OCCT.
For that, you need to ask OCCT wrapping OpenGL context already created by Qt (for that V3d_View::SetWindow() provides an optional argument of type Aspect_RenderingContext, which corresponds to HGLRC on Windows and can be fetched using wglGetCurrentContext() within rendering thread) as well as FBO created by QOpenGLWidget (for that, OCCT provides OpenGl_FrameBuffer::InitWrapper() and OpenGl_Context::SetDefaultFrameBuffer() methods, as well as OpenGl_Caps::buffersNoSwap flag to leave window buffer swapping management to Qt).
OCCT doesn't come yet with a sample using QOpenGLWidget, but you can find also qt/AndroidQt sample implementing similar thing for embedding OCCT 3D Viewer into QtQuick application.
After some investigation, I found that method QOpenGLWidget::winId() returns the correct handle. It's been found out only now, because the rendered scene disappeared immediately, leaving a black picture instead. However, when the viewport is resized, the scene returns back (and disappears again, though). Looks like Open CASCADE has problems with Qt 5 OpenGL implementation, since QGLWidget didn't have such problems, as far as I know.

QOpenGLWidget with QApplication?

We have a QWidget based application that was previously using a QWindow for OpenGL rendering. To fit that window in our application we had to use
QWidget QWidget::createWindowContainer(QWindow);
Previously we only used external to Qt OpenGL libraries for rendering.
We have a desire to switch from using QWindow to some kind of QWidget for compatibility with touch gestures, and generally better overall compatibility with the rest of our application. The latest recommended OpenGL compatible QWidget seems to be QOpenGLWidget, so we are trying to use that.
glContext is an OpenGLContext that we manage ourselves.
The problem now is that QOpenGLWidget is not a QSurface, so I cannot call
glContext->makeCurrent(this);
to make the context current on my custom QOpenGLWidget like we could before with our custom QWindow and our own OpenGLContext.
If I try to use QOpenGLWidget::makeCurrent(); then this uses the wrong context and tries to do stuff with some magical QT handled context or something I don't understand.
The result is that after creating our OpenGLContext when we try to call
glFunctions = glContext->versionFunctions<QOpenGLFunctions_3_3_Core>();
if(!glFunctions->initializeOpenGLFunctions())
printf("Could not initialize OpenGL functions.");
It always fails to initialize the OpenGL functions.
I have been reading over all the other resources I can find on the subject and came across this older Stack Overflow question that was similar:
QOpenGLWidget with shared OpenGL context?
The answer to that question did not solve my issue because we are using QApplication, not QGuiApplication as this is a QWidget based application.
QGuiApplicationPrivate::init() is never called and the QOpenGLContext::globalShareContext() returns a null pointer since it is not initialized.
Unfortunately I cannot wait for QOpenGLWidget::initializeGL() to be called to initialize the QT managed OpenGLContext since we already have lots of OpenGL resources over various classes that attempt to get initialized before that.
Has anyone else come across this same problem?
Any suggestions?
I am doing a little guess work here.
Probably your OpenGL is defaulting to ANGLE.
And your previous application OpenGL calls are platform specific OpenGL API.
try setting below attribute to your QApplication object.
appObject->setAttribute(Qt::AA_UseDesktopOpenGL, true);
then try calling
QOpenGLWidget::makeCurrent();
If things are still not working, configure your QT libraries for desktop OpenGL.
configure -opengl desktop
the below link gives you some information on Qt approach to OpenGL.
http://doc.qt.io/qt-5/windows-requirements.html
Put in comments, if this is not helping you, will delete the answer.

Integrate GUI with OpenGL in C++

I need to create a GUI with a file menu and menu in which the user can input parameters. The parameters are then used for drawing rectangles in a canvas which is part of the application window. Is there a way to scale the OpenGL subwindow to just one part of the screen and the parameter input to the other? The application needs to be written in C++.
Is it possible to create a GUI with QT and draw the rectangles in the same window using OpenGL? If not, what is the common way to integrate a GUI with OpenGL? (or any other graphics library which I can use to draw rectangles from points as easy as possible)
EDIT: I am not sure If OpenGL is necessary or there is a way to paint the rectangles on the canvas like you can in Java with paintComponent().
I have never used QT before so I am not aware of its capabilites.
you can use opengl window singly or use this in the common mainwindow. previous example (in first answer) show how to use opengl window in qt singly and without communication with other components of Qt (like menu, toolbar and ...). but you can add a opengl window to a mainwindow (like other widget) and use it alongside other widgets . this example can help you.
Yes, using OpenGL together with Qt is absolutely possible. There is even an example for that and Qt provides classes for a more object oriented way of using OpenGL. Have a look here (Section "OpenGL and OpenGL ES Integration") for more details.

OpenGL in Qt Quick cross platform application

I'm trying to develop a cross platform (or at least desktop + embedded hardware) application. I would like to use Qt Quick to create a touch friendly GUI. I have been implemented a classical application with a QGLWidget displaying data. It is important that only a part of the window is in OpenGL. Because of this there are problems with EGLFS and LinuxFB. Only X11 (or maybe Wayland) can display the application properly (others generates a couple of errors about missing setParent function and the whole screen is black). Now I'm trying to achieve the same thing in QML. I want to use this OpenGL renderer as part of my QML application and some Qt Quick widgets around it. I found a couple of people asking about the same thing and the answer is always to subclass QDeclarativeItem and call the painter's beginNativePainting() (the others says to export it through QDeclarativeItem, but I cannot figure out how to do this). The problem is that on desktop, Qt 5.11 the native painter is not OpenGL. And in QT5 there is no way to force OpenGL graphics system. So when I try to get the OpenGL context (QGLContext::currentContext()) I always get NULL. Another problem: If I export my widget with qmlRegisterType("Test", 1, 0, "Test"); it becomes only visible when I use QDeclarativeView, but then it doesn't sees Qt Quick. If I use QQuickView it says module "Test" is not installed. How can I implement this properly?
QDeclarativeItem is from Qt Quick 1 and Qt4. With Qt 5 and Qt Quick 2 you should use QQuickItem.
There is at least 1 example of this provided with qt docs, which you can find in Qt Creator in the Welcome tab in the Examples section.