0

I am trying to transfer an OpenGL code from GLFW to Qt, in order to integrate it with a larger project. But not matter what I have tried, I have not been able to make a texture show up and all I get is a black screen.

In Qt, the program compiles with no errors and I have managed to draw a multi-color triangle before attempting to insert textures.

I have tried using the Qt OpenGL Objects for shaders, shader programs, textures, and re-write code based on their examples but still nothing.

Below is a simple Qt implementation that attempts to display a texture, which results in black screen. An exact GLFW equivalent works fine:

CustomViewGL::CustomViewGL(QWidget *parent): QOpenGLWidget(parent)
{
    QSurfaceFormat format;

    format.setMajorVersion(3);
    format.setMinorVersion(3);
    format.setProfile(QSurfaceFormat::CoreProfile);
    setFormat(format);
}

void CustomViewGL::initializeGL()
{
    glewExperimental=true;

    if (glewInit() != GLEW_OK)
    {
        qDebug() << "Failed to initialize GLEW";
    }

    std::string vertexShaderSource =
            " #version 330 core\n                                 "
            "                                                     "
            " layout (location = 0) in vec3 aPos;                 "
            " layout (location = 1) in vec2 aTexCoord;            "
            "                                                     "
            " out vec2 TexCoord;                                  "
            "                                                     "
            " void main()                                         "
            " {                                                   "
            "                                                     "
            "   TexCoord = aTexCoord;                             "
            "   gl_Position = vec4(aPos, 1.0);                    "
            "                                                     "
            " }\0                                                 ";

    std::string fragmentShaderSource =
            " #version 330 core\n                                 "
            "                                                     "
            " in vec2 TexCoord;                                   "
            " out vec4 FragColor;                                 "
            " uniform sampler2D tex;                              "
            " void main()                                         "
            " {                                                   "
            "                                                     "
            " FragColor = texture(tex, TexCoord);                 "
            "                                                     "
            " }\0                                                 ";

    // Variables
    unsigned int shaderVertex, shaderFragment, shaderProgram;

    ....
    ....
    // Compile Shaders //
    ...
    ...

    glUseProgram(shaderProgram);

    // Vetrices
    float rectangle[] = {
        // positions          // texture coords
         1.0f,  1.0f, 0.0f,   1.0f, 1.0f,   // top right
         1.0f, -1.0f, 0.0f,   1.0f, 0.0f,   // bottom right
        -1.0f, -1.0f, 0.0f,   0.0f, 0.0f,   // bottom left
        -1.0f,  1.0f, 0.0f,   0.0f, 1.0f    // top left
    };

    unsigned int indices[] = {  // note that we start from 0!
        0, 1, 3,   // first triangle
        1, 2, 3    // second triangle
    };

    QImage texture = QImage("wall.jpg").convertToFormat(QImage::Format_RGB888);

    // Variables
    unsigned int VAO, VBO, EBO, tex;

    // VAO, VBO, Attributes Configuration
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(rectangle), rectangle, GL_STATIC_DRAW);


    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // Texture

    glGenTextures(1, &tex);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

    float borderColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture.width(), texture.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, texture.bits());

    glGenerateMipmap(GL_TEXTURE_2D);
}

void CustomViewGL::paintGL()
{
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*) 0);
}
Manos
  • 143
  • 9
  • Edit in a [mcve]. – genpfault Dec 15 '17 at 15:06
  • @genpfault It's OpenGL code, is as minimal as it can be. Only the most important stuff is in the code. It is complete, everything is included and verifiable, you can copy and paste it and check if works. It does nothing special, just loads a texture and display it on screen. – Manos Dec 15 '17 at 15:47
  • Went a bit too far on the "minimal" side of things, that won't compile as-is: no `#include`s, no `CustomViewGL` declaration, missing `wall.jpg`. – genpfault Dec 15 '17 at 17:10
  • Slightly off topic, but... you really should be calling [glGetError](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGetError.xhtml) once in a while. – G.M. Dec 15 '17 at 17:17
  • @genpfault Honestly, I 've been over this for more than 8 hours straight. #include just includes the header of the class, there is nothing else special declared than the functions. wall.jpg can be any image. I conclude that QOpenGLWidget has some weird functionality. 1) you don't control when the buffer is changed and 2) i managed to load a texture but either i had to activate GL_TEXTURE1 (!) or bind it in paintGL everytime. Anyway, I switched to QGLWidget, which the official site says to avoid, I used setAutoBufferSwap(false) and now I control the swap and everything seems to work. – Manos Dec 15 '17 at 17:38

1 Answers1

0

Regarding QOpenGLWidget, as I have written in my comment on the question, the first behavior that I did not like is that the there is not a buffer swap function. Qt arbitrarily decides when to draw stuff, as stated in this question as well, which is something I definitely do not want. Secondly, although I would bind the texture and set the texture data, it would not appear on the screen unless a) bind it every time in the paintGL function or b) call glActiveTexture(GL_TEXTURE1) after binding and setting TEXTURE0 data, which is at least strange.

So I decided to switch to QGLWidget, which the official Qt documentation recommends to avoid. QGLWidget provides the freedom to disable auto swap buffer, has swap buffer function and was working properly with the code mentioned in the question (which, itself, was a direct copy from a working GLFW based implementation).

In order to disable auto buffer swap, choose OpenGL version, set anti aliasing and set shared context, the code below is used as the constructor:

CustomViewGL::CustomViewGL(QWidget *parent, const QGLWidget *shareWidget):
    QGLWidget(parent, shareWidget) // QGLWidget accepts as a second
{                                  // constructor argument another QGLWidget
    QGLFormat format;              // thus context sharing between this and
                                   // the shareWidget is created

    format.setVersion(3,3); // Set OpenGL version, here 3.3
    format.setProfile(QGLFormat::CoreProfile); // Core Profile
    format.setSamples(16); // Anti Alliasing

    setFormat(format);

    setAutoBufferSwap(false); // Prevents Qt from drawing whenever it wants
}

The header file decleration of the constructor is:

CustomViewGL(QWidget *parent = 0, const QGLWidget *shareWidget = 0);

Then implement protected function initializeGL() and enter the initialization code and you are ready to go.

Manos
  • 143
  • 9