QOpenGlWidget: usage of native opengl code and QPainter class
-
Hello everyone!
I am preparing a desktop application to draw some 2D plots. I am using C++: Qt 5 and visual studio 2013. I created a simple GUI and put myQOpenGLWidget in it. I am already drawing the plots, axes and ticks using my own openGl shaders. Everything works fine and now I want to add the description to my axes and ticks to make the graph possible to analysis. As in OpenGL itself there is no dedicated functions to render text, I came up with using QPainter object just to add the desired description to already created plot. And here are problems starting...Here is my functions of my QopenGLWidget implementation:
void GLWidget::initializeGL() { initializeOpenGLFunctions(); glEnable(GL_POINT_SPRITE); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); vertexShad = new QOpenGLShader(QOpenGLShader::Vertex); fragmentShad = new QOpenGLShader(QOpenGLShader::Fragment); bool flag = vertexShad->compileSourceFile(QString("vs.glsl")); if (flag) printf("compiled vertex Shader\n"); flag = fragmentShad->compileSourceFile(QString("fs.glsl")); if (flag) printf("compiled fragment Shader\n"); flag = program.addShader(vertexShad); if (flag) printf("linked vertex Shader\n"); flag = false; flag =program.addShader(fragmentShad); if (flag) printf("linked fragment Shader\n"); program.link(); program.bind(); }
paintGL:
void GLWidget::paintGL() { glViewport(0, 0, this->width(), this->height()); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); drawAxes(); glViewport(MARGIN, MARGIN, this->width() - MARGIN * 2, this->height() - MARGIN * 2); glScissor(MARGIN, MARGIN, this->width() - MARGIN * 2, this->height() - MARGIN * 2); glEnable(GL_SCISSOR_TEST); // functions that uses openGL native code // .... // // labels description: QPainter painter(this); char * maxText = new char[4]; sprintf(maxText, "%d", maxY); char * minText = new char[4]; sprintf(minText, "%d", minY); painter.drawText(0, MARGIN, QString(maxText)); painter.drawText(0, height() - MARGIN, QString(minText)); painter.drawText(MARGIN, height() - MARGIN + 20, QString("0")); painter.drawText(width() - MARGIN, height() - MARGIN + 20, QString(100)); update(); painter.end(); }
Unfortunately, when I run the code, with uncommented QPainter part, the axis and plots are cleared, only the numbers I paint with QPainter are shown. Any suggestions how I can add the text with QPainter to my plot instead of clearing it?
Thank you for any comments!
-
I finally managed to get things work.
First of all, I had to change and set the format (you have to change it before widget is shown), for example in main function , before my app was shown:
main:int main(int argc, char *argv[]) { QApplication a(argc, argv); SymmGaitModels w; // GLWidget is my implemantation of QOpenGLWidget GLWidget* gl = w.findChild<GLWidget*>("OpenGLWidget"); QSurfaceFormat format; //format.setSamples(4); //format.setDepthBufferSize(24); //format.setStencilBufferSize(8); format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile); QSurfaceFormat::setDefaultFormat(format); gl->setFormat(format); w.show(); return a.exec(); }
Moreover, I had to move all (even enabling and disabling things like blend, point_sprite etc, which caused my problems) of my openGL functions between
QPainter-> beginNativePainting() ... QPainter->endNativePainting();
And I had to implement paintEvent function. I just put paintGL() expression there.
Now my functions look like that:void GLWidget::initializeGL() { printf("autoFILL: %d\n",this->autoFillBackground()); initializeOpenGLFunctions(); // this function has to stay in initializeGL // commented functions below has to be removed and put after beginNativePainting //glEnable(GL_POINT_SPRITE); //glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); //glEnable(GL_BLEND); //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // shaders may be compiled and added here, but program has to be linked and built after beginNativePainting() vertexShad = new QOpenGLShader(QOpenGLShader::Vertex); fragmentShad = new QOpenGLShader(QOpenGLShader::Fragment); bool flag = vertexShad->compileSourceFile(QString("vs.glsl")); //bool flag = vertexShad->compileSourceCode(vertexShadSrc); if (flag) printf("compiled vertex Shader\n"); flag = fragmentShad->compileSourceFile(QString("fs.glsl")); //flag = fragmentShad->compileSourceCode(fragmentShadSrc); if (flag) printf("compiled fragment Shader\n"); flag = program.addShader(vertexShad); if (flag) printf("linked vertex Shader\n"); flag = false; flag =program.addShader(fragmentShad); if (flag) printf("linked fragment Shader\n"); } void GLWidget::paintEvent(QPaintEvent *e) { paintGL(); // still this, widget has to be now refreshed by widget->update() } void GLWidget::paintGL() { painter = new QPainter(this); painter->beginNativePainting(); // glEnable(GL_POINT_SPRITE); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); program.link(); program.bind(); // glViewport(0, 0, this->width(), this->height()); glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); drawAxes(); glViewport(MARGIN, MARGIN, this->width() - MARGIN * 2, this->height() - MARGIN * 2); glScissor(MARGIN, MARGIN, this->width() - MARGIN * 2, this->height() - MARGIN * 2); glEnable(GL_SCISSOR_TEST); // functions using native openGL functions here // ..... // glDisable(GL_SCISSOR_TEST); glDisable(GL_POINT_SPRITE); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); glDisable(GL_BLEND); program.disconnect(); painter->endNativePainting(); drawTicksValues(); painter->end(); }
After adding paintEvent implementation, the openGL widget has to be now refreshed using
widget->update()
.Hope it will be helpful for other people who are struggling with using both QPainter and native openGL functions, as Qt doc seems to be a little shallow on this topic.
Thanks!
Adam