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
Related
I have a Microsoft visual studio application that is grabbing frames from cameras and I am trying to display those frames in a Qt application. I am doing some processing with the frames using OpenCV, so the frames are Mat objects. I use QThreads to parallelize the application. I am getting a Access Violation reading location when I try to emit a Mat signal from my CameraThread class.
main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
mainwindow.cpp
#include "main_window.h"
MainWindow::MainWindow()
{
// create a horizontal widget
main_layout = new QVBoxLayout;
QHBoxLayout* row1 = new QHBoxLayout;
QHBoxLayout* row2 = new QHBoxLayout;
for (int i = 0; i < 1; i++) {
camera_array[i] = new CameraWidget(i);
if (i < 4)
row1->addWidget(camera_array[i]);
else
row2->addWidget(camera_array[i]);
}
main_layout->addLayout(row1);
main_layout->addLayout(row2);
// make the central widget the main layout window
central = new QWidget();
central->setLayout(main_layout);
setCentralWidget(central);
}
camerawidget.cpp
#include "stdafx.h"
#include "camera_widget.h"
CameraWidget::CameraWidget(int id)
{
camera_id = id;
qRegisterMetaType<cv::Mat>("cv::Mat");
current_frame = cv::imread("camera_1.png");
thread = new CameraThread(camera_id);
QObject::connect(thread, SIGNAL(renderFrame(cv::Mat)), this, SLOT(updateFrame(cv::Mat)));
thread->start();
}
CameraWidget::~CameraWidget()
{
qDebug("camera widget destructor");
thread->wait(5000);
}
// initializeGL() function is called just once, before paintGL() is called.
void CameraWidget::initializeGL()
{
qglClearColor(Qt::black);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 480.0f, 640.0f, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glGenTextures(3, &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);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 480.0f, 640.0f, GL_BGR, GL_UNSIGNED_BYTE, NULL);
glDisable(GL_TEXTURE_2D);
}
void CameraWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 480.0f, 640.0f, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
current_frame_i = QImage(current_frame.data, current_frame.cols, current_frame.rows, current_frame.cols * 3, QImage::Format_RGB888);
glBindTexture(GL_TEXTURE_2D, texture);
// ******************************
// getting access violation here
// ******************************
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 480.0f, 640.0f, 0.0f, GL_BGR, GL_UNSIGNED_BYTE, current_frame.ptr());
glBegin(GL_QUADS);
glTexCoord2i(0, 1); glVertex2i(0, 640.0f);
glTexCoord2i(0, 0); glVertex2i(0, 0);
glTexCoord2i(1, 0); glVertex2i(480.0f, 0);
glTexCoord2i(1, 1); glVertex2i(480.0f, 640.0f);
glEnd();
glFlush();
}
void CameraWidget::resizeGL(int w, int h)
{
// setup viewport, projection etc.
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 480.0f, 640.0f, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void CameraWidget::updateFrame(cv::Mat image)
{
current_frame = image;
update();
}
camerathread.cpp
CameraThread::CameraThread(int id)
{
camera_q = new bounded_frame_queue(50);
}
void CameraThread::run()
{
cv::Mat image;
while (true) {
if (!camera_q->empty()) {
image = camera_q->pop();
if (!image.empty())
emit renderFrame(image);
}
else {
msleep(1);
}
}
}
When I emit renderFrame from the camerathread.cpp, I get an access violation reading location. I cannot read the current_frame.ptr() value in camerawidget.cpp.
Can someone direct me on how I can fix this issue?
What I see is happenning:
You get an image from queue. As per OpenCV docs:
Mat& cv::Mat::operator= ( const Mat & m )
Assigned, right-hand-side matrix. Matrix assignment is an O(1)
operation. This means that no data is copied but the data is shared
and the reference counter, if any, is incremented. Before assigning
new data, the old data is de-referenced via Mat::release .
Then you pass it as cv::Mat image (by value) when emitting signal. The copy constructor again doesn't copy any data:
Array that (as a whole or partly) is assigned to the constructed
matrix. No data is copied by these constructors. Instead, the header
pointing to m data or its sub-array is constructed and associated with
it. The reference counter, if any, is incremented. So, when you modify
the matrix formed using such a constructor, you also modify the
corresponding elements of m . If you want to have an independent copy
of the sub-array, use Mat::clone() .
Your data pointers are queued on UI thread
You get/try-get new frame triggering release from p.1
Your queued slot is executed and crashes...
Suggestion: I haven't worked much with it, but it seems something like cv::Mat::clone to make a deep copy is what you need, to prevent release of memory before it would be used by UI thread.
Or possibly it would be enough to define image right when you pop it from queue:
cv::Mat image = camera_q->pop();
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);
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!?
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!
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.