I am trying to use an OpenGL Shader on a QGrapicsView.
My graphic card is a NVidia GeForce GT 425M. I made my experiments on a Ubuntu 12.04 with the NVidia driver 295.40.
I Create a QMainWindow containing two QGraphicsView, each graphics view are displaying the same scene. On One of the Graphics View, I setup an OpenGL View port.
The OpenGL View Port is a QGLWidget I had overloaded with the loading of the vertex and fragment shader programs.
Look at my QMainWindow constructor :
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_scene = new QGraphicsScene(this);
ui->gvShaded->setScene(m_scene);
ui->gvUnshaded->setScene(m_scene);
m_glWidget = new QGLScene();
ui->gvShaded->setViewport(m_glWidget);
m_glWidget->updateGL();
if(m_glWidget->context()->isValid())
{
qDebug()<<"GL Context is valid";
}else
{
qWarning()<<"GL Context is not valid";
}
qDebug() << "Opengl Version : " << m_glWidget->context()->format().openGLVersionFlags();
QBrush brush(QLinearGradient(0,0,20,0));
brush.setColor(Qt::blue);
QGraphicsRectItem* rect = m_scene->addRect(0,0,20,20,QPen(Qt::black), brush);
ui->gvShaded->ensureVisible(rect);
ui->gvUnshaded->ensureVisible(rect);
}
As you can see I instantiate the object QGLScene which is :
class QGLScene : public QGLWidget
{
public:
QGLScene(QWidget* _parent=0);
protected :
virtual void initializeGL();
};
My GLWidget Construction is :
QGLScene::QGLScene(QWidget *_parent)
:QGLWidget(QGLFormat(QGL::DepthBuffer), _parent)
{
}
And definition of initializeGL is :
void QGLScene::initializeGL()
{
qDebug() << __PRETTY_FUNCTION__;
QGLShader fragmentShader(QGLShader::Fragment, context(), this);
QGLShader vertexShader(QGLShader::Vertex, context(), this);
QGLShaderProgram pgm(context(), this);
if(vertexShader.compileSourceFile("./vertexShader.glsl"))
{
if(fragmentShader.compileSourceFile("./fragmentShader.glsl"))
{
pgm.addShader(&fragmentShader);
pgm.addShader(&vertexShader);
pgm.link();
pgm.bind();
qDebug() << "Shader bien chargé : "<< pgm.log();
}else
{
qDebug() << "Problem when loading fragment shader :";
qDebug() << fragmentShader.log();
qDebug() << QString(fragmentShader.sourceCode());
}
}else
{
qDebug() << "Problem when loading vertex shader :";
qDebug() << vertexShader.log();
qDebug() << QString(vertexShader.sourceCode());
}
}
My shaders are very useless shaders :
Vertex :
#version 150
uniform mat4 viewMatrix, projMatrix;
in vec4 position;
in vec3 color;
out vec3 Color;
void main()
{
Color = color;
gl_Position = projMatrix * viewMatrix * position ;
}
Fragment :
#version 150
in vec3 Color;
out vec4 outputF;
void main()
{
outputF = vec4(1.0, 0, 0, 1.);
}
So I attempt to have my Shaded Graphics view as a big red square because I think I enforced the pixels to be red (in my fragment shader).
I have no shader compilation error, but my two scene are the same.
Of course, the program pass into the initializeGL function (I can read the PRETTY_FUNCTION).
Does some one have an explanation ?
Related
I'm experimenting with QThreadPool and realized that my program exited with SIGSEGV after QThreadPool reaches expiry timeout.
I started the program creating pointers to QLabel and QLineEdits as placeholders, which are kept in QLists.
Then, the method carregar2() is called, when the menu is clicked, to start the QThreadPool.
I implemented 4 QRunnables. They're all the same: they invoke external program (QProcess) with different parameters. Their result are written to QLineEdits.
If I set setExpiryTimeout(-1), the program does not crash.
This is the MainWindow class, it is the called from the main.cpp :
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QtWidgets>
#include "ClickableLabel.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QMainWindow::showMaximized();
ui->setupUi(this);
QStringList args = QApplication::arguments();
QString path;
if(args.size()<=1)
path = QFileDialog::getExistingDirectory(parent, "", "/studio/FOTOS", QFileDialog::ShowDirsOnly);
else
path = static_cast<QString>(args.at(1));
QDir *dir = new QDir(path);
setWindowTitle("QExif - " + path);
QScrollArea *scroll = new QScrollArea();
QGridLayout *grid = new QGridLayout(scroll);
QFrame *frame = new QFrame();
int row=0;
int col=0;
QStringList filtro;
filtro << "*.jpg";
const QFileInfoList fil = dir->entryInfoList(filtro,QDir::Files );
qDebug() << "FOTOS: " << fil.size();
foreach (QFileInfo fi, fil ) {
QString f = fi.absoluteFilePath();
QLabel *l = new ClickableLabel(); //A custom QLabel that implements a clicked() signal and "emit clicked()" on mousePressEvent
l->setStyleSheet("border: 5px solid white");
l->setMaximumSize(w,h);
l->setMinimumSize(w,h);
l->setProperty("foto", f);
l->setToolTip(f);
connect(l, SIGNAL(clicked()), this, SLOT(abrirVisualizadorExterno()));
grid->addWidget(l,row,col,1,1,Qt::AlignTop);
//tag buttons
QHBoxLayout *box = new QHBoxLayout(parent);
QFrame *btnFrame = new QFrame();
btnFrame->setLayout(box);
btnFrame->setMaximumWidth(w);
QLineEdit *tagArtista = new QLineEdit(parent);
tagArtista->setToolTip("Etiquetas");
grid->addWidget(tagArtista,row+1,col,1,1,Qt::AlignTop);
QLineEdit *tagDescricao = new QLineEdit(parent);
tagDescricao->setToolTip("Descrição da imagem");
grid->addWidget(tagDescricao,row+2,col,1,1,Qt::AlignTop);
QLineEdit *tagDataHora = new QLineEdit(parent);
tagDataHora->setToolTip("Data e Hora");
grid->addWidget(tagDataHora,row+3,col,1,1,Qt::AlignTop);
tagArtista->setProperty("foto", f);
tagDescricao->setProperty("foto", f);
tagDataHora->setProperty("foto", f);
fList->append(f);
labelList->append(l);
tagList->append(tagArtista);
descricaoList->append(tagDescricao);
dataHoraList->append(tagDataHora);
col++;
if(col >3) { col=0; row+=4; }
} //foreach
frame->setLayout(grid);
scroll->setWidget(frame);
setCentralWidget(scroll);
/*
* MENU
* */
QMenu *menuExif = ui->menuBar->addMenu("Exif");
menuExif->addAction("Carregar");
connect(menuExif,SIGNAL(triggered(QAction*)),this,SLOT(menuHandler(QAction*)));
}
void MainWindow::menuHandler(QAction *action){
if(action->text() == "Carregar"){
carregar2();
}
}
void MainWindow::carregar2(){
QThreadPool *pool = QThreadPool::globalInstance();
pool->setExpiryTimeout(-1);
for(int i=0; i<fList->count(); i++){
ImagemRunnable *imageRunnable = new ImagemRunnable(labelList->at(i), fList->at(i), w, h);
QThreadPool::globalInstance()->start(imageRunnable);
TagRunnable *tagRunnable = new TagRunnable(tagList->at(i), fList->at(i));
pool->start(tagRunnable);
TagDescricaoRunnable *tagDescricaoRunnable = new TagDescricaoRunnable(descricaoList->at(i), fList->at(i));;
pool->start(tagDescricaoRunnable);
TagDataHoraRunnable *tagDataHoraRunnable = new TagDataHoraRunnable(dataHoraList->at(i), fList->at(i));
pool->start(tagDataHoraRunnable);
}
}
void MainWindow::abrirVisualizadorExterno(){
ClickableLabel *l = (ClickableLabel *) sender();
qDebug() << "Abrir" << l->property("foto");
if (l->property("foto").isValid()){
QStringList cmd;
cmd << QString("eog %1").arg(l->property("foto").toString());
system(cmd.at(0).toUtf8().data());
}
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event){
qDebug() << watched->property("foto").toString();
return false;
}
MainWindow::~MainWindow()
{
delete ui;
}
And this is one of the implemented QRunnables:
header:
#ifndef TAGRUNNABLE_H
#define TAGRUNNABLE_H
#include <QRunnable>
#include <QLineEdit>
class TagRunnable : public QRunnable, QObject
{
public:
TagRunnable(QLineEdit * f, QString file);
void run() override;
private:
QLineEdit *field;
QString file;
};
#endif // TAGRUNNABLE_H
cpp:
#include "tagrunnable.h"
#include <QProcess>
#include <QDebug>
TagRunnable::TagRunnable(QLineEdit * f, QString file)
{
field = f;
this->file = file;
}
void TagRunnable::run(){
QProcess *proc = new QProcess();
//pessoas na foto
proc->start("/usr/bin/exif", QStringList()
<< "-t" << "0x013b"
<< "-m"
<< file
);
if(!proc->waitForFinished()){
qDebug() << "Timeout ao ler exif tag (pessoas)." << file;
}
field->setText(proc->readAllStandardOutput());
field->setProperty("tagOriginal", field->text());
}
My questions:
Suppose I use 30 seconds as expiry timeout. After that time, is my reference to the QProcess removed from memory and causing the QLineEdit text to be lost as well?
Is it ok to set expiry timeout to -1 in any situation or, perhaps, I'm not using it properly because of other architectural error of my program ?
I have already tried many solution that are provided on stackoverflow to make it transparent.
I want to make QRubberBand transparent and i am also facing problem regarding that green color which is due to mplayer.
#include "physician.h"
#include "ui_physician.h"
Physician::Physician(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Physician)
{
ui->setupUi(this);
ui->sendROIButton->setStyleSheet(
"background-color: #d9d9d9;"
"border-radius: 10px;"
"color: Black; "
"font-size: 15px;"
);
}
Physician::~Physician()
{
delete ui;
}
void Physician::mouseMoveEvent(QMouseEvent *e)
{
rubberBand->hide();
bottomRight = e->pos();
QRect rect = QRect(topLeft, bottomRight).normalized();
rubberBand->setGeometry(rect);//Area Bounding
QToolTip::showText(e->globalPos(), QString("%1,%2")
.arg(rubberBand->size().width())
.arg(rubberBand->size().height()), this);
}
void Physician::mousePressEvent(QMouseEvent *e)
{
wWidth=ui->videoShowLabel->width();
wHeight = ui->videoShowLabel->height();
rubberBand->setGeometry(QRect(0, 0, 0, 0).normalized());
rubberBand->hide();
topLeft = e->pos();
}
void Physician::mouseReleaseEvent(QMouseEvent *e){
rubberBand->show();
}
void Physician::on_manualROIRadioButton_clicked()
{
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
}
void Physician::on_autoROIRadioButton_clicked()
{
QString winNuber= QString::number((int)(ui->videoShowLabel->winId()));
QStringList argsList ;
argsList << "-slave" << "-quiet" << "-wid" << winNuber << "zoom" << "-
vo" << "gl" << "C:/../../../Physician21/PhotoshopQML.mkv";
mplayer_proc = new QProcess;
mplayer_proc-
>start("C:/../../../PhysicianTest/mplayer/mplayer.exe",argsList);
}
Firstly, regarding "QRubberBand should work only on that QLabel". You need to make the QLabel the parent of the QRubberBand to achieve that.
Secondly, regarding transparency I assume you mean that the output from mplayer should be visible through the rectangle painted by the QRubberBand? I'm not sure you will be able to do that. Doing so would required the rubber band painting logic to act as a compositor but in order to do that it needs to know both the source and destination(mplayer) images. Since mplayer draws directly on the underlying native window Qt has know knowledge of the current destination image and so can not merge the source image with it. I think your best bet would be to find/generate a style that causes QRubberBand to draw the rectangle outline only -- not sure if that's possible. You could subclass it and do your own painting with something like...
class rubber_band: public QRubberBand {
using super = QRubberBand;
public:
template<typename... Types>
explicit rubber_band (const Types &... args)
: super(args...)
{}
protected:
virtual void paintEvent (QPaintEvent *event) override
{
QPainter painter(this);
painter.setPen(Qt::red);
painter.setBrush(Qt::NoBrush);
painter.drawRect(rect().adjusted(0, 0, -1, -1));
}
};
The above could still leave visual artifacts on the widget though.
i'm a new member and i have a question.
I want to develope a simple project with QT5 and opengl core profile for an end term project.
I first tried with a simple example but nothing happen. The screen show me only the red background but not the shader that i have write.
the code is the following:
main.cpp
#include <QApplication>
#include <QGLFormat>
#include "glwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//specify oepngl version and other stuff
QGLFormat glFormat;
glFormat.setVersion(4, 3);
glFormat.setProfile(QGLFormat::CoreProfile);
glFormat.setSampleBuffers(true);
GLWidget w(glFormat);
w.show();
return a.exec();
}
glwidget.h
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QGLWidget>
#include <QGLBuffer>
#include <QGLShaderProgram>
#include <QOpenGLVertexArrayObject>
class GLWidget : public QGLWidget
{
Q_OBJECT
public:
GLWidget(const QGLFormat& format, QWidget* parent = 0);
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
//virtual void keyPressEvent(QKeyEvent* e);
private:
bool prepareShaderProgram(const QString& vertexShaderPath, const QString& fragmentShaderPath);
QGLShaderProgram m_shader;
QGLBuffer m_vertexBuffer;
GLuint vertex_array_object;
};
#endif // GLWIDGET_H
glwidget.cpp
#include "glwidget.h"
GLWidget::GLWidget(const QGLFormat& format, QWidget* parent)
:QGLWidget(format, parent),
m_vertexBuffer(QGLBuffer::VertexBuffer)
{
}
void GLWidget::initializeGL()
{
QGLFormat glFormat = QGLWidget::format();
if(!glFormat.sampleBuffers())
qWarning() << "Can't enable sample buffers";
//set background color
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
//load the shaders
if(!prepareShaderProgram("/home/sera/workspace/qtWorkspace/provaShader/simple.vert",
"/home/sera/workspace/qtWorkspace/provaShader/simple.frag"))
return;
//create and bind the vertex buffer to the context
m_vertexBuffer.create();
if(!m_vertexBuffer.bind())
{
qWarning() << "could not bind vertex buffer to the opengl context";
return;
}
//bind program to the context
if(!m_shader.bind())
{
qWarning() << "could not bind shader program to the context";
return;
}
}
bool GLWidget::prepareShaderProgram(const QString &vertexShaderPath, const QString &fragmentShaderPath)
{
//load and compile shaders
bool result = m_shader.addShaderFromSourceFile(QGLShader::Vertex, vertexShaderPath);
if(!result)
qWarning() << m_shader.log();
result = m_shader.addShaderFromSourceFile(QGLShader::Fragment, fragmentShaderPath);
if(!result)
qWarning() << m_shader.log();
//link shaders into program
result = m_shader.link();
if(!result)
qWarning() << "could not link shader program" << m_shader.log();
return result;
}
void GLWidget::resizeGL(int w, int h)
{
//set the viewport
glViewport(0, 0, w, qMax(h, 1));
}
void GLWidget::paintGL()
{
//clear buffer with current color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPointSize(40.0);
glDrawArrays(GL_POINTS, 0, 1);
}
/*
void GLWidget::keyPressEvent( QKeyEvent* e )
{
switch (e->key())
{
case Qt::Key_Escape:
QCoreApplication::instance()->quit();
break;
default:
QGLWidget::keyPressEvent( e );
}
}
*/
simple.vert
#version 430 core
void main(void)
{
gl_Position = vec4(1.0, 0.0, 0.0, 1.0);
}
simple.frag
#version 430 core
out vec4 color;
void main(void)
{
color = vec4(1.0, 1.0, 1.0, 1.0);
}
And the result is this in the figure, but i'm aspected a point in the middle
result
What is wrong?
I have a very large QGraphicsScene that can contain a very large number of graphics. I'm using a QGLWidget as the viewport so that I can leverage OpenGL to try to improve how some things get rendered. I have created a custom QGraphicsItem that I can use to draw several quads with the same texture in one render call rather than having hundreds or thousands of different QGraphicsItems in the scene that really all get drawn the same way, just in different locations. In my custom QGraphicsItem's paint() method, I called beginNativePainting() and endNativePainting() and do all of my OpenGL calls between them.
I want to use shader programs so that I can manipulate the vertices somewhat within the vertex shader, so I copied Qt's OpenGL Textures Example which uses a shader program to draw 6 textured quads. That example works just fine as is, but when I try to use the same approach within a QGraphicsItem's paint() method, all of my quads just get drawn white. My best guess is that my fragment shader just isn't getting used. I've even tried hardcoding the color within the fragment shader and nothing changes.
Here's the source code of my custom QGraphicsItem class.
class BatchGraphics : public QGraphicsPixmapItem
{
enum {PROGRAM_VERTEX_ATTRIBUTE = 0,
PROGRAM_TEXCOORD_ATTRIBUTE = 1};
public:
BatchGraphics()
: _program(0),
_texture(0),
_dirty(false)
{
}
// Returns the custom bounding rect for this item which encompasses all quads
QRectF boundingRect() const
{
return _boundingRect;
}
// Add a quad to the batch. Only the center point is necessary
void addQuad(int id, float x, float y)
{
_quads.insert(id, QPointF(x, y));
updateBoundingRect();
_dirty = true;
}
// Remove a quad from the batch.
void removeQuad(int id)
{
if (_quads.contains(id))
{
_quads.remove(id);
updateBoundingRect();
_dirty = true;
}
}
// Return the number of quads in the batch
int count() {return _quads.count();}
// Paint the batch using a custom implementation.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
// If the item is dirty (has been modified, update the geometry)
if (_dirty) {
updateGeometry();
}
if (_program)
{
painter->beginNativePainting();
// Enable GL states
//glEnable(GL_TEXTURE_2D);
// Set the MVP matrix
_program->setUniformValue("matrix", painter->transform());
// Enable and set the vertex and texture attributes
_program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
_program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
_program->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, _vertices.constData(), 3, 5*sizeof(GLfloat));
_program->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, _vertices.constData()+2, 2, 5*sizeof(GLfloat));
// Bind the texture
_texture->bind();
// Draw the arrays
glDrawArrays(GL_TRIANGLES, 0, _quads.count()*6); // 6 vertices per quad
painter->endNativePainting();
}
}
private:
// Initialize the shader and texture
void initialize()
{
// Create the OpenGL texture
_texture = new QOpenGLTexture(pixmap().toImage());
// Vertex Shader
QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex);
const char *vsrc =
"attribute highp vec4 vertex;\n"
"attribute mediump vec4 texCoord;\n"
"varying mediump vec4 texc;\n"
"uniform mediump mat4 matrix;\n"
"void main(void)\n"
"{\n"
" gl_Position = matrix * vertex;\n"
" texc = texCoord;\n"
"}\n";
vshader->compileSourceCode(vsrc);
// Fragment Shader
QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment);
const char *fsrc =
"uniform sampler2D texture;\n"
"varying mediump vec4 texc;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(texture, texc.st);\n"
"}\n";
fshader->compileSourceCode(fsrc);
// Program
_program = new QOpenGLShaderProgram;
_program->addShader(vshader);
_program->addShader(fshader);
_program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
_program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
_program->link();
_program->bind();
_program->setUniformValue("texture", 0);
}
// Update the vertex array. Calls initialize the first time.
void updateGeometry()
{
if (_program == 0) {
initialize();
}
_vertices.clear();
// Half pixmap size
QPointF s = QPointF(pixmap().width()/2, pixmap().height()/2);
// Build vertex data for each quad
foreach (const QPointF& point, _quads)
{
// Top Left
_vertices << point.x()-s.x(); // x
_vertices << point.y()-s.y(); // y
_vertices << 1; // z
_vertices << 0; // tu
_vertices << 1; // tv
// Top Right
_vertices << point.x()+s.x(); // x
_vertices << point.y()-s.y(); // y
_vertices << 1; // z
_vertices << 1; // tu
_vertices << 1; // tv
// Bottom Left
_vertices << point.x()-s.x(); // x
_vertices << point.y()+s.y(); // y
_vertices << 1; // z
_vertices << 0; // tu
_vertices << 0; // tv
// Top Right
_vertices << point.x()+s.x(); // x
_vertices << point.y()-s.y(); // y
_vertices << 1; // z
_vertices << 1; // tu
_vertices << 1; // tv
// Bottom Left
_vertices << point.x()-s.x(); // x
_vertices << point.y()+s.y(); // y
_vertices << 1; // z
_vertices << 0; // tu
_vertices << 0; // tv
// Bottom Right
_vertices << point.x()+s.x(); // x
_vertices << point.y()+s.y(); // y
_vertices << 1; // z
_vertices << 1; // tu
_vertices << 0; // tv
}
_dirty = false;
}
private:
// Updates the bounding rect based on the quads in the batch.
void updateBoundingRect()
{
prepareGeometryChange();
double left = 9999;
double right = -9999;
double top = 9999;
double bottom = -9999;
double w = pixmap().width()/2;
double h = pixmap().width()/2;
foreach (const QPointF& p, _quads)
{
left = qMin(left, p.x()-w);
right = qMax(right, p.x()+w);
top = qMin(top, p.y()-h);
bottom = qMax(bottom, p.y()+h);
}
_boundingRect = QRectF(left, top, (right-left), (bottom-top));
}
private:
QOpenGLShaderProgram* _program;
QOpenGLTexture* _texture;
QRectF _boundingRect;
QMap<int, QPointF> _quads;
QVector<GLfloat> _vertices;
bool _dirty;
};
I understand the basics of the render pipeline and how to use shaders, but as far as dependencies between things and other OpenGL methods that must be called when using certain features I'm pretty clueless on. I can get the quads to be rendered with the texture using a fixed function pipeline approach, but that's old school and like I said, I want to be able to manipulate the vertices in the vertex shader once I get this working.
I'm not doing anything special when creating the QGLWidget, and its QGLFormat ends up being 2.0. I'v also tried calling glEnable(GL_TEXTURE_2D), but that just makes the quads get rendered black instead of white. I've also tried binding the program each time paint() is called, thinking perhaps Qt is binding a different shader somewhere else behind the scenes, but that just causes NOTHING to appear.
Can anyone provide any help please? I can't figure out why this approach works fine in Qt's Textures example but not when I try to do it inside of a QGraphicsItem.
I finally figured it out after looking at Qt's source code and what happens when beginNativePainting(). First, I DID have to bind my shader each time paint() was called, and second I had to get the correct MVP matrix.
I was trying to just pass the QPainter's transform to my shader to act as the modelview projection matrix, but the transform was only the modelview matrix. I needed to get the projection matrix as well, which Qt sets when beginNativePainting() is called.
I got the project and modelview matrices from OpenGL directly and combined them to pass to my shader after binding my texture and presto! It worked!
Here are the relevant changes I had to make:
painter->beginNativePainting();
// Enable GL states
//glEnable(GL_TEXTURE_2D);
// === Begin New Code ======
// Bind my program
_program->bind();
QMatrix4x4 proj;
glGetFloatv(GL_PROJECTION_MATRIX, proj.data());
QMatrix4x4 model;
glGetFloatv(GL_MODELVIEW_MATRIX, model.data());
// Set the MVP matrix
_program->setUniformValue("matrix", proj * model);
// === End New Code ======
// Enable and set the vertex and texture attributes
_program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
_program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
_program->setAttributeArray(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, _vertices.constData(), 3, 5*sizeof(GLfloat));
_program->setAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, _vertices.constData()+2, 2, 5*sizeof(GLfloat));
My OpenGL|ES 2.0 glClear command freezes until the window state changes (eg. the window gets hidden or shown).
The target platform is ARM7 with a Mali 400 GPU.
All code is mostly copied from the Qt OpenGL ES Cube example.
What am I forgetting?
Leon
Source:
#include "streamplayer.h"
#include <QtOpenGL>
#include <QGLFunctions>
StreamPlayer::StreamPlayer(QWidget *parent) :
QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{
program = new QGLShaderProgram();
}
StreamPlayer::~StreamPlayer()
{
}
void StreamPlayer::initializeGL()
{
qDebug() << "Initializing GL";
initShaders();
glClearColor(0.5f, 0.5f, 0.7f, 1.0f);
return;
}
void StreamPlayer::paintGL()
{
qDebug() << "Paint GL";
qDebug() << "Clearing buffers";
glClear(GL_COLOR_BUFFER_BIT);
qDebug() << "Never comes here until a window state change";
}
void StreamPlayer::resizeGL(int width, int height)
{
qDebug() << "Resizing GL to " << width << "x" << height;
glViewport(0, 0, width, height);
qDebug() << "Done resizing";
}
void StreamPlayer::initShaders()
{
qDebug() << "Initializing shaders";
setlocale(LC_NUMERIC, "C");
if(!program->addShaderFromSourceFile(QGLShader::Vertex, ":/shaders/vshader.glsl")) {
qDebug() << "Failed to create vertex shader";
}
if(!program->addShaderFromSourceFile(QGLShader::Fragment, ":/shaders/fshader.glsl")) {
qDebug() << "Failed to create fragment shader";
}
if(!program->link()) {
qDebug() << "Failed to link";
}
_gl_vertex = program->attributeLocation("vertex");
_gl_texCoord = program->attributeLocation("texCoord");
_gl_matrix = program->attributeLocation("matrix");
_gl_texture = program->attributeLocation("tex");
if(!program->bind()) {
qDebug() << "Failed to bind";
}
setlocale(LC_ALL, "");
qDebug() << "Shaders ready";
}
Have you kept the timer asking for frame updates ? It is this timer that is asking for openGL redraw by calling updateGL() on the glwidget, that ask for a (delayed) paintGL(). Otherwise paintGL will only be called when Qt estimates necessary (for example window shown).
QTimer *timer = new QTimer(this);
timer->setInterval(10);
QObject::connect(timer, SIGNAL(timeout()), glwidget, SLOT(updateGL()));
//And at the end of MainWindow initialization
timer->start();
See this SO thread for related question.