1
votes

Using OpenGL core profile, I'm trying to create a texture that fills the screen and displays a white square in the middle of the texture.

#include <SDL2/SDL.h>
#include "glad/glad.h"

#define SIMPLE_VERTEX_SHADER "#version 330 core \n \
layout (location = 0) in vec3 aPos; \n \
layout (location = 1) in vec2 aTexCoord; \n \
out vec2 TexCoord; \n \
void main() { \n \
    gl_Position = vec4(aPos, 1.0f); \n \
    TexCoord = vec2(aTexCoord.x, aTexCoord.y); \n \
}\n\0"

#define SIMPLE_FRAGMENT_SHADER "#version 330 core \n \
out vec4 FragColor; \n \
in vec3 ourColor; \n \
in vec2 TexCoord; \n \
uniform sampler2D tex; \n \
void main() { \n \
    FragColor = texture(tex, TexCoord); \n \
}\n\0"

int main(int argv, char** args) {
    SDL_Window *window;
    SDL_GLContext glcontext;

    if (SDL_Init(SDL_INIT_VIDEO)) {
        printf("Unable to initialise SDL: %s\n", SDL_GetError());
        SDL_Quit();
        exit(1);
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    int screen_width, screen_height;
    screen_height = screen_width = 500;

    window = SDL_CreateWindow("Texture Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screen_width, screen_height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    if (!window) {
        printf("Unable to create window: %s\n", SDL_GetError());
        SDL_Quit();
        exit(1);
    }

    glcontext = SDL_GL_CreateContext(window);

    SDL_GL_SetSwapInterval(1);


    if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress))
    {
        printf("Failed to initialize GLAD\n");
    }

    const GLchar* vertexShaderSource = SIMPLE_VERTEX_SHADER;

    GLuint vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);

    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
        printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
    }

    const GLchar* fragmentShaderSource = SIMPLE_FRAGMENT_SHADER;

    GLuint fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);

    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
    }

    GLuint shaderProgram;

    shaderProgram = glCreateProgram();

    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);

    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        printf("ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
    }

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    GLfloat vertices[] = {
            1.0f, 1.0f, 0.0f, 1.0, 0.0f,
            1.0f, -1.0f, 0.0f, 1.0, 1.0f,
            -1.0f, -1.0f, 0.0f, 0.0, 1.0f,
            -1.0f, 1.0f, 0.0f, 0.0, 0.0f
    };

    GLfloat indices[] = {
            0, 1, 3,
            1, 2, 3
    };

    bool running;
    running = true;
    GLuint VAO, VBO, EBO;
    SDL_Surface* surface;
    SDL_Event e;

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    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(GLfloat), (void*)0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(0);

    GLuint texture;

    glGenTextures(1, &texture);
    surface = SDL_CreateRGBSurface(0, screen_width, screen_height, 32, 0, 0, 0, 0);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    SDL_GL_SwapWindow(window);


    while(running) {
        while(SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT) {
                running = false;
            }
            if (e.type == SDL_KEYDOWN)
            {
                switch (e.key.keysym.sym)
                {
                    case SDLK_ESCAPE:
                        running = false;
                        break;
                    default:
                        break;
                }
            }
        }

        if (SDL_MUSTLOCK(surface)) {
            SDL_LockSurface(surface);
        }
        uint8_t* pixel_data = (uint8_t*)surface->pixels;
        for (int y = screen_height * 0.25; y < screen_height * 0.75; ++y) {
            for (int x = screen_width * 0.25; x < screen_width * 0.75; ++x) {
                pixel_data[4 * (y * surface -> w + x) + 0] = 0xFF;
                pixel_data[4 * (y * surface -> w + x) + 1] = 0xFF;
                pixel_data[4 * (y * surface -> w + x) + 2] = 0xFF;
                pixel_data[4 * (y * surface -> w + x) + 3] = 0xFF;
            }
        }
        if (SDL_MUSTLOCK(surface)) {
            SDL_UnlockSurface(surface);
        }

        glBindTexture(GL_TEXTURE_2D, texture);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glBindTexture(GL_TEXTURE_2D, 0);

        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shaderProgram);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);
        glUniform1i(glGetUniformLocation(shaderProgram, "tex"), 0);

        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        glUseProgram(0);

        SDL_GL_SwapWindow(window) ;
    }

    SDL_GL_DeleteContext(glcontext);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

It displays a white screen when it opens (as though I set the clear colour to white), and then it changes to a black screen almost immediately, and then stays like that.

I'm clearly doing something wrong, but I cannot work out. I get the feeling that my shaders are the problem. But I don't know for sure.

Is someone able to give me a pointer on what I'm doing wrong?

Thanks.

2
What does your program display? - HolyBlackCat
It displays a white screen when it opens (as though I set the clear colour to white), and then it changes to a black screen almost immediately, and then stays like that. - user2167177
@user2167177 your indices defined as GLfloat but draw says they are GL_UNSIGNED_INT. Bitmasks for surface creation are also wrong, I'm not sure it is guaranteed to work. - keltar
@keltar You are a superstar. Changing my indices to a GLuint fixed it. If you want to write an answer to that effect, I'll give you a big ol' answered. - user2167177

2 Answers

0
votes

Indices defined as

GLfloat indices[] = {
        0, 1, 3,
        1, 2, 3
};

However, indices must be integer. Later when drawing it is said indices are GLuint:

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

And float bits are interpreted as uint, giving invalid values like 1065353216, 1077936128, ..., which greatly exceeds vertex buffer size.

Define indices as GLuint (or uint32_t).

0
votes

I am adding an answer based on keltar's answer in the comment to take this question out of the unanswered tab. If keltar answers I will delete my answer.

The issue is that the vertex attributes are qualified as floats in the lines:

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

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
glEnableVertexAttribArray(1);

But the texture is expecting unsigned bytes:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);

So changing the vertex attributes fixes the problem.