Vertex Buffer Object -> Segmentation Fault - qt

I've been developing a 3D creator but I'm still stuck in the first stages since I haven't been able to draw with VBO.
This is a piece of my glwidget.cpp code, where all the objects are drawn
void GLWidget::initializeGL()
{
#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_NORMALS_ATTRIBUTE 1
//glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
vShader= new QGLShader (QGLShader::Vertex, this);
vShader->compileSourceFile("../src/shaders/editorVshader.glsl");
fShader= new QGLShader (QGLShader::Fragment, this);
fShader->compileSourceFile("../src/shaders/editorFshader.glsl");
editor= new QGLShaderProgram (this);
editor->addShader(vShader);
editor->addShader(fShader);
editor->bindAttributeLocation("vertices", PROGRAM_VERTEX_ATTRIBUTE);
editor->bindAttributeLocation("normals", PROGRAM_NORMALS_ATTRIBUTE);
editor->link();
editor->bind();
}
void GLWidget::paintGL()
{
glClearColor(0.4765625, 0.54296875, 0.6171875, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/*
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -10.0f);
*/
editor->setUniformValue("projectMatrix", controller->getProjectionMatrix());
editor->setUniformValue("viewMatrix", controller->getViewMatrix());
/** Ahora para las operaciones especificas de cada objeto **/
for (int i=0; i<Objects.size(); i++)
{
Objects[i].modelmatrix.scale(1.0, 1.0, 1.0);
Objects[i].modelmatrix.rotate(1.0, 0.0, 0.0, 1.0);
editor->setUniformValue("modelMatrix", Objects.at(i).modelmatrix);
glEnableClientState(GL_VERTEX_ARRAY);
Objects[i].vertexbuffer->bind();
glVertexPointer(3, GL_FLOAT, 0, Objects.at(i).indexed_vertices.data());
editor->enableAttributeArray("vertices");
editor->setAttributeBuffer("vertices", GL_FLOAT, 0, Objects[i].indexed_vertices.size() * sizeof(vertex)); // (PROGRAM_VERTEX_ATTRIBUTE, Objects[i].vertices.data());
/*
Objects[i].normalbuffer.bind();
//glVertexPointer(3, GL_FLOAT, 3, Objects.at(i).indexed_normals.data());
glEnableClientState(GL_NORMAL_ARRAY);
editor->enableAttributeArray(PROGRAM_NORMALS_ATTRIBUTE);
editor->setAttributeBuffer (PROGRAM_NORMALS_ATTRIBUTE, GL_FLOAT, 0, Objects[i].indexed_normals.size() * sizeof(vertex));*/
//glDrawArrays(GL_QUADS, 0, Objects[i].vertices.size());
Objects[i].elementbuffer->bind();
glDrawElements(GL_QUADS, Objects[i].indices.size(), GL_UNSIGNED_SHORT, (void*)0);
}
}
It explodes when it tries to execute the glDrawElements instruction. I've been tracking down the problem but I can't find what's wrong. I'm even doubting about the right way to use QGLBuffer in Qt. Can anyone help me?

I solved it. The problem was the “tuplasize” that I was using with the setAttributeBuffer instruction.
It was
Objects[i].indexed_vertices.size() * sizeof(vertex)
Now I changed it to 3 and started passing normals as vertices too, the result code is:
void GLWidget::paintGL()
{
glClearColor(0.4765625, 0.54296875, 0.6171875, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/*
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -10.0f);
*/
editor->setUniformValue("projectMatrix", controller->getProjectionMatrix());
editor->setUniformValue("viewMatrix", controller->getViewMatrix());
/** Ahora para las operaciones especificas de cada objeto **/
for (int i=0; i<Objects.size(); i++)
{
Objects[i].modelmatrix.scale(1.0, 1.0, 1.0);
Objects[i].modelmatrix.rotate(1.0, 0.0, 0.0, 1.0);
editor->setUniformValue("modelMatrix", Objects.at(i).modelmatrix);
glEnableClientState(GL_VERTEX_ARRAY);
editor->enableAttributeArray("vertices");
Objects[i].vertexbuffer->bind();
//glVertexPointer(3, GL_FLOAT, 0, Objects.at(i).indexed_vertices.data());
editor->setAttributeBuffer("vertices", GL_FLOAT, 0, 3); // (PROGRAM_VERTEX_ATTRIBUTE, Objects[i].vertices.data());
//glDisableClientState(GL_VERTEX_ARRAY);
//glEnableClientState(GL_NORMAL_ARRAY);
editor->enableAttributeArray("normals");
Objects[i].normalbuffer->bind();
//glVertexPointer(3, GL_FLOAT, 3, Objects.at(i).indexed_normals.data());
editor->setAttributeBuffer ("normals", GL_FLOAT, 0, 3);
glDisableClientState(GL_VERTEX_ARRAY);
//glDrawArrays(GL_QUADS, 0, Objects[i].vertices.size());
Objects[i].elementbuffer->bind();
glDrawElements(GL_QUADS, Objects[i].indices.size(), GL_UNSIGNED_SHORT, (void*)0);
}
}
This can be marked as Solved.

Related

How to get framebuffer image and save it to texture in Qt?

I am trying to get front-face and back-face of cube and save them to texture for calculating difference of them.
This is what I want to get.
Vertices of cube is passed to pipeline for getting front-face of cube and save it to texture
Vertices of cube is passed to pipeline for getting back-face of cube and save it to texture
Using texture of both front-face and back-face of cube, calculate the difference of them
I have paintGL() like this,
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glShadeModel(GL_SMOOTH);
QMatrix4x4 mMatrix;
QMatrix4x4 vMatrix;
QMatrix4x4 cameraTransformation;
cameraTransformation.rotate(alpha, 0, 1, 0);
cameraTransformation.rotate(beta, 1, 0, 0);
QVector3D cameraPosition = cameraTransformation * QVector3D(0, 0, distance);
QVector3D cameraUpDirection = cameraTransformation * QVector3D(0, 1, 0);
QVector3D eye = QVector3D(0, 0, 0);
vMatrix.lookAt(cameraPosition, eye, cameraUpDirection);
shaderProgram.bind();
shaderProgram.setUniformValue("mvpMatrix", pMatrix*vMatrix*mMatrix);
//vertex array enable
shaderProgram.setAttributeArray("vertex", vertices.constData());
shaderProgram.enableAttributeArray("vertex");
//color array enable
shaderProgram.setAttributeArray("color", colors.constData());
shaderProgram.enableAttributeArray("color");
/ /glDisable(GL_DEPTH_TEST);
glDrawArrays(GL_QUADS, 0, vertices.size());
//vertex&color array disable
shaderProgram.disableAttributeArray("vertex");
shaderProgram.disableAttributeArray("color");
shaderProgram.release();
}

Displaying heatmap with OpenGL using shaders

I am trying to display a heatmap with OpenGL using shaders.
Here is my vertex shader:
# version 130
void main (void)
{
vec4 vertex = gl_Vertex;
gl_Position = gl_ModelViewProjectionMatrix * vertex;
gl_TexCoord[0] = gl_MultiTexCoord0;
}
And here is my fragment shader:
# version 130
uniform sampler2D heatmap;
uniform sampler1D colormap;
void main (void)
{
float temp = texture2D(heatmap, gl_TexCoord[1].st).r; // [0 - 50] degrees celcius
float r = temp/50.0f;
r = clamp(r, 0.0f, 1.0f);
gl_FragColor = texture1D(colormap, r);
}
Here is the code I call once to send the textures to GPU memory:
glGenTextures(2, textures);
GLenum errc = glGetError();
if (errc != GL_NO_ERROR)
{
const char* errmsg = (const char*)gluErrorString(errc);
std::cerr << errmsg;
}
...
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_1D);
glBindTexture(GL_TEXTURE_2D, textures[0]); // makes the texture with id texture active
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, 100, 100, 0, GL_RED, GL_FLOAT, &data[0]);
glBindTexture(GL_TEXTURE_1D, textures[1]); // makes the texture with id texture active
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage1D(GL_TEXTURE_1D, 0, 3, 256, 0, GL_RGB, GL_FLOAT, &rgb[0]);
Here data is a std::vector of 100x100 floats and rgb is a std::vector of 3x256 floats.
Here is my drawing code:
glBegin(GL_QUADS); // Draw A Quad
glTexCoord2f(0.0, 1.0);
glVertex3f(0.0, 1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0)
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, 0.0, 0.0);
glTexCoord2f(0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
Do I need to call glTexCoord1f() for each vertex? These values are not used.
I am using Qt and QGLWidget in particular.
I am not seing anything. What could be wrong?
Some observations:
If instead set gl_FragColor = texture2D(heatmap, gl_TexCoord[1].st); inside the fragment shader I see the red component correctly.
In the code above glGenTextures fails, but I still can see the red component as described above.
If I move this call to just before glBindTexture it does not fail, but then I do not see anything!?

Can QGLFramebufferObject be larger than the viewport?

Can QGLFramebufferObject be larger than the viewport? For example, if I have a viewport of 300x300 pixels, can the fbo be 600x300? ...so one half of the fbo is shown...then applying a translation, the other half is shown. The first time make_text(); is called scaling is correct, second time the x dimension gets stretched.
main.h
#include <QGLWidget>
#include <QGLFunctions>
#include <QGLFramebufferObject>
#include <QFont>
#include <QGLShader>
class glview : public QGLWidget, protected QGLFunctions
{
Q_OBJECT
public:
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, 3, 0, 0, 1},
{6, 3, 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 QPainter
glEnable(GL_TEXTURE_2D);
if (fbo)
delete fbo;
makeCurrent();
fbo = new QGLFramebufferObject(600, 300, GL_TEXTURE_2D);
fbo->bind();
texture_id = fbo->texture();
QPainter painter(fbo);
font.setPointSize(20);
painter.setFont(font);
painter.eraseRect(0,0,600,300);
painter.setPen(Qt::blue);
painter.drawText(100, 140, "FBO");
painter.setPen(Qt::red);
painter.drawText(400, 140, "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(0, 3, 0, 3, -1, 1);
//matrix.translate(-3,0,0);
txtovlp->bind();
txtovlp->setUniformValue("matrix", matrix);
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();
}
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.

OpenGL Does Not Render Triangle

I am following this tutorial with a few modifications and have got this code:
#define GLSL(src) "#version 330 core\n" #src
void MainWindow::initializeGL() {
glClearColor(0, 0, 0, 1);
// Generate buffers
GLfloat verticies[] = {
+0.0f, +1.0f, +0.0f,
-1.0f, -1.0f, +0.0f,
+1.0f, -1.0f, +0.0f,
};
GLuint vertexBufferID;
glGenBuffers(1, &vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(verticies), verticies, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
// Generate shaders
const char *vertexShaderSrc = GLSL(
layout(location = 0) in vec3 pos;
void main() {
gl_Position.xyz = pos;
gl_Position.w = 1.0;
}
);
GLuint vertexShaderID = createGLShader(GL_VERTEX_SHADER, vertexShaderSrc);
const GLchar *fragmentShaderSrc = GLSL(
out vec4 color;
void main() {
color = vec4(0.0, 1.0, 0.0, 1.0);
}
);
GLuint fragmentShaderID = createGLShader(GL_FRAGMENT_SHADER, fragmentShaderSrc);
GLuint programID = glCreateProgram();
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragmentShaderID);
glLinkProgram(programID);
glUseProgram(programID);
}
void MainWindow::paintGL() {
//glViewport(0, 0, width(), height());
glClear(GL_COLOR_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES, 0, 3);
//glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
}
GLuint MainWindow::createGLShader(GLenum type, const GLchar* src) {
GLuint shaderID = glCreateShader(type);
glShaderSource(shaderID, 1, &src, 0);
glCompileShader(shaderID);
GLint vertexCompileStatus;
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &vertexCompileStatus);
if (vertexCompileStatus != GL_TRUE) {
GLint infoLogLength;
glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar buffer[infoLogLength];
glGetShaderInfoLog(shaderID, infoLogLength, 0, buffer);
qDebug(buffer);
}
return shaderID;
}
This is all contained in a QGLWidget. However when I run this code I just get a black screen. What is going wrong? I don't get an error message so the shaders are compiling.
I set up the QGLWidget:
#include "mainwindow.h"
#include <QApplication>
#include <QGLFormat>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QGLFormat glFormat;
glFormat.setVersion(3, 3);
glFormat.setProfile(QGLFormat::CoreProfile);
MainWindow w(glFormat);
w.show();
return a.exec();
}
Staying with "pure" OpenGL code, you need (at least) a Vertex Array Object. That object needs to be bound when you configure the vertex arrays, and everytime you draw from the aforementioned arrays.
So, before the calls to gl*VertexAttribArray, create and bind the VAO. Add a
GLuint m_vao;
member to your class. Then in initializeGL:
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
// now configure the arrays:
glEnableVertexAttribArray...
glVertexAttribArray...
// now release the VAO and move on
glBindVertexArray(0);
Then in paintGL we need the VAO again:
glBindVertexArray(m_vao);
glDrawArrays(...);
glBindVertexArray(0);
And now your code with Qt 5 OpenGL enablers (didn't try to compile it, but you can get the idea). You tell me which one is more readable and less error prone.
#define GLSL(src) "#version 330 core\n" #src
void MainWindow::initializeGL() {
glClearColor(0, 0, 0, 1);
// Generate buffers
GLfloat verticies[] = {
+0.0f, +1.0f, +0.0f,
-1.0f, -1.0f, +0.0f,
+1.0f, -1.0f, +0.0f,
};
m_vertexBuffer = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
m_vertexBuffer->create();
m_vertexBuffer->setusagePatter(QOpenGLBuffer::StaticDraw);
m_vertexBuffer->bind();
m_vertexBuffer->allocate(verticies, sizeof(verticies);
m_vertexBuffer->release();
// Generate shaders
const char *vertexShaderSrc = GLSL(
layout(location = 0) in vec3 pos;
void main() {
gl_Position.xyz = pos;
gl_Position.w = 1.0;
}
);
const GLchar *fragmentShaderSrc = GLSL(
out vec4 color;
void main() {
color = vec4(0.0, 1.0, 0.0, 1.0);
}
);
m_program = new QOpenGLShaderProgram;
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSrc);
m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSrc);
m_program->link();
// error checking missing from the last three calls. if they return false, check log()
m_vao = new QOpenGLVertexArrayObject;
m_vao->bind();
m_program->bind();
m_vertexBuffer->bind();
m_program->enableAttributeArray("pos");
m_program->setAttributeBuffer("pos", GL_FLOAT, 0, 3);
m_vertexBuffer->release();
m_program->release();
m_vao->release();
}
void MainWindow::paintGL() {
glClear(GL_COLOR_BUFFER_BIT);
m_vao->bind();
m_program->bind();
glDrawArrays(GL_TRIANGLES, 0, 3);
m_program->release();
m_vao->release();
}

