Displaying heatmap with OpenGL using shaders - qt

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!?

Related

openGL - failed to display an images

Learning to display images using QOpenGLWidget. However, I've met some problems.
How can I pass the GLuint texture variable (the actual texture loaded from the image) into the shader scripts? Like how to bind GLuint texture to uniform sampler2D texture? Maybe I am just not realising I already did that.
What's the difference between attribute vec4 vertexColorIn and uniform sampler2D texture? I think the color comes from the texture.
Can I use glTexCoord2f() and glVertex2f() instead of glVertexAttribPointer() and glVertexAttribPointer()? It's because they seem better to me.
I am still not clear on the concept about how openGL displays an image, although I've done many researches. I'm not quit sure what I'm doing wrong. The image is NOT showing up.
MyGLWiget.cpp
shader scipts:
#define STR(x) #x
#define VS_LOCATION 0
#define FS_LOCATION 1
const char* vertextShader = STR(
attribute vec4 position;
attribute vec4 vertexColorIn;
varying vec4 vertexColorOut;
void main(void)
{
gl_Position = position;
vertexColorOut = vertexColorIn;
}
);
const char* fragmentShader = STR(
varying vec4 vertexColorOut;
uniform sampler2D texture;
void main(void)
{
??? = texture2D(???, textureOut).r // no clue how to use it
gl_FragColor = vertexColorOut;
}
);
loading an Image texture:
void MyGLWiget::loadTexture(const char* file_path)
{
img_data = SOIL_load_image(file_path, &width, &height, &channels, SOIL_LOAD_RGB);
glEnable(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data);
SOIL_free_image_data(img_data);
}
initialization:
void MyGLWiget::initializeGL()
{
initializeOpenGLFunctions();
program.addShaderFromSourceCode(QGLShader::Vertex, vertextShader);
program.bindAttributeLocation("position", VS_LOCATION);
program.addShaderFromSourceCode(QGLShader::Fragment, fragmentShader);
program.bindAttributeLocation("vertexColorIn", FS_LOCATION);
program.link();
program.bind();
static const GLfloat ver[] = {
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f
};
static const GLfloat tex[] = {
0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f
};
glVertexAttribPointer(VS_LOCATION, 2, GL_FLOAT, 0, 0, ver);
glEnableVertexAttribArray(VS_LOCATION);
glVertexAttribPointer(FS_LOCATION, 2, GL_FLOAT, 0, 0, tex);
glEnableVertexAttribArray(FS_LOCATION);
program.setUniformValue("texture", texture);
//texture = program.uniformLocation("texture");
}
paintGL:
I'm really confused with this part. I have no idea what should I use to make it to draw an image.
void MyGLWiget::paintGL()
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, img_data);
glUniform1i(texture, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 1);
}
How can I pass the GLuint texture variable (the actual texture loaded from the image) into the shader scripts? Like how to bind GLuint texture to uniform sampler2D texture? Maybe I am just not realising I already did that.
This binds the texture to texture unit 0:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
This is invalid because texture is not a uniform location, so remove this line:
glUniform1i(texture, 0); // <-- invalid
This is invalid too, because the uniform texture should be set to the number of the texture unit:
program.setUniformValue("texture", texture); // <-- invalid
So replace it with:
program.setUniformValue("texture", 0); // <-- sampler2D texture uses GL_TEXTURE0
Note: I'm assuming here that setUniformValue works correctly.
What's the difference between attribute vec4 vertexColorIn and uniform sampler2D texture? I think the color comes from the texture.
vertexColorIn comes from the VAO and is different for each vertex. texture is the sampler that samples from the texture that's bound to the texture unit that you set above.
In your code you don't need a vertex color, but you do need texture coordinates. So your shaders should look like:
const char* vertextShader = STR(
attribute vec4 position;
attribute vec4 texcoordIn;
varying vec4 texcoordOut;
void main(void)
{
gl_Position = position;
texcoordOut = texcoordIn;
}
);
const char* fragmentShader = STR(
varying vec4 texcoordOut;
uniform sampler2D texture;
void main(void)
{
gl_FragColor = texture2D(texture, texcoordOut);
}
);
Can I use glTexCoord2f() and glVertex2f() instead of glVertexAttribPointer() and glVertexAttribPointer()? It's because they seem better to me.
glTexCoord2f and glVertex2f are legacy functions that were removed in OpenGL 3, and are available only in the compatibility profile. You shall not use them.
This lines are in the wrong place:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
They shall go after you bound the texture:
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, img_data);
// sets the filtering for the bound texture:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
Since the question is tagged opengl-4: you don't need to set any uniforms in this case. You can specify the locations and the bindings directly in the shaders:
const char* vertextShader =
"#version 450 core\n" STR(
layout(location = 0) in vec4 position;
layout(location = 1) in vec4 texcoordIn;
layout(location = 0) out vec4 texcoordOut;
void main(void)
{
gl_Position = position;
texcoordOut = texcoordIn;
}
);
const char* fragmentShader =
"#version 450 core\n" STR(
layout(location = 0) in vec4 texcoord;
layout(binding = 0) uniform sampler2D TEX;
layout(location = 0) out vec4 OUT;
void main(void)
{
OUT = texture(TEX, texcoord);
}
);
a few edits
const char* vertextShader = STR(
attribute vec4 position;
attribute vec4 vertexColorIn;
varying vec4 vertexColorOut;
out vec2 TexCoord;//--->add
void main(void)
{
gl_Position = position;
vertexColorOut = vertexColorIn;
TexCoord = vec2(aPos.x/2.0+0.5, 0.5-aPos.y/2.0);//a hack,ideally you need to pass the UV coordinates for proper texture mapping.UVs need to be passed in as a uniform or an attribute depending on preference.
}
);
const char* fragmentShader = STR(
varying vec4 vertexColorOut;
uniform sampler2D texture;
in vec2 TexCoord; //---->add
void main(void)
{
gl_FragColor = texture2D(texture,TexCoord) //( no clue how to use it) -->here is the change
//gl_FragColor = vertexColorOut;
}
);

