Render loop function in QT to render opengl in Windows - c++

Since QGLWidget cannot be used for OpenGL / ES, i am left with QWidget in Qt for widgets to render opengl. Reference
if i have the following renderView function to render in the current window, i am looking for "that" function that will be called repeatedly by qt for QWidget to refresh screen so that i can call renderView in that function by overloading it.
any idea how to do this or common work around?
Original problem: I do not want to call renderView in a timer of 1 MilliSec or even 16.66 Milli sec as per the screen refresh rate.
class MyWindow
{
void renderView()
{
if(DeviceContext && RenderingContext)
{
wglMakeCurrent(m_hdc, m_hrc); //Set current context
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// glViewPort.... and render using shaders
SwapBuffers(m_hdc); // Double buffering thats why
}
}
};
class MyWidget : public QWidget, public MyWindow
{
// What is the function called repeatedly to refresh the screen
// so that i would ask that function to call renderView
};
Thanks in advance!

Since QGLWidget cannot be used for OpenGL / ES
Right, we need to clear up some confusion before going further down the road...
It can be. This widget was invented to extend the usual QWidget interface with OpenGL desktop and embedded support. Please refer to the following example to see yourself it is possible to use this widget for OpenGL ES functionality:
OpenGL Hello GL ES Example
Now, we can come to the point to answer your question. What you should probably reimplement is the following protected method.
void QGLWidget::paintGL() [virtual protected]
This virtual function is called whenever the widget needs to be painted. Reimplement it in a subclass.
While we are at discussing it, please also check the protected initialization method:
void QGLWidget::initializeGL() [virtual protected]
This virtual function is called once before the first call to paintGL() or resizeGL(), and then once whenever the widget has been assigned a new QGLContext. Reimplement it in a subclass.
This function should set up any required OpenGL context rendering flags, defining display lists, etc.
In fact, you could even deal with overlays with this interface as per the following protected methods:
void QGLWidget::paintOverlayGL() [virtual protected]
This virtual function is used in the same manner as paintGL() except that it operates on the widget's overlay context instead of the widget's main context. This means that paintOverlayGL() is called whenever the widget's overlay needs to be painted. Reimplement it in a subclass.
and
void QGLWidget::initializeOverlayGL() [virtual protected]
This virtual function is used in the same manner as initializeGL() except that it operates on the widget's overlay context instead of the widget's main context. This means that initializeOverlayGL() is called once before the first call to paintOverlayGL() or resizeOverlayGL(). Reimplement it in a subclass.
This function should set up any required OpenGL context rendering flags, defining display lists, etc. for the overlay context.

Related

Where to use the makeCurrent() in QGLWidget?

The qt's documentation said:
Your widget's OpenGL rendering context is made current when paintGL(),
resizeGL(), or initializeGL() is called. If you need to call the
standard OpenGL API functions from other places (e.g. in your widget's
constructor or in your own paint functions), you must call
makeCurrent() first.
for the following case:
paintGL()
{
drawSomething();
}
...
drawSomething()
{
glClearColor()...
//many other gl calls...
}
do I have to makeCurrent inside the drawSomething() function.
And if I only make QPainter call in stead of standard OpenGL API functions. Do I have to use makeCurrent?
do I have to makeCurrent inside the drawSomething() function.
If that function is called only from paintGL, no, as Qt will call paintGL with the context already current.
As the docs say, you'll need it whenever you need the GL context current in some other function.
// called from other code, context may not be current
void MyGLWidget::setBackgroundColor(const QColor &color) {
makeCurrent();
glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
}
As the documentation states:
[The] rendering context is made current when paintGL() ... is called
So there is no need to call makeCurrent in any method called from paintGL. When using QPainter, it is also not necessary (Btw.: QPainter does not necessarily use OpenGL).

How to draw to "parent TLW backing store"?

This might be very complicated question not many people know answer but I still will ask.
I do have QWindow derived class, with overloaded event(), which uses Backing store and fill in whole window with a colour, let say black.
Now I have my QT QML app, when I create my window and set parent as main view of my app, I getting window sized to 1x1px ! This is driving me crazy..
I dug though the QT source code and found this:
void QQnxRasterWindow::adjustBufferSize()
{
// When having a raster window we don't need any buffers, since
// Qt will draw to the parent TLW backing store.
const QSize windowSize = window()->parent() ? QSize(1,1) : window()->size();
if (windowSize != bufferSize())
setBufferSize(windowSize);
}
void QQnxRasterWindow::setParent(const QPlatformWindow *wnd)
{
QQnxWindow::setParent(wnd);
adjustBufferSize();
}
Which is kinda bummer because I have no idea how I suppose to use TLW and draw into my window now.
Any ideas?
First of all what is TLW ?
Second how do I draw into parent TLW in a way it will end up in my window buffer.
Thank you
QT 5.3.1
Edit:
not renderNow() - my mistake,
overloaded function event, which uses event UpdateRequested to draw my background.
Edit2:
Also this is only problem when I set parent, when no parent set I can do whatewer I want with my QWindow and it has own buffer. Kinda weird.

Moving from QGLWidget to QWindow

