QOpenGLFramebufferObject not working when it is larger than viewport?
-
I'm using QOpenGLFramebufferObject as a QPaint device, then drawing a texture from the fbo in the QGLWidget. A QOpenGLFramebufferObject and QPainter are created and destroyed each time make_text() is called. The example below creates a 600x600 fbo with a 300x300 viewport. The first call to make_text() is fine, all calls after the first mess up the projection. If I limit the fbo to the viewport size there is no issue. The corruption seams to happen at the first use of the QPainter eraseRect(). I have no idea why this is breaking.
main.h
@
#include <QGLWidget>
#include <QGLFunctions>
#include <QGLFramebufferObject>
#include <QFont>
#include <QGLShader>class glview : public QGLWidget, protected QGLFunctions
{
Q_OBJECTpublic:
explicit glview(QWidget *parent = 0);
~glview();
QSize sizeHint() const;protected:
void initializeGL();
void resizeGL(int w, int h);
void paintGL();private:
void make_text(void);
QGLFramebufferObject *fbo;
QFont font;
quint32 vbo_id[1], texture_id;
QGLShaderProgram *txtovlp;
QTimer *delay;private slots:
void refresh(void);
};
@main.cpp
@
#include <QApplication>
#include <QPainter>
#include <QTimer>
#include "main.h"struct txtr_vrtx {
GLfloat x;
GLfloat y;
GLfloat z;
GLfloat tx;
GLfloat ty;
}attribute((packed)) txtr_geo[] = {
// x, y, z, tx,ty
{0, 0, 0, 0, 0},
{0, 6, 0, 0, 1},
{6, 6, 0, 1, 1},
{6, 0, 0, 1, 0},
};int main(int argc, char *argv[])
{
QApplication app(argc, argv);
glview widget;
widget.show();
return app.exec();
}glview::glview(QWidget *parent) : QGLWidget(parent)
{
fbo = NULL;
font.setFamily("Helvetica");
delay = new QTimer;
delay->start(2000);
connect(delay, SIGNAL(timeout()), this, SLOT(refresh()));
}glview::~glview()
{
delete fbo;
}void glview::refresh(void)
{
delay->stop();
qDebug() << "refresh fired";
make_text();
updateGL();
}void glview::make_text(void)
{
glBindBuffer(GL_ARRAY_BUFFER, 0); // must unbind for QPainterglEnable(GL_TEXTURE_2D);
if (fbo)
delete fbo;
fbo = new QGLFramebufferObject(600, 600, GL_TEXTURE_2D);
fbo->bind();
texture_id = fbo->texture();QPainter painter(fbo);
font.setPointSize(20);
painter.setFont(font);
painter.eraseRect(0,0,600,600);
painter.setPen(Qt::blue);
painter.drawText(250, 310, "FBO");
painter.setPen(Qt::red);
painter.drawText(100, 310, "FBO");
painter.setPen(Qt::green);
painter.drawText(250, 510, "FBO");
painter.end();fbo->release();
}QSize glview::sizeHint() const
{
return QSize(300, 300);
}void glview::initializeGL()
{
initializeGLFunctions();
qglClearColor(Qt::white);QGLShader *txtovlp_vshader = new QGLShader(QGLShader::Vertex, this);
const char *txtovlp_vsrc =
"attribute highp vec4 vertex;\n"
"attribute mediump vec2 texCoord;\n"
"varying mediump vec2 texc;\n"
"uniform mediump mat4 matrix;\n"
"void main(void)\n"
"{\n"
" gl_Position = matrix * vertex;\n"
" texc = texCoord;\n"
"}\n";
txtovlp_vshader->compileSourceCode(txtovlp_vsrc);QGLShader *txtovlp_fshader = new QGLShader(QGLShader::Fragment, this);
const char *txtovlp_fsrc =
"uniform sampler2D texture;\n"
"varying mediump vec2 texc;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(texture, texc.st);\n"
"}\n";
txtovlp_fshader->compileSourceCode(txtovlp_fsrc);txtovlp = new QGLShaderProgram(this);
txtovlp->addShader(txtovlp_vshader);
txtovlp->addShader(txtovlp_fshader);
txtovlp->link();glGenBuffers(1, vbo_id);
glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(txtr_geo), txtr_geo, GL_STATIC_DRAW);make_text();
glEnable(GL_DEPTH_TEST);
}void glview::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}void glview::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);QMatrix4x4 matrix;
matrix.ortho(1.5, 4.5, 1.5, 4.5, -1, 1);
//matrix.translate(1,1,0);txtovlp->bind();
txtovlp->setUniformValue("matrix", matrix);
//txtovlp->setUniformValue("texture", 0);glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]);
glBindTexture(GL_TEXTURE_2D, texture_id);int txtr_vertexLocation = txtovlp->attributeLocation("vertex");
txtovlp->enableAttributeArray(txtr_vertexLocation);
glVertexAttribPointer(txtr_vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(struct txtr_vrtx), 0);int texCoordLocation = txtovlp->attributeLocation("texCoord");
txtovlp->enableAttributeArray(texCoordLocation);
glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(struct txtr_vrtx), ((char*)NULL + 12));glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);glFlush();
}@
-
Is the correct context current when calling make_text from refresh? Try doing a makeCurrent in refresh() before calling make_text.
-
I tried calling makeCurrent() before make_text(), no change. Also tried putting a makeCurrent() in the beginning of the paintGL(). Also tried both places at the same time. It feels like the matrix is getting messed up but qDebug() << matrix in paintGL() shows it is the same the first and last paint event. Maybe there is a bug in my shader programs?
-
QPainter trashes the GL context and I've learned that also includes the viewport. By adding glViewport(0, 0, width(), height()); at the end of make_text() (after QPainter is finished) restores the viewport for the next paint event.