OpenGL not rendering anything after following tutorial

Viewed 113

I recently started following an OpenGL tutorial series by TheCherno on youtube.
Here is my code:

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

struct ShaderProgramSource {
    std::string VertexSource;
    std::string FragmentSource;
};

static ShaderProgramSource ParseShader(const std::string& filepath) {
    std::ifstream stream(filepath);

    enum class ShaderType {
        NONE = -1, VERTEX = 0, FRAGMENT = 1
    };

    std::string line;
    std::stringstream ss[2];
    ShaderType type = ShaderType::NONE;
    while (getline(stream, line)) {

        if (line.find("#shader") != std::string::npos) {

            if (line.find("vertex") != std::string::npos)
                type = ShaderType::VERTEX;
            else if (line.find("fragment") != std::string::npos)
                type = ShaderType::FRAGMENT;

        } else {
            ss[(int)type] << line << '\n';
        }
    }

    return { ss[0].str(), ss[1].str() };
}

static unsigned int CompileShader(unsigned int type, const std::string& source) {

    std::cout << "Compiling " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader..." << std::endl;

    unsigned int id = glCreateShader(type);
    const char* src = source.c_str();
    glShaderSource(id, 1, &src, nullptr);
    std::cout << glGetError() << std::endl;

    glCompileShader(id);
    std::cout << glGetError() << std::endl;

    int result;
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);
    std::cout << glGetError() << std::endl;

    if (result == GL_FALSE) {
        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
        std::cout << glGetError() << std::endl;

        char* message = (char*)alloca(length * sizeof(char));
        glGetShaderInfoLog(id, length, &length, message);
        std::cout << glGetError() << std::endl;

        std::cout << "Failed to compile" << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl;
        std::cout << message << std::endl;
        glDeleteShader(id);
        std::cout << glGetError() << std::endl;

        return 0;
    }

    std::cout << "Successfully compiled " << (type == GL_VERTEX_SHADER ? "vertex" : "fragment") << " shader!" << std::endl << std::endl;
    return id;
}

static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader) {

    std::cout << "Creating shader..." << std::endl << std::endl;
    
    unsigned int program = glCreateProgram();
    unsigned int vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
    unsigned int fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);

    glAttachShader(program, vs);
    std::cout << glGetError() << std::endl;
    std::cout << "Attached vertex shader" << std::endl;

    glAttachShader(program, fs);
    std::cout << glGetError() << std::endl;
    std::cout << "Attached fragment shader" << std::endl;

    glLinkProgram(program);
    std::cout << glGetError() << std::endl;
    glValidateProgram(program);
    std::cout << glGetError() << std::endl;
    std::cout << "Linked and validated program" << std::endl;

    glDeleteShader(vs);
    std::cout << glGetError() << std::endl;
    std::cout << "Deleted vertex shader" << std::endl;

    glDeleteShader(fs);
    std::cout << glGetError() << std::endl;
    std::cout << "Deleted fragment shader" << std::endl;

    std::cout << "Succesfully created shader!" << std::endl << std::endl;

    return program;
}

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    if (glewInit() != GLEW_OK) {
        std::cout << "Error!" << std::endl;
    }

    std::cout << glGetString(GL_VERSION) << std::endl;

    float positions[6] = {
        -0.5f, -0.5f,
         0.0f,  0.5f,
         0.5f, -0.5f
    };

    unsigned int buffer;
    glGenBuffers(1, &buffer);
    std::cout << glGetError() << std::endl;
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    std::cout << glGetError() << std::endl;
    glBufferData(GL_ARRAY_BUFFER, 6*sizeof(float), positions, GL_STATIC_DRAW);
    std::cout << glGetError() << std::endl;

    glDisableVertexAttribArray(0);
    std::cout << glGetError() << std::endl;
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float)*2, 0);
    std::cout << glGetError() << std::endl;

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    std::cout << glGetError() << std::endl;
    
    ShaderProgramSource source = ParseShader("res/shaders/Basic.shader");
    std::cout << "VERTEX" << std::endl;
    std::cout << source.VertexSource << std::endl;
    std::cout << "FRAGMENT" << std::endl;
    std::cout << source.FragmentSource << std::endl;

    //unsigned int shader = CreateShader(vertexShader, fragmentShader);
    ///glUseProgram(shader);


    
    // render loop
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        glDrawArrays(GL_TRIANGLES, 0, 3);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    //glDeleteProgram(shader);

    glfwTerminate();
    return 0;
}

Here's the Basic.shader file:

#shader vertex
#version 330 core  

layout(location = 0) in vec4 position;  

void main()  
{  
    gl_Position = position;  
}

#shader fragment
#version 330 core  

layout(location = 0) out vec4 color;  

void main()  
{  
    color = vec4(1.0, 0.0, 0.0, 1.0);  
}

I have tried using glGetError and it doesn't output any errors.

2 Answers

You need to enable the generic vertex attribute array instead of disabling it (see glEnableVertexAttribArray):

glDisableVertexAttribArray(0);

glEnableVertexAttribArray(0);

Furthermore, the code which compiles, linkes and installs the sahder is commented out:

//unsigned int shader = CreateShader(vertexShader, fragmentShader);
///glUseProgram(shader);

unsigned int shader = CreateShader(source.VertexSource, source.FragmentSource);
glUseProgram(shader);

I believe @Rabbid76's answer is correct. If it still does not work, make sure you are using compatible OpenGL context or create a VAO to hold the state.

Compatible OpenGL context can be set with:

//Before glfwCreateWindow call, after glfwInit
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);

The default value is GLFW_OPENGL_ANY_PROFILE and this could mean CORE if COMPAT is not available. This ensures that a default VAObject always exist and is bound. Meaning that your glVertexAttribPointer calls actually have a place to store that information. I did not see these Cherno's tutorials, it's quite possible that VAOs are covered in the future tutorials. In CORE there will not be one and it might not draw anything.

While we are here, it is not a bad idea to set minimal OpenGL version required precisely. If for some reason it is not available on the target machine, the window creation will fail. This is more preferable than getting "random" seg faults when calling unsupported functions.

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

My preferred way would be to create an actual VAO and go with GLFW_OPENGL_CORE_PROFILE. But feel free to go with tutorials, the ones I've seen from him are really high-quality.

//Put these before the vertex buffer initialization
int VAO;
glGenVertexArrays(1,&VAO);
glBindVertexArray(VAO);
Related