I was just wondering if QOpenGLWidget that is on Qt (I am using version 5.4) can be used without subclassing.
In the Qt Creator, form editor, there is a Display widget that can be inserted into the form named "OpenGL Widget". The widget appears black when inserted and is QOpenGLWidget object. Compilation does not throw errors, such as the fact that the initializedGL() virtual function must be implemented.
The Qt help available and examples only show how to use this object by subclassing it. This kind of defeats the purpose of having an insertable object on the toolbar so I thought perhaps there could be a way.
I noticed that the widget has functions such as makeCurrent(), which I think could be useful.
Thanks
This kind of defeats the purpose of having an insertable object on the toolbar so I thought perhaps there could be a way.
You have to subclass, but you also want the .ui file to use the widget of the correct derived class, not of the base class.
There are two ways to go about it:
Insert the base class widget. Then promote it to the derived class. You can also do it manually by editing the .ui file.
Make a custom widget Designer plugin for your class. Note that this plugin (and the widget!) have to be compiled using the same version/configuration of Qt used to compile Qt Creator itself, so in most cases you have to compile Qt Creator itself first.
If you're serious about development in Qt, you'll probably have your own Designer and Creator plugins, and you'll build Creator yourself, as well as Qt.
You can do something like this by subclassing a shell widget
void OpenGLDisplayWidget::initializeGL()
{
m_renderer->initialise(context());
}
void OpenGLDisplayWidget::resizeGL(int w, int h)
{
m_renderer->resize(w, h);
}
void OpenGLDisplayWidget::paintGL()
{
m_renderer->draw();
}
So your rendering code isn't tied to the display widget.
I just made a few experiments and I found that the QOpenGLWidget can be used very easily, without subclassing.
Insert the "Open GL Widget" (QOpenGLWidget object)
Insert a button and go to "clicked()" slot.
Insert the following code
void MainWindow::on_pushButton_clicked()
{
ui->openGLWidget->makeCurrent();
//Paint a colorful triangle
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_TRIANGLES);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(-0.5, -0.5, 0);
glColor3f(0.0, 1.0, 0.0);
glVertex3f( 0.5, -0.5, 0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f( 0.0, 0.5, 0);
glEnd();
}
Run and click the button and you should see this
screenshot
So no need to subclass, however it may be useful to include an initialization function that sets the projection matrix and aspect ratio.
Also these GL drawing functions must be called within the mainwindow which may not be desirable for the modular fanatics.
Related
I am developing an OpenGL application using Qt. Until yesterday I was subclassing QOpenGLWidget to create my custom widget but after adding It to the main application which is a QMainWindow with a few buttons and three QGraphicsView it ran really slow. I have tried using QGLWidget and the application runs the same as without the OpenGL widget.
The problem I have is that the widget that I've made subclassing QGLWidget does not resize properly (or at least the OpenGL rendering area doesn't).
I will give you an example using hellogl2 example from Qt 5.5.
Using QOpenGLWidget I get:
https://s32.postimg.org/u136s54ld/QOpen_GLWidget.png
Using QGLWidget I get:
https://s32.postimg.org/ahylis5tt/QGLWidget.png
I just changed the parent class from QOpenGLWidget to QGLWidget the rest of the code is the same. The same thing happens in my aplication.
I have tried to find a solution but I could not. May someone tell me why is this happening and how to solve it?
Thank you!
Firstly, its a good idea to stick with the up to date approach and stay away from depricated code as suggested by #ddriver.
Having said that I have written a lot of code using the QGLWidget and there is no problem with it. It does everything I need so I stick with it for now.
Here is the main issue with your approach. You took the hellogl example from qt 5.5 and simply replaced the parent from QOpenGLWidget to QGLWidget. Unfortunately they don't handle resize events similarly.
QOpenglGLWidget does change the viewport based on the width and height given by the resize event as mentioned (not so clearly with a double negative) in their documentation. Link : http://doc.qt.io/qt-5/qopenglwidget.html#resizeGL
check function resizeEvent() which in turn invokes resizeGL().
Now the QGL widget does not do this for you. All it does is makes the opengl context current which means you have to handle it old school style calling glViewport() inside the resizeGL() function. I have copied a code snippet from the hellogl example from qt4.8
void GLWidget::resizeGL(int width, int height)
{
int side = qMin(width, height);
glViewport((width - side) / 2, (height - side) / 2, side, side);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
#ifdef QT_OPENGL_ES_1
glOrthof(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
#else
glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
#endif
glMatrixMode(GL_MODELVIEW);
}
Here is a link for qt4.8 version of the hellogl : http://doc.qt.io/qt-4.8/qt-opengl-hellogl-example.html
Notice how the glViewport() is called to resize the framebuffer inside the resizeGL() function. This is done automatically by the newer QOpenGLWidget even before reaching this function. If you choose to stick with QGLWidget, you need to handle this yourself.
There may be other subtle differences as well which you will need to figure out.
Simply put, I cannot for the life of me figure out how to actually make use of things like QOpenGLWidget or QOpenGLWindow or anything. I want to have the rendering I do be a child widget of a window in a MDI, but nothing works.
Here's the code I have currently set up for the widget (at least, just the parts involving OpenGL):
Viewport::Viewport(QWidget * parent) : QOpenGLWidget(parent) { }
void Viewport::initializeGL() {
initializeOpenGLFunctions();
}
void Viewport::paintGL() {
// first, clear the screen
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
And here's how I use the widget:
vp = new Viewport;
vp->resize(QSize(320,240));
hbox->addWidget(vp);
And the result is that I see nothing. I just see a tiny sliver of empty space next to the other widget in the window, but that's it. No black screen like I try to clear with, not even a 320x240-sized empty space.
Like I said, I've been unable to do this in any of the ways I could find, and it's really frustrating. Am I missing something obvious? There's very little documentation as-is, so it's hard to tell if I am, or if there's some weird corner case I'm running into. (For example, none of the documentation I find uses QOpenGLWidget as part of a larger widget; is that because it can't be, or because all the examples I can find are just lazy about using the widget as its own top-level window?)
After some more fiddling around, it turns out my issue was apparently caused by the other object in the window (a QListView) by default taking up as much space as possible, making the OpenGL widget disappear since it doesn't have a minimum size.
In other words, the problem is fixed by either changing the QListView to have a QSizePolicy::Preferred sizing policy (since resizing the window will now let you see the OpenGL widget), or by giving the OpenGL widget a minimum or fixed size.
(As an aside, I really wish this could've been more obvious than just stumbling upon it by chance.)
I am doing an excercise where I draw three boxes across three windows using GLUT. They draw individually, but in the same project, the three windows display correctly, but immediately close the program with code 1.
glutInitWindowPosition(x,y);
windowOne = glutCreateWindow("windowOne");
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
glOrtho(-400, 400, -400, 400, -500, 500);
glutInitWindowPosition(x,y);
windowTwo = glutCreateWindow("windowTwo");
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
glFrustum(-60, 60, -60, 60, 60, 200);
gluLookAt(0, 0, 120, 0, 0, 0, 0, 1, 0);
With each window in a separate file loaded in by itself, they each display exactly as they are meant to. I have a feeling I should be setting the window at some point between each init, but I don't know why. I do not have a draw function in at the moment, as I wanted to confirm this happens without the drawing code.
I should also note that I have to create separate windows, exactly as I have done, so other window drawing functions are useless.
I found the answer scouring through examples, so I'll post it just in case anyone else is having similar problems.
the draw function needs to be added after each window, in the style of
// window one
glutInitWindowPosition(50, 50);
WindowOne = glutCreateWindow("orthogonal projection");
glutDisplayFunc(drawWindowOne);
// window two
glutInitWindowPosition(650, 50);
WindowThree = glutCreateWindow("3D viewing system with glFrustum()");
glutDisplayFunc(drawWindowTwo);
I was using a draw function that shuffles through each window and generates its specific draw after using glutSetWindow. each draw takes place after each window is initialized, and multiple glutDisplayFunc() can be called after eachother.
I originally thought I was using glutDisplayFunc to set a pointer, so that when the display routine went through for the frame, it would only generate the last display function called, as opposed to all of them.
Never do OpenGL drawing operations in the same function in which you also create GLUT windows. It doesn't work. You need to register a display callback function for each window and do all drawing there. Calling glutMainLoop is mandatory if you want to see something sensible using GLUT.
I've looked at a ton of articles and SO questions about OpenGL not drawing, common mistakes, etc. This one is stumping me.
I've tried several different settings for glOrtho, different vertex positions, colors, etc., all to no avail.
I can confirm the OpenGL state is valid because the clear color is purple in the code (meaning the window is purple). gDEBugger is also confirming frames are being updated (so is Fraps).
Here is the code. Lines marked as "didn't help" were not there originally, and were things that I tried and failed.
QTWindow::QTWindow( )
{
// Enable mouse tracking
this->setMouseTracking(true);
}
void QTWindow::initializeGL()
{
// DEBUG
debug("Init'ing GL");
this->makeCurrent(); ///< Didn't help
this->resizeGL(0, 0); ///< Didn't help
glDisable(GL_CULL_FACE); ///< Didn't help
glClearColor(1, 0, 1, 0);
}
void QTWindow::paintGL()
{
// DEBUG
debug("Painting GL");
this->makeCurrent(); ///< Didn't help
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0,1,1);
glBegin(GL_TRIANGLES);
glVertex2f(500,100);
glVertex2f(100,500);
glVertex2f(0,0);
glEnd();
this->swapBuffers(); ///< Didn't help
}
void QTWindow::resizeGL(int width, int height)
{
// DEBUG
debug("Resizing GL");
this->makeCurrent(); ///< Didn't help
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1000, 0, 1000, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
The triangle is not being displayed at all, even with culling turned off. However, all three debug logs are called exactly how they should be.
What am I missing?
Try calling glViewport() function at the very beginning of the QTWindow::resizeGL() function:
glViewport(0, 0, width, height);
And don't ever call resizeGL() with width and height set to 0 ;) Besides that, it is not necessary for you to call resizeGL() directly as it is being called by Qt whenever the window is being resized.
You can remove all calls to the swapBuffers() function - it is being called internally by Qt.
The makeCurrent() function should be called before all other GL calls, so it is good that you have called it in initializeGL(), but you don't have to call it in the paintGL() function (unless paintGL() is being called from another thread, but I bet it isn't in your code).
The issue ended up being versions. The version string returned with glGetString(GL_VERSION) indicated 4.2 compatibility context was being used.
Since the triangle calls in the paintGL method were removed in 3.1 (if I recall correctly), it was obvious why they weren't drawing anything. Further, no errors were being thrown because it was in compat. mode.
Because I couldn't get the version down below 3.0 on the QGLWidget (due to the fact that QT requires 2.1, as I was informed on another message board), I set the version to 3.0 and tried using some 3.0 drawing calls and it ended up working.
I am trying to create a tool that will draw a shape in openGL and then modify the values of the properties of that shape in a windows form. So if my shape is a rectangle, I will create a form that will allow the user to control the size, color etc of the rectangle. I have written the openGL code in managed c++ and the form in c#, and as some of these shapes got more complicated I decided to make display lists for them (for both performance and predictability purposes).
I define the display list in the constructor for the shape and I call the display lists in the render method.
My issue is that my display lists won't run at all. The parts that I render outside of a display list will be rendered, but the parts inside the display list will not be rendered.
Here's some sample code of my process:
//c# side
GLRectangle rect
public CSharpRectangle() {
rect = new GLRectangle();
}
//managed c++ side
public GLRectangle() {
width = 50;
height = 50;
//initialize more values
rectDL = glGenLists(1);
glNewList(rectDL, GL_COMPILE);
renderRect();
glEndList();
}
public render() {
//Draw border
glBegin(GL_LINE_LOOP);
glVertex2f(0, 0);
glVertex2f(width, 0);
glVertex2f(width, height);
glVertex2f(0, height);
glEnd();
//Draw interior
glCallList(rectDL);
}
private renderRect() {
glRectf(0,0,width,height);
}
In this example, the border of the rectangle would be rendered, but the rectangle itself won't be rendered... if I replace the display list with simply a method call, the rectangle is rendered fine. Does anyone know why this might be happening?
I want to give my 2 cents.
The code in your question seems correct to me, so probably there something else in your application that make your display list not runnable.
The only thing I can think is there's no current context when compiling the display list (indeed when executing GlRectangle constructor). So, is that routine executed in the same thread which have called glMakeCurrent? Is that routine called after glMakeCurrent?
Further, check with glGetError after each OpenGL routine in order to validate the operation. In the case it returns an error, you can know what's wrong in your code..
The reason you may not get what you want is simply because it isn't there anymore. In time I was reading openGL Red book, I've noticed that display lists were deprecated in openGL 3.1 and higher (means simply removed) and googling for that confirmed it. I don't remember reason anymore, but I believe because it was messing with VAOs and VBOs. So if you are using higher than opengl 3.1 you won't get display lists anymore.