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() {
painter = new QPainter(this);
painter->beginNativePainting();
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);
// here are the functions which use native openGL code
// ...
// disabling openGL settings
glDisable(GL_SCISSOR_TEST);
glDisable(GL_POINT_SPRITE);
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
glDisable(GL_BLEND);
painter->endNativePainting();
drawTicksValues(); // function that uses QPainter
painter->end();
}
drawTicksValues:
void GLWidget::drawTicksValues() {
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));
}
main:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSurfaceFormat format;
format.setSamples(4);
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
QSurfaceFormat::setDefaultFormat(format);
SymmGaitModels w;
w.show();
return a.exec();
}
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. But if I comment the QPainter part, the plots and axes are drawed normally. Any suggestions how I can add the text with QPainter to my plot instead of clearing it?
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);
// methods 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