I have some code using Qt 4. I want to migrate it to Qt 5 and switch to QOpenGL stuff. I can't understand where the code from void paintGL() and void initializeGL() needs to go in a QWindow. Can anyone help me with an example?
I have created a simple example of using QWindow with OpenGL.
To simplify OpenGL development I have created an abstract class GLWindow, which contains the virtual functions initializeGL(), paintGL() and resizeGL(int w, int h). I believe the source code shows the relationship between the old style and the new style.
The example is available here:
https://github.com/mortennobel/QtOpenGLChapter/tree/master/OpenGL3xAlt
Qt has at least one example (Overpainting) of putting widgets over an OpenGL scene. By looking at that, it appears the easiest way would be to inherit from QGLWidget instead of QWidget and override the appropriate virtual functions for initialize and paint.
The standard example for using QWindow with OpenGL is hellowindow in qtbase/examples/opengl.
There is no direct replacement for initializeGL and paintGL. Instead you do something like this:
Have a QWindow with surface type OpenGLSurface.
Create a QOpenGLContext with a matching format.
When the window receives an expose event, start rendering (makeCurrent, your GL calls and finally swapBuffers).

Trouble initializing shaders before resize on wxGLCanvas

wxGLCanvas seems to hate OpenGL shaders, by not providing an initialization callback function like the one in Qt; Making me unable to create the shaders even after creating the context myself in the constructor, like so:
m_context = new wxGLContext(this);
Also tried:
SetCurrent(*m_current);
Still no luck and GLEW keeps throwing "Missing GL Version" which indicates that the context has not been created (from Google).
I have tried:
Using WX_EVT() for show and activate events, still no luck.
Initializing shaders in the resize event, still no luck.
Is there any way to make wxGLCanvas call my initialization function before anything else?
There is no specific method to initialize OpenGL that gets called before everything else, but after the window was shown, in wxWidgets. You can roll your own with a member variable that indicates whether OpenGL has been initialized, and doing your initialization in the Paint event handler if the variable is false.
In my experience it is safest to issue all OpenGL commands only in the Paint event handler, so in your Size event handler, you should save the new viewport size and update the projection matrix in your Paint handler (or just query the viewport size using wxGLCanvas' GetClientRect() method).
In the examples in http://wiki.wxwidgets.org/WxGLCanvas it is suggested that you do the initialization on the paint event (EVT_PAINT(BasicGLPane::render)), as said by Kristian Duske in the comments above.
Instead you can initialize OpenGL in any other place, you just have to show the wxwidget window or frame first (e.g. frame->Show() ).
I do this:
initialize wxGLCanvas (in my case with a wxFrame frame as parent)
canvas = new Canvas( (wxFrame*) frame, args);
show window
frame->Show()
Now call your custom OpenGL initialization method in the canvas class (only once):
set context
wxGLCanvas::SetCurrent(*m_context);
initialize glew:
glewExperimental = GL_TRUE;
GLenum err = glewInit();
After this I compile the shaders etc.
In the paint event then only do the drawing: glDrawArrays() and SwapBuffers()

pyqt : Why QGLWidget influenced by maya event?

openGL with maya
I made a openGL View with QGLWidget. It has a problem when work with Maya. As you see in video, when I click and move on a modelPanel within Maya, the QGLWidget get broken. And I found that the marquee rectangle is shown on my QGLWidget, not Maya. Why this problem happend?
To datenwolf
I tried to edit my code as you suggested. But... it doesn't call makeCurrent() and doneCurrent() at all. I expected that when I clicked on my maya modelPanel it could send me the message, but it didn't. What did I miss? Sorry for that.
def makeCurrent(self):
import OpenGL.WGL as wgl
print "MAKE CURRENT!!!"
self.prevHDC = wgl.wglGetCurrentDC()
self.prevHRC = wgl.wglGetCurretnContext()
super(GLWidget, self).makeCurrent()
def doneCurrent(self):
import OpenGL.WGL as wgl
print "DONE CURRENT!!!"
super(GLWidget, self).doneCurrent()
wgl.wglMakeCurrent(self.prevHDC, self.prevHRC)
I wrote just like above. But it never even show the "MESSAGE".
Most likely Qt and Maya's event loop are battling for processing event. Qt's paintGL does the right thing and makes the OpenGL context current whenever it is called. Maya however does not and so drawing commands of Maya end up in your OpenGL context.
Playing along with Maya is going to be tricky, because it requires storing which OpenGL/DC context was active before switching and restoring that once finished with one own's operations. You'll probably have to subclass QGLWidget and QGLContext to do this.
Update due to comment
Derive from QGLWidget, add two members HDC m_prevHDC and HRC m_prevHRC, override makeCurrent and doneCurrent
void QMyGLWidget::makeCurrent()
{
this->m_prevHDC = wglGetCurrentDC();
this->m_prevHRC = wglGetCurrentContext();
QGLWidget::makeCurrent();
}
void QMyGLWidget::doneCurrent()
{
QGLWidget::doneCurrent();
wglMakeCurrent(this->m_prevHDC, this->m_prevHRC);
}
Then derive your actual GLWidget from this intermediary class.