Related
I have created two shader programs shaderProgram0 and shaderProgram1. I have appended all related shaders and variables with either 0 or 1 to show their relation with either shaderProgram0 or shaderProgram1.
Both shader programs work as designed. shaderProgram0 use SimpleVertexShader0.vert as a vertex shader:
#version 330
in vec3 vertexPosition0;
void main()
{
gl_Position = vec4(vertexPosition0, 1);
}
The output of shaderProgram0 is like this:
shaderProgram1 use SimpleVertexShader1.vert as a vertex shader:
#version 330
in vec3 vertexPosition1;
void main()
{
gl_Position = vec4(vertexPosition1, 1);
}
The output of shaderProgram1 is like this:
Now the fun part is this; when using shaderProgram1, I accidentally commented the binding of vertex attribute array vao1 and left the binding of vao0 uncommented which resulted in output like the following picture which is in fact the output which (I think) could be generated only by shaderProgram0!:
Code is simplified and is written using Qt Creator in Windows:
void OpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
shaderProgram0.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/SimpleVertexShader0.vert");
shaderProgram0.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/SimpleFragmentShader0.frag");
shaderProgram0.link();
shaderProgram1.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/SimpleVertexShader1.vert");
shaderProgram1.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/SimpleFragmentShader1.frag");
shaderProgram1.link();
}
void OpenGLWidget::resizeGL(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}
void OpenGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLfloat vertexBufferData0[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
GLuint vbo0;
glGenBuffers(1, &vbo0);
glBindBuffer(GL_ARRAY_BUFFER, vbo0);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertexBufferData0),
vertexBufferData0,
GL_STATIC_DRAW);
GLuint vao0;
glGenVertexArrays(1, &vao0);
glBindVertexArray(vao0);
glBindBuffer(GL_ARRAY_BUFFER, vbo0);
glVertexAttribPointer(glGetAttribLocation(shaderProgram0.programId(),"vertexPosition0"), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
GLfloat vertexBufferData1[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
GLuint vbo1;
glGenBuffers(1, &vbo1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glBufferData(GL_ARRAY_BUFFER,
sizeof(vertexBufferData1),
vertexBufferData1,
GL_STATIC_DRAW);
GLuint vao1;
glGenVertexArrays(1, &vao1);
glBindVertexArray(vao1);
glBindBuffer(GL_ARRAY_BUFFER, vbo1);
glVertexAttribPointer(glGetAttribLocation(shaderProgram1.programId(),"vertexPosition1"), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
// Now Rendering-----------------------------------------------------
glBindVertexArray(vao0);
glEnableVertexAttribArray(glGetAttribLocation(shaderProgram0.programId(),"vertexPosition0"));
// glBindVertexArray(vao1);
// glEnableVertexAttribArray(glGetAttribLocation(shaderProgram1.programId(),"vertexPosition1"));
shaderProgram1.bind();
glDrawArrays(GL_TRIANGLES, 0, 3);
}
Isn't it strange that the vertex shader of shaderProgram1 access the buffer data which is bound with shaderProgram0 attribute? I thought it should not have generated any output as the valid vertex attribute array is not enabled!
Please explain this scenario if somebody knows how this works. If you don't understand what i am asking then please look at the code thoroughly you will get the point or i will explain further.
EDIT:
// Now Rendering-----------------------------------------------------
glBindVertexArray(vao0);
glEnableVertexAttribArray(glGetAttribLocation(shaderProgram0.programId(),"vertexPosition0"));
shaderProgram0.bind();
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(vao1);
glEnableVertexAttribArray(glGetAttribLocation(shaderProgram1.programId(),"vertexPosition1"));
shaderProgram1.bind();
glDrawArrays(GL_TRIANGLES, 0, 3);
Output of the edited code is:
Here a question arise if both programs are using the same location for the only attribute then they should either generate one or the other triangle not both due overwriting!?
Bear with me please, i have just started learning it.
Isn't it strange that the vertex shader of shaderProgram1 access the buffer data which is bound with shaderProgram0 attribute?
No.
If you are not explicitly specifying attribute locations from your shader, or using glBindAttribLocation before linking the program, then the implementation will arbitrarily assign vertex attribute locations for you. There is no requirement that separate programs use separate attribute locations. Indeed, it's generally advised that you try to make your attribute location interfaces compatible between programs where possible.
In your case, the implementation happened to assign them both to the same location. So either VAO will work with either program.
I'm trying to render a QImage using OpenGL wrapper classes of Qt5 and shader programs. I have the following shaders and a 3.3 core context. I'm also using a VAO for the attributes. However, I keep getting a blank red frame (red is the background clear color that I set). I'm not sure if it is a problem with the MVP matrices or something else. Using a fragment shader which sets the output color to a certain fixed color (black) still resulted in a red frame. I'm totally lost here.
EDIT-1: I also noticed that attempting to get the location of texRGB uniform from the QOpenGLShaderProgram results in -1. But I'm not sure if that has anything to do with the problem I'm having. Uniforms defined in the vertex shader for the MVP matrices have the locations 0 and 1.
Vertex Shader
#version 330
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec2 inTexCoord;
out vec2 vTexCoord;
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
void main(void)
{
gl_Position = projectionMatrix * modelViewMatrix * vec4(inPosition, 1.0);
// pass the input texture coordinates to fragment shader
vTexCoord = inTexCoord;
}
Fragment Shader
#version 330
uniform sampler2DRect texRGB;
in vec2 vTexCoord;
out vec4 fColor;
void main(void)
{
vec3 rgb = texture2DRect(texRGB, vTexCoord.st).rgb;
fColor = vec4(rgb, 0.0);
}
OGLWindow.h
#include <QOpenGLWindow>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLTexture>
#include <QDebug>
#include <QString>
class OGLWindow : public QOpenGLWindow, protected QOpenGLFunctions
{
public:
OGLWindow();
~OGLWindow();
// OpenGL Events
void initializeGL();
void resizeGL(int width, int height);
void paintGL();
// a method for cleanup
void teardownGL();
private:
bool isInitialized;
// OpenGL state information
QOpenGLBuffer m_vbo_position;
QOpenGLBuffer m_vbo_index;
QOpenGLBuffer m_vbo_tex_coord;
QOpenGLVertexArrayObject m_object;
QOpenGLShaderProgram* m_program;
QImage m_image;
QOpenGLTexture* m_texture;
QMatrix4x4 m_projection_matrix;
QMatrix4x4 m_model_view_matrix;
};
OGLWindow.cpp
#include "OGLWindow.h"
// vertex data
static const QVector3D vertextData[] = {
QVector3D(-1.0f, -1.0f, 0.0f),
QVector3D( 1.0f, -1.0f, 0.0f),
QVector3D( 1.0f, 1.0f, 0.0f),
QVector3D(-1.0f, 1.0f, 0.0f)
};
// indices
static const GLushort indices[] = {
0, 1, 2,
0, 2, 3
};
OGLWindow::OGLWindow() :
m_vbo_position (QOpenGLBuffer::VertexBuffer),
m_vbo_tex_coord (QOpenGLBuffer::VertexBuffer),
m_vbo_index (QOpenGLBuffer::IndexBuffer),
m_program (nullptr),
m_texture (nullptr),
isInitialized (false)
{
}
OGLWindow::~OGLWindow()
{
makeCurrent();
teardownGL();
}
void OGLWindow::initializeGL()
{
qDebug() << "initializeGL()";
initializeOpenGLFunctions();
isInitialized = true;
QColor backgroundColor(Qt::red);
glClearColor(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), 1.0f);
// load texture image
m_image = QImage(":/images/cube.png");
m_texture = new QOpenGLTexture(QOpenGLTexture::TargetRectangle);
// set bilinear filtering mode for texture magnification and minification
m_texture->setMinificationFilter(QOpenGLTexture::Nearest);
m_texture->setMagnificationFilter(QOpenGLTexture::Nearest);
// set the wrap mode
m_texture->setWrapMode(QOpenGLTexture::ClampToEdge);
m_texture->setData(m_image.mirrored(), QOpenGLTexture::MipMapGeneration::DontGenerateMipMaps);
int imgWidth = m_image.width();
int imgHeight = m_image.height();
m_projection_matrix.setToIdentity();
m_projection_matrix.ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
// m_projection_matrix.ortho(0.0, (float) width(), (float) height(), 0.0f, -1.0f, 1.0f);
m_model_view_matrix.setToIdentity();
glViewport(0, 0, width(), height());
m_program = new QOpenGLShaderProgram();
m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader.glsl");
m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl");
m_program->link();
m_program->bind();
// texture coordinates
static const QVector2D textureData[] = {
QVector2D(0.0f, 0.0f),
QVector2D((float) imgWidth, 0.0f),
QVector2D((float) imgWidth, (float) imgHeight),
QVector2D(0.0f, (float) imgHeight)
};
// create Vertex Array Object (VAO)
m_object.create();
m_object.bind();
// create position VBO
m_vbo_position.create();
m_vbo_position.bind();
m_vbo_position.setUsagePattern(QOpenGLBuffer::StaticDraw);
m_vbo_position.allocate(vertextData, 4 * sizeof(QVector3D));
// create texture coordinates VBO
m_vbo_tex_coord.create();
m_vbo_tex_coord.bind();
m_vbo_tex_coord.setUsagePattern(QOpenGLBuffer::StaticDraw);
m_vbo_tex_coord.allocate(textureData, 4 * sizeof(QVector2D));
// create the index buffer
m_vbo_index.create();
m_vbo_index.bind();
m_vbo_index.setUsagePattern(QOpenGLBuffer::StaticDraw);
m_vbo_index.allocate(indices, 6 * sizeof(GLushort));
// enable the two attributes that we have and set their buffers
m_program->enableAttributeArray(0);
m_program->enableAttributeArray(1);
m_program->setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(QVector3D));
m_program->setAttributeBuffer(1, GL_FLOAT, 0, 2, sizeof(QVector2D));
// Set modelview-projection matrix
m_program->setUniformValue("projectionMatrix", m_projection_matrix);
m_program->setUniformValue("modelViewMatrix", m_model_view_matrix);
// use texture unit 0 which contains our frame
m_program->setUniformValue("texRGB", 0);
// release (unbind) all
m_object.release();
m_vbo_position.release();
m_vbo_tex_coord.release();
m_vbo_index.release();
m_program->release();
}
void OGLWindow::resizeGL(int width, int height)
{
qDebug() << "resizeGL(): width =" << width << ", height=" << height;
if (isInitialized) {
// avoid division by zero
if (height == 0) {
height = 1;
}
m_projection_matrix.setToIdentity();
m_projection_matrix.perspective(60.0, (float) width / (float) height, -1, 1);
glViewport(0, 0, width, height);
}
}
void OGLWindow::paintGL()
{
// clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// render using our shader
m_program->bind();
{
m_texture->bind();
m_object.bind();
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0) );
m_object.release();
}
m_program->release();
}
void OGLWindow::teardownGL()
{
// actually destroy our OpenGL information
m_object.destroy();
m_vbo_position.destroy();
m_vbo_color.destroy();
delete m_program;
}
EDIT-2: I'm creating the context as follows:
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3,3);
This line in your fragment shader code is invalid:
vec3 rgb = texture2DRect(texRGB, vTexCoord.st).rgb;
texture2DRect() is not a built-in function.
Since you're using the GLSL 3.30 core profile (core is the default for the version unless compatibility is specified), you should be using the overloaded texture() function, which replaces the older type specific functions like texture2D() in the core profile.
Functions like texture2D() are still supported in GLSL 3.30 core unless a forward compatible core profile context is used. So depending on how the context is created, you can still use those functions.
However, sampler2DRect was only added as a sampler type in GLSL 1.40 as part of adding rectangular textures to the standard in OpenGL 3.1. At the time, the legacy sampling functions were already marked as deprecated, and only the new texture() function was defined for rectangular textures. This means that texture2DRect() does not exist in any GLSL version.
The correct call is:
vec3 rgb = texture(texRGB, vTexCoord.st).rgb;
Another part of your code that can prevent it from rendering anything is this projection matrix:
m_projection_matrix.perspective(60.0, (float) width / (float) height, -1, 1);
The near and far planes for a standard projection matrix both need to be positive. This call will set up a projection transformation with a "camera" on the origin, looking down the negative z-axis. The near and far values are distances from the origin. A valid call could look like this:
m_projection_matrix.perspective(60.0, (float) width / (float) height, 1.0f, 10.0f);
You will then also need to set the model matrix to transform the coordinates of the object into this range on the negative z-axis. You could for example apply a translation by (0.0f, 0.0f, -5.0f).
Or, if you just want to see something, the quad should also become visible if you simply use the identity matrix for the projection.
I'm trying to use OpenGL for visibility testing for complex geometries. What I want to do is simple: assign each primitive an integer ID, and then count the number of pixels with that ID. That allows me to calculate the relative visible area of each primitive. (Ultimately, this will be expanded to some minor finite-element calculations on the visible area.)
My problem is this. I'm trying to read the output of a fragment shader into my application memory: specifically, the primitive ID output. I'm using QT 4.7.4 and its OpenGL wrapper classes. When I bind and enable a buffer (a "PixelPack" buffer), and attempt to read from the OpenGL buffer into the memory, it reports a successful read. But the values stored in the array are not what I expect- they're all 0, even though for testing purposes I've set the ID to 1 for all primitives.
Here's my fragment shader:
#version 130
in vec4 Color;
flat in uint VertId;
out vec4 FragColor;
out uint FragId;
void main()
{
FragColor = Color;
// Changed to simpler version for debugging.
// FragId = VertId;
FragId = uint( 1 );
}
And here's my application code, with some irrelevant parts stripped off (test harness hookups, etc.):
#include <QtOpenGL/QGLShader>
#include <QtOpenGL/QGLShaderProgram>
#include <QtOpenGL/QGLBuffer>
using namespace std;
string loadSource( string file );
int
testSelfShadow::
shader( ostream& error )
{
bool fail = false;
// Create the OpenGL context.
int argc = 0;
char* argv;
QApplication* app = new QApplication( argc, &argv );
QGLWidget* widget = new QGLWidget();
widget->makeCurrent();
// Create the shader program.
QGLShaderProgram* prog = new QGLShaderProgram();
bool success = false;
success = prog->addShaderFromSourceCode( QGLShader::Vertex,
loadSource( "vertex.glsl" ).c_str() );
if ( ! success )
{
ErrorOStream msg;
msg << "Error trying to load vertex shader into a shader program.\n"
<< prog->log().toStdString();
throw ERRORLOG( msg.str() );
}
success = prog->addShaderFromSourceCode( QGLShader::Fragment,
loadSource( "fragment.glsl" ).c_str() );
if ( ! success )
{
ErrorOStream msg;
msg << "Error trying to load fragment shader into a shader program.\n"
<< prog->log().toStdString();
throw ERRORLOG( msg.str() );
}
success = prog->link();
if ( ! success )
{
ErrorOStream msg;
msg << "Error trying to link shaders into a shader program.\n"
<< prog->log().toStdString();
throw ERRORLOG( msg.str() );
}
prog->bind();
// Create the buffer for vertex position.
QGLBuffer* vBuf = new QGLBuffer( QGLBuffer::VertexBuffer );
vBuf->create();
vBuf->setUsagePattern( QGLBuffer::DynamicDraw );
vBuf->bind();
GLfloat vertices[] = {
-1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, 0.0f, 1.0f,
-1.0f, 0.0f, 0.1f, 1.0f,
-1.0f, 1.0f, 0.1f, 1.0f,
1.0f, 1.0f, 0.1f, 1.0f,
1.0f, 0.0f, 0.1f, 1.0f };
vBuf->allocate( vertices, sizeof( vertices ) );
prog->setAttributeBuffer( "Vertex", GL_FLOAT, 0, 4, 0 );
prog->enableAttributeArray( "Vertex" );
// Create the buffer for Grayscale brightness value.
// Not important for final program, just for debugging during
// development.
QGLBuffer* bBuf = new QGLBuffer( QGLBuffer::VertexBuffer );
bBuf->create();
bBuf->bind();
GLfloat brightness[] = {
1.0, 0.9, 0.8, 0.7,
0.5, 0.4, 0.3, 0.2
};
bBuf->allocate( brightness, sizeof( brightness ) );
prog->setAttributeBuffer( "Brightness", GL_FLOAT, 0, 1, 0 );
prog->enableAttributeArray( "Brightness" );
// Create the buffer for polygon ID.
QGLBuffer* idBuf = new QGLBuffer( QGLBuffer::VertexBuffer );
idBuf->create();
idBuf->bind();
GLuint polyId[] = {
1, 1, 1, 1,
2, 2, 2, 2
};
idBuf->allocate( polyId, sizeof( polyId ) );
prog->setAttributeBuffer( "PolyId", GL_UNSIGNED_INT, 0, 1, 0 );
prog->enableAttributeArray( "PolyId" );
// Create the index buffer. Not trying to do any optimization
// here yet.
QGLBuffer* iBuf = new QGLBuffer( QGLBuffer::IndexBuffer );
iBuf->create();
iBuf->bind();
GLuint indices[] = {
0, 1, 2, 3, 4, 5, 6, 7
};
iBuf->setUsagePattern( QGLBuffer::StaticDraw );
iBuf->allocate( indices, sizeof( indices ) );
// Create the buffer for reading back polygon id per fragment.
QGLBuffer* fBuf = new QGLBuffer( QGLBuffer::PixelPackBuffer );
fBuf->create();
fBuf->setUsagePattern( QGLBuffer::DynamicRead );
fBuf->bind();
fBuf->allocate( 640 * 480 * sizeof( GLuint ) );
prog->setAttributeBuffer( "FragId", GL_UNSIGNED_INT, 0, 1, 0 );
prog->enableAttributeArray( "FragId" );
GLuint* fBufData = new GLuint[ 640 * 480 * sizeof( GLuint ) ];
glDrawElements( GL_QUADS, 8, GL_UNSIGNED_INT, 0 );
widget->show();
widget->updateGL();
// Trying this two different ways; neither way works.
bool readSuccess = fBuf->read( 0, fBufData, 640 * 480 * sizeof( GLuint ) );
GLuint* fBufMap =
static_cast< GLuint* >( fBuf->map( QGLBuffer::ReadOnly ) );
cout << "\n"
<< "Read Successful: " << readSuccess << endl;
cout << "Buffer map location and sample data: "
<< fBufMap << ":" << fBufMap[640] << endl;
cout << "Read data pointer: " << fBufData << endl;
cout << "Sample fragment ID: " << fBufData[ 640 * 480 / 2 ] << endl;
app->exec();
return fail;
}
Here are sample outputs for a program run:
Read Successful: true
Buffer map location and sample data: 0x5a5d9000:0
Read data pointer: 0x59e48008
Sample fragment ID: 0
That's not what I would expect. I would expect all fragment IDs to be 1, because I explicitly set FragId = uint( 1 ) in the fragment shader. Am I setting up my reads wrong? Am I doing something wrong in my binding of buffers, or enabling the names?
I would prefer to use QT code if possible, for reasons beyond the scope of this question.
There's so much Qt stuff in here that it's almost impossible to find actual OpenGL calls. But you seem to have two problems:
You're rendering to the screen. Your screen uses some kind of normalized integer image format. Which basically means "float, but takes up 8 bits". You're writing integers from your shader. These don't match. Therefore, your rendering yields undefined behavior.
What you need to do is render to an FBO that contains a GL_R8UI texture. Then your uint fragment shader output type will match your buffer. You will probably want a depth buffer too.
You never actually read the pixel data. QGLBuffer::read reads from the buffer object. But you haven't put anything into the buffer object yet. You never told OpenGL to copy the framebuffer data you rendered and store it in the buffer object. You need to do that first; after doing that, then you can read from it.
After you render to your FBO, you need to call glReadPixels. When you do that, you need to provide the correct pixel transfer parameters for what you've rendered. Namely, you need to use GL_RED_INTEGER for the format and GL_UNSIGNED_BYTE for the type. And since you're reading into a pixel buffer, you need to make sure it is bound before reading.
I am trying to implement a game using opengl in qt4. So far I have created the football pitch and I am now trying to implement a camera with which the user can move in the world freely using the arrow keys. My friend used a piece of code he found on NeHe's tutorials and simply copy pasted it to his code and the camera worked for him. When I tried the same only the escape button works and it just closes the opengl widget. f1 key is supposed to switch to fullscreen but it just makes the mouse cursor invisible without switching to fullscreen mode. The arrow keys don't work at all. As I'm new to opengl I could not figure out what is wrong with the implementation.
I'm adding the code where I draw the pitch and also the keyboard event handlers.
void metinalifeyyaz::paintGL(){
movePlayer();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
GLfloat xtrans = -xpos;
GLfloat ytrans = -walkbias - 0.50f;
GLfloat ztrans = -zpos;
GLfloat sceneroty = 360.0f - yrot;
glLoadIdentity();
glRotatef(lookupdown, 1.0f, 0.0f, 0.0f);
glRotatef(sceneroty, 0.0f, 1.0f, 0.0f);
glTranslatef(xtrans, ytrans+50, ztrans-130);
glLoadIdentity();
glTranslatef(1.0f,0.0f,-18.0f);
glRotatef(45,1,0,0);
drawScene();
int delay = time.msecsTo(QTime::currentTime());
if (delay == 0)
delay = 1;
time = QTime::currentTime();
timer->start(qMax(0,10 - delay));
}
void metinalifeyyaz::movePlayer() {
if (keyUp) {
xpos -= sin(yrot * PI_OVER_180) * 0.5f;
zpos -= cos(yrot * PI_OVER_180) * 0.5f;
if (walkbiasangle >= 360.0f)
walkbiasangle = 0.0f;
else
walkbiasangle += 7.0f;
walkbias = sin(walkbiasangle * PI_OVER_180) / 10.0f;
} else if (keyDown) {
xpos += sin(yrot * PI_OVER_180)*0.5f;
zpos += cos(yrot * PI_OVER_180)*0.5f ;
if (walkbiasangle <= 7.0f)
walkbiasangle = 360.0f;
else
walkbiasangle -= 7.0f;
walkbias = sin(walkbiasangle * PI_OVER_180) / 10.0f;
}
if (keyLeft)
yrot += 0.5f;
else if (keyRight)
yrot -= 0.5f;
if (keyPageUp)
lookupdown -= 0.5;
else if (keyPageDown)
lookupdown += 0.5;
}
void metinalifeyyaz::keyPressEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_Escape:
close();
break;
case Qt::Key_F1:
setWindowState(windowState() ^ Qt::WindowFullScreen);
break;
default:
QGLWidget::keyPressEvent(event);
case Qt::Key_PageUp:
keyPageUp = true;
break;
case Qt::Key_PageDown:
keyPageDown = true;
break;
case Qt::Key_Left:
keyLeft = true;
break;
case Qt::Key_Right:
keyRight = true;
break;
case Qt::Key_Up:
keyUp = true;
break;
case Qt::Key_Down:
keyDown = true;
break;
}
}
void metinalifeyyaz::changeEvent(QEvent *event) {
switch (event->type()) {
case QEvent::WindowStateChange:
if (windowState() == Qt::WindowFullScreen)
setCursor(Qt::BlankCursor);
else
unsetCursor();
break;
default:
break;
}
}
void metinalifeyyaz::keyReleaseEvent(QKeyEvent *event) {
switch (event->key()) {
case Qt::Key_PageUp:
keyPageUp = false;
break;
case Qt::Key_PageDown:
keyPageDown = false;
break;
case Qt::Key_Left:
keyLeft = false;
break;
case Qt::Key_Right:
keyRight = false;
break;
case Qt::Key_Up:
keyUp = false;
break;
case Qt::Key_Down:
keyDown = false;
break;
default:
QGLWidget::keyReleaseEvent(event);
}
}
I know that copy paste is not an efficient method but my friend's project is not different than mine and it works for him. If you know anything that might cause the same code to work on one project and not the other please point it out. Of course any other comment about the code are much appreciated.
Look:
glLoadIdentity();
glRotatef(lookupdown, 1.0f, 0.0f, 0.0f);
glRotatef(sceneroty, 0.0f, 1.0f, 0.0f);
glTranslatef(xtrans, ytrans+50, ztrans-130);
glLoadIdentity(); // get rid of this!
glTranslatef(1.0f,0.0f,-18.0f);
glRotatef(45,1,0,0);
drawScene();
"glLoadIdentity" resets the current matrix. In your code, you rotate and translate the matrix, but afterward, you reset the matrix by calling "glLoadIdentity", so the previous matrix transformations do nothing.
Basically this is your code:
OpenGL, reset the matrix.
OpenGL, move the player and camera.
OpenGL, reset the matrix, and forget anything I just did.
OpenGL, do... whatever that is.
OpenGL, draw my scene!
I've very recently picked up Qt and am using it with OpenGL
The thing though is that when moving my SDL code to Qt and changing the texture code to use QImage it stops working.
The image does load correctly, as shown through the error checking code.
Thanks!
P.S: Please don't suggest I use glDrawPixels, I need to fix the problem at hand. Some of the reasons for that being 1. slow 2. android (which this code may be running on eventually) is OpenGL ES and does not support glDrawPixels
Here's the code:
//original image
QImage img;
if(!img.load(":/star.png"))
{
//loads correctly
qWarning("ERROR LOADING IMAGE");
}
//array for holding texture ID
GLuint texture[1];
//get the OpenGL-friendly image
QImage GL_formatted_image;
GL_formatted_image = QGLWidget::convertToGLFormat(img);
//make sure its not null
if(GL_formatted_image.isNull())
qWarning("IMAGE IS NULL");
else
qWarning("IMAGE NOT NULL");
//generate the texture name
glGenTextures(1, texture);
//bind the texture ID
glBindTexture(GL_TEXTURE_2D, texture[0]);
//generate the texture
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, GL_formatted_image.width(),
GL_formatted_image.height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, GL_formatted_image.bits() );
//texture parameters
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//draw the texture
glPushMatrix();
glTranslatef(-2.0f, 0.0f, 0.0f);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLES);
glVertex2f(1.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f);
glVertex2f(0.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f);
glEnd();
glPopMatrix();
Here's the original texture loading function with SDL:
GLuint loadTexturewithSDL(const char* FILE, GLenum texture_format)
{
GLuint texture; // This is a handle to our texture object
SDL_Surface *surface; // This surface will tell us the details of the image
GLint nOfColors;
if ( (surface = SDL_LoadBMP(FILE)) ) {
// Check that the image's width is a power of 2
if ( (surface->w & (surface->w - 1)) != 0 ) {
printf("warning: image's width is not a power of 2\n");
}
// Also check if the height is a power of 2
if ( (surface->h & (surface->h - 1)) != 0 ) {
printf("warning: image's height is not a power of 2\n");
}
// get the number of channels in the SDL surface
nOfColors = surface->format->BytesPerPixel;
if (nOfColors == 4) // contains an alpha channel
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGBA;
else
texture_format = GL_BGRA;
} else if (nOfColors == 3) // no alpha channel
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGB;
else
texture_format = GL_BGR;
} else {
printf("warning: the image is not truecolor.. this will probably break\n");
// this error should not go unhandled
}
// Have OpenGL generate a texture object handle for us
glGenTextures( 1, &texture );
// Bind the texture object
glBindTexture( GL_TEXTURE_2D, texture );
// Set the texture's stretching properties
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// Edit the texture object's image data using the information SDL_Surface gives us
glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, surface->w, surface->h, 0,
texture_format, GL_UNSIGNED_BYTE, surface->pixels );
}
else {
printf("SDL could not load image %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
// Free the SDL_Surface only if it was successfully created
if ( surface ) {
SDL_FreeSurface( surface );
}
return texture;
}
I have similar code that works but uses glTexSubImage2D :
void Widget::paintGL()
{
glClear (GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,win.width(),0,win.height());
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0 , image.width(), image.height(), glFormat, glType, image.bits() );
glBegin(GL_QUADS); // in theory triangles are better
glTexCoord2i(0,0); glVertex2i(0,win.height());
glTexCoord2i(0,1); glVertex2i(0,0);
glTexCoord2i(1,1); glVertex2i(win.width(),0);
glTexCoord2i(1,0); glVertex2i(win.width(),win.height());
glEnd();
glFlush();
}
void Widget::initializeGL()
{
glClearColor (0.0,0.0,0.0,1.0);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0,win.width(),0,win.height());
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, glFormat, image.width(), image.height(), 0, glFormat, glType, NULL );
glDisable(GL_TEXTURE_2D);
}
And a few perfomance tweaks in the ctor
void Widget::setDisplayOptions()
{
glFormat = GL_RGB; // QImage RGBA is BGRA
glType = GL_UNSIGNED_BYTE;
QGL::setPreferredPaintEngine(QPaintEngine::OpenGL2);
QGLFormat glFmt;
glFmt.setSwapInterval(1); // 1= vsync on
glFmt.setAlpha(GL_RGBA==glFormat);
glFmt.setRgba(GL_RGBA==glFormat);
glFmt.setDoubleBuffer(true); // default
glFmt.setOverlay(false);
glFmt.setSampleBuffers(false);
QGLFormat::setDefaultFormat(glFmt);
setAttribute(Qt::WA_OpaquePaintEvent,true);
setAttribute(Qt::WA_PaintOnScreen,true);
}
This is my solution for conversion from Qt to GL
This also can work in reverse with little changes;
Cheers -- Daimon
void Image::Convert32bitARGBtoRGBA()
{
if(!isQtImage()) return;
QImage& q = *(m_data->image);
U32 count=0, max=(U32)(q.height()*q.width());
U32* p = (U32*)(q.bits());
U32 n;
while( count<max )
{
n = p[count]; //n = ARGB
p[count] = 0x00000000 |
((n<<8) & 0x0000ff00) |
((n<<8) & 0x00ff0000) |
((n<<8) & 0xff000000) |
((n>>24) & 0x000000ff);
// p[count] = RGBA
count++;
}
}
void Image::Convert32bitRGBAtoARGB()
{
if(!isQtImage()) return;
QImage& q = *(m_data->image);
U32 count=0, max=(U32)(q.height()*q.width());
U32* p = (U32*)(q.bits());
U32 n;
while( count<max )
{
n = p[count]; //n = RGBA
p[count] = 0x00000000 |
((n>>8) & 0x000000ff) |
((n>>8) & 0x0000ff00) |
((n>>8) & 0x00ff0000) |
((n<<24) & 0xff000000);
// p[count] = ARGB
count++;
}
}
It looks like your problem is not here, as I have no problem with the following code.
You should check your GL init and display setup.
Have you a glEnable(GL_TEXTURE_2D) somewhere ?
Also note glTexCoord2f must be before glVertex2f.
#include <GL/glut.h>
#include <QtOpenGL/qgl.h>
#include <iostream>
GLuint texture[1] ;
void LoadGLTextures( const char * name )
{
QImage img;
if( ! img.load( name ) )
{
std::cerr << "error loading " << name << std::endl ;
exit( 1 );
}
QImage GL_formatted_image;
GL_formatted_image = QGLWidget::convertToGLFormat(img);
if( GL_formatted_image.isNull() )
{
std::cerr << "error GL_formatted_image" << std::endl ;
exit( 1 );
}
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
GL_formatted_image.width(), GL_formatted_image.height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, GL_formatted_image.bits() );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
}
void resize(int Width, int Height)
{
glViewport( 0 , 0 , Width , Height );
}
void draw()
{
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f);
glClear( GL_COLOR_BUFFER_BIT );
gluOrtho2D( -1 , 1 , -1 , 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glShadeModel( GL_FLAT );
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glBegin(GL_TRIANGLES);
glTexCoord2f( 1.0f, 0.0f);
glVertex2f( 1.0f, 0.0f);
glTexCoord2f( 0.0f, 1.0f);
glVertex2f( 0.0f, 1.0f);
glTexCoord2f( 0.0f, 0.0f);
glVertex2f( 0.0f, 0.0f);
glEnd();
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA );
glutInitWindowSize(640, 480);
glutCreateWindow("Texture");
LoadGLTextures( "star.png" );
glutDisplayFunc( & draw );
glutReshapeFunc( & resize );
glutMainLoop();
return 1;
}