OpenGL texture not rendering if it's currently active

I was using QOpenGLWidget to render textured triangle, the code was looking good but the triangle was always rendering black i had problem with it for two days until i accidentally found out what the title says.
This is the code, the texture gets loaded to default location of GL_TEXTURE0 and the code will not work unless i call glActiveTexture(GL_TEXTURE1) at the end, GL_TEXTURE1 is just an example it can be any other texture slot except the one where texture actually is. Without the call the object will be black.
QImage ready;
QImage image("C:/Users/Gamer/Desktop/New folder/ring.jpg");
ready = image.convertToFormat(QImage::Format_RGBA8888);
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(program.programId(), "samp"), 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ready.width(), ready.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, ready.constBits());
glGenerateMipmap(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE1)
I've tried some tests, creating multiple textures and displaying them all at once, the last active texture was always black unless i activate some other unoccupied slot.
I don't know what to make of this, i'm begginer in OpenGL and Qt but this doesn't sound right.
EDIT:
Main function
#include "mainwindow.h"
#include <QApplication>
#include <QSurfaceFormat>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSurfaceFormat format;
format.setVersion(3, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setSamples(4);
format.setSwapInterval(0);
QSurfaceFormat::setDefaultFormat(format);
MainWindow w;
w.show();
return a.exec();
}
Widget code
#include "openglwidget.h"
#include <QOpenGLShaderProgram>
#include <QImage>
#include <QDebug>
OpenGLWidget::OpenGLWidget(QWidget *parent) :
QOpenGLWidget(parent)
{
}
OpenGLWidget::~OpenGLWidget()
{
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteTextures(1, &texture);
}
void OpenGLWidget::initializeGL()
{
QOpenGLFunctions_3_3_Core::initializeOpenGLFunctions();
GLfloat vertices[] = {
0.0f, 0.75f, 0.0f,
-0.75f, -0.75f, 0.0f,
0.75f, -0.75f, 0.0f,
0.5f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f
};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
program.addShaderFromSourceFile(QOpenGLShader::Vertex, "C:/Users/Gamer/Desktop/New folder/vertex.vert");
program.addShaderFromSourceFile(QOpenGLShader::Fragment, "C:/Users/Gamer/Desktop/New folder/fragment.frag");
program.link();
program.bind();
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (void*)36);
glEnableVertexAttribArray(1);
QImage ready;
QImage image("C:/Users/Gamer/Desktop/New folder/ring.jpg");
ready = image.convertToFormat(QImage::Format_RGBA8888);
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(program.programId(), "samp"), 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ready.width(), ready.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, ready.constBits());
glGenerateMipmap(GL_TEXTURE_2D);
// glActiveTexture(GL_TEXTURE1);
}
void OpenGLWidget::paintGL()
{
GLfloat yellow[] = {1.0, 1.0, 0.0, 0.0};
glClearBufferfv(GL_COLOR, 0, yellow);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void OpenGLWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}
And shaders
#version 330 core
layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 coord;
out vec2 tc;
void main(void)
{
tc = coord;
gl_Position = vec4(pos, 1.0);
}
#version 330 core
uniform sampler2D samp;
in vec2 tc;
out vec4 color;
void main(void)
{
color = texture(samp, tc);
}
QOpenGLWidget is a rather complex abstraction which has some side effects which you might not expect. Quoting from the Qt5 docs:
All rendering happens into an OpenGL framebuffer object. makeCurrent() ensure that it is bound in the context. Keep this in mind when creating and binding additional framebuffer objects in the rendering code in paintGL(). Never re-bind the framebuffer with ID 0. Instead, call defaultFramebufferObject() to get the ID that should be bound.
Now, this in itself isn't an issue. However, looking at the description for the initializeGL() method (my emphasis):
There is no need to call makeCurrent() because this has already been done when this function is called. Note however that the framebuffer is not yet available at this stage, so avoid issuing draw calls from here. Defer such calls to paintGL() instead.
Now, this in itself still is not the issue. But: it means that Qt will create the FBO in-between initializeGL and the first paintGL. Since Qt creates a texture as the color buffer for the FBO, this means it will re-use the currently active texture unit, and change the texture binding you did establish in initializeGL.
If you, on the other hand set glActiveTexture to something other than unit 0, Qt will screw up the binding of that unit, but since you only use unit 0, it will not have any negative effects in your example.
You need to bind the texture to the texture unit before drawing. Texture unit state is not part of program state, unlike uniforms. It is unusual to try and set texture unit state during program startup, that would require allocating different texture units to each program (not out of the question, it's just not the way things are normally done).
Add the following line to paintGL, before the draw call:
glBindTexture(GL_TEXTURE_2D, texture);

Vertex Buffer Object -> Segmentation Fault

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.

How to set the colour of an alpha blended GL_TEXTURE_2D in a QGLWidget

I'm a newbie with blending and textures in Opengl. My render_text() method uses the drawText method in QPainter with a QImage as its device. The QImage becomes a GL_TEXTURE_2D and then is attached to a GL_QUADS. The text appears correctly over the 2d scene as black. I would like to know how to arbitrarily set the colour. If anyone can recommend a good tutorial on how the source to destination blending works would also benefit.
void GLView::render_text(char *txt, quint8 height)
{
QImage image;
qint32 font_height, width;
font_height = height * VIEW_SIZE / (ZOOM * OBJ_HEIGHT);
QFont font("Helvetica", font_height);
QFontMetrics fm(font);
// render text in QImage
QImage img(fm.width(txt), fm.height(), QImage::Format_ARGB32);
img.fill(0);
QPainter pixPaint(&img);
pixPaint.setFont(font);
pixPaint.drawText(0, font_height, txt);
// push to gl
image = QGLWidget::convertToGLFormat(img);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//glBlendColor(1, 0, 0, 0.5);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.width(), image.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.bits() );
width = image.width() * ZOOM * OBJ_WIDTH / VIEW_SIZE; //calc object width from image width
glBegin(GL_QUADS);
glTexCoord2i(0,0); glVertex2f(0, 0);
glTexCoord2i(0,1); glVertex2f(0, height);
glTexCoord2i(1,1); glVertex2f(width, height);
glTexCoord2i(1,0); glVertex2f(width, 0);
glEnd();
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDeleteTextures(1, &texture);
}
You can paint in the right color in the first place -- set the color on the QPainter object / QPen!
May I suggest you use QGLFrameBufferObject? You can draw into it with the QPainter and then draw it as texture with a Qt call within your GL code. Advantages:
Qt will use OpenGL for rendering the text
No copy to the GPU needed.
=> Much faster!

How can I draw my opengl background keeping good performance?

I draw my background every frames :
void Window::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
backgrd->Draw();
texture = text->loadTexture(text->amis_path.toStdString(),text->w,text->h);
amis->Draw();
texture = text->loadTexture(text->enemis_path.toStdString(),text->w,text->h);
for (int i = 0; i<liste_enemis.length(); i++){
liste_enemis[i]->Draw();
}
for (int i = 0; i<liste_missiles.length(); i++){
liste_missiles[i]->Draw();
}
swapBuffers();
}
But when I run the game, the fps a pretty bad (1fps).
Edit :
Well I'm trying to load my background in a texture one time but it doesn't work :
Background::Background(int w, int h)
{
width = w;
height = h;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D,0, GL_RGBA, back.width(), back.height(), 0,
GL_RGBA, GL_UNSIGNED_BYTE, back.bits());
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
void Background::Draw(){
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,texture);
glPushMatrix();
glTranslatef(width/2, height/2, 0.0f);
glBegin(GL_QUADS);
glTexCoord2d(0,0); glVertex3f(-width/2, -height/2, 0.0f);
glTexCoord2d(0,1); glVertex3f(-width/2, height/2, 0.0f);
glTexCoord2d(1,1); glVertex3f(width/2, height/2, 0.0f);
glTexCoord2d(1,0); glVertex3d(width/2, -height/2, 0.0f);
glEnd();
glPopMatrix();
}
The constructor load the background with glTexImage2D(...) and links it to the "texture" variable.
Then in my paintGL() function, I call the Background::Draw() function.
But when I run the game, there is no background.
If I move glTexParameteri(...) and glTexImage2D(...) functions from constructor to Draw function, it works.
You're reloading the textures each and every frame, that's what's causing your performance it (it will also consume your memory in no time).
Instead of reloading the texture every frame, load them only once, and then switch between textures using glBindTexture

Resources