How to make original (0,0) coordinate to be on the top left of QGLWIdget?

I want to display an image using QGLWidget, it doesn't show in the correct way, one of the problems is the original coordinate is on the bottom left of the widget.
I would like to know how to make the original coordinate to be on the top left and flip the y axis.
here's my code:
header
#ifndef _GLImageDisplay_H_
#define _GLImageDisplay_H_
#include "stdafx.h"
class GLImageDisplay : public QGLWidget
{
Q_OBJECT
public:
GLImageDisplay(QWidget *parent = 0);
void DisplayImage(QString img);
protected:
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
private:
QImage svgImage;
GLubyte* gluImage;
};
#endif
cpp
#include "stdafx.h"
#include "GLImageDisplay.h"
GLImageDisplay::GLImageDisplay(QWidget *parent) : QGLWidget (parent)
{
}
void GLImageDisplay::DisplayImage(QString img)
{
svgImage.load(img);
resize(svgImage.size());
gluImage = new GLubyte[svgImage.height() * svgImage.width() * 3];
for (int a = 0; a < svgImage.width(); ++a)
{
for (int b = 0; b < svgImage.height(); ++b)
{
QColor color = svgImage.pixel(a, b);
gluImage[3 * (a + b * svgImage.width()) + 0] = (GLubyte) color.red();
gluImage[3 * (a + b * svgImage.width()) + 1] = (GLubyte) color.green();
gluImage[3 * (a + b * svgImage.width()) + 2] = (GLubyte) color.blue();
}
}
this->setMinimumWidth(svgImage.width());
this->setMinimumHeight(svgImage.height());
}
void GLImageDisplay::initializeGL()
{
glClearColor(0.5, 0.5, 0.5, 1.0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
void GLImageDisplay::resizeGL(int w, int h)
{
glViewport(0, 0, svgImage.width(), svgImage.height());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, svgImage.width(), 0, svgImage.height(), 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void GLImageDisplay::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2i(0, 0);
glDrawPixels(svgImage.width(), svgImage.height(), GL_RGB, GL_UNSIGNED_BYTE, gluImage);
}
OpenGL coordinates start at the bottom. To fix this, you can do a -1 scaling in the y axis in your projection matrix. The offset is related.
To fix this, alter your call to glOrtho or apply a scaling + translation just after the call.
Btw. you could also use QPainter and use beginNativePainting() wherever you really need GL. QPainter will already use GL itself and perform very well.
glDrawPixels is a very inefficient way of drawing an image onto screen. You should rather load it into a texture and draw a quad with it. (Yet again, QPainter can do that for you, too, much more easily.)
Thanks ypnos!
in the end i flip the projection matrix gluOrtho2D(0, width, height, 0);
and flip the text coord.
here's my code:
#include "stdafx.h"
#include "GLImageDisplay.h"
GLImageDisplay::GLImageDisplay(QWidget *parent) : QGLWidget (parent)
{
}
void GLImageDisplay::DisplayImage(QString img)
{
myImage.load(img);
// calculating power-of-two (pow) size
int xpow = (int) std::pow(2.0, std::ceil( std::log10((double)myImage.width())/std::log10(2.0) ) );
int ypow = (int) std::pow(2.0, std::ceil( std::log10((double)myImage.height())/std::log10(2.0) ) );
// the texture should be square too
xpow = std::max(xpow, ypow);
ypow = xpow;
// shrink if the size is too big
if(xpow > 1024)
{
xpow = 1024;
ypow = 1024;
}
// transform the image to square pow size
scaledImage = myImage.scaled(xpow, ypow, Qt::IgnoreAspectRatio);
glImage = QGLWidget::convertToGLFormat(scaledImage);
this->setMinimumWidth(myImage.width());
this->setMinimumHeight(myImage.height());
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &imageID);
glBindTexture( GL_TEXTURE_2D, imageID );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, scaledImage.width(), scaledImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, glImage.bits());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glDisable(GL_TEXTURE_2D);
}
void GLImageDisplay::initializeGL()
{
glClearColor(0.5, 0.5, 0.5, 1.0);
}
void GLImageDisplay::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, height, 0); // flip the y axis
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void GLImageDisplay::paintGL()
{
int width = myImage.width();
int height = myImage.height();
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1,0,0);
glBegin(GL_POLYGON);
glVertex2f(10,10);
glVertex2f(10,600);
glVertex2f(300,10);
glEnd();
glEnable(GL_TEXTURE_2D);
glColor3f(1,1,1);
glBindTexture( GL_TEXTURE_2D, imageID );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glImage.width(), glImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, glImage.bits());
glBegin(GL_QUADS);
// text coord is flipped
glTexCoord2d(0,1); glVertex3d(0, 0, 0);
glTexCoord2d(1,1); glVertex3d(width, 0, 0);
glTexCoord2d(1,0); glVertex3d(width, height, 0);
glTexCoord2d(0,0); glVertex3d(0, height, 0);
glEnd();
glDisable(GL_TEXTURE_2D);
}
but i'm encountering another issue when i try to display a large image where the bottom of the widget is cut and displays black area. It seems that the widget only is rendered at most the height of my LCD screen (?) I'm wondering QGLWidget can't be easily put in the QScrollArea (?). It's a different issue though.

Resources