5/14

4.1. Display a triangle

The next step consists in using OpenGL functions to display a 3D shape in the window. We will consider in this example a minimalistic static triangle with uniform color.

OpenGL programs can generally be viewed as three steps

  • Initialization step

    • Setting the shader programs (1)

    • Sending data to GPU (2)

  • Displaying data (3)

The two steps from the initialization part can be performed in any order, while the display is usually performed in the animation loop and requires the two previous steps.


The full code of the function is provided below for your information only (you don’t need to download it now), each new part of this code will be explained in the next subparts of the tutorial.

triangle

[ code, main.cpp ]

#include <glad/glad.hpp>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>



int main()
{
    std::cout<<"*** Init GLFW ***"<<std::endl;
    const int glfw_init_value = glfwInit();
    if( glfw_init_value != GLFW_TRUE ) {
        std::cerr<<"Failed to Init GLFW"<<std::endl;
        abort();
    }


    std::cout<<"*** Create window ***"<<std::endl;
    const int window_width  = 500;
    const int window_height = 500;
    const std::string title = "My Window";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
    GLFWwindow* window = glfwCreateWindow(window_width, window_height, title.c_str(), /*monitor*/ nullptr, /*share*/ nullptr);
    if( window==nullptr ) {
        std::cerr<<"Failed to create GLFW Window"<<std::endl;
        abort();
    }

    glfwMakeContextCurrent(window);

    std::cout<<"*** Init GLAD ***"<<std::endl;
    const int glad_init_value = gladLoadGL();
    if( glad_init_value == 0 ) {
        std::cerr<<"Failed to Init GLAD"<<std::endl;
        abort();
    }


    std::cout<<"OpenGL information: VENDOR      : "<<glGetString(GL_VENDOR)<<std::endl;
    std::cout<<"                    RENDERDER   : "<<glGetString(GL_RENDERER)<<std::endl;
    std::cout<<"                    VERSION     : "<<glGetString(GL_VERSION)<<std::endl;
    std::cout<<"                    GLSL VERSION: "<<glGetString(GL_SHADING_LANGUAGE_VERSION)<<std::endl;



    // ************************************************* //
    //             1 - Setup Shaders                     //
    // ************************************************* //

    std::cout<<"*** Setup Shader ***"<<std::endl;

    // ******************************** //
    // 1.1 Define vertex and fragment shader
    // ******************************** //

    const char* vertex_shader_txt = "                                      \n \
            #version 330 core                                              \n \
            layout (location = 0) in vec4 position;                        \n \
            void main()                                                    \n \
            {                                                              \n \
                gl_Position = position;                                    \n \
            }";
    const char* fragment_shader_txt = "                                    \n \
            #version 330 core                                              \n \
            out vec4 FragColor;                                            \n \
            void main()                                                    \n \
            {                                                              \n \
                FragColor = vec4(1.0, 0.0, 0.0, 1.0);                      \n \
            }";



    // ******************************** //
    // 1.2 Create shader program
    // ******************************** //

    // (Warning: the following code doesn't perform error checking)

    //  A. Compile each shader separately
    // ******************************************* //

    const GLuint vertex_shader   = glCreateShader(GL_VERTEX_SHADER);
    const GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);

    glShaderSource(vertex_shader, 1, &vertex_shader_txt, nullptr);
    glCompileShader(vertex_shader);

    glShaderSource(fragment_shader, 1, &fragment_shader_txt, nullptr);
    glCompileShader(fragment_shader);

    //  B. Link shaders into shader program
    // ******************************************* //

    const GLuint shader = glCreateProgram();
    glAttachShader(shader, vertex_shader);
    glAttachShader(shader, fragment_shader);
    glLinkProgram(shader);

    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);


    // ************************************************* //
    //           2 - Sending data to GPU                 //
    // ************************************************* //

    std::cout<<"*** Setup Data ***"<<std::endl;

    // 2.1 Setup contiguous array of floating point value
    // ******************************************* //
    const std::vector<GLfloat> position = {
        -0.5f, -0.5f, 0.0f,
         0.5f, -0.5f, 0.0f,
         0.0f,  0.5f, 0.0f
    };

    // 2.2 Create VBO - Send data to GPU
    // ******************************************* //

    GLuint vbo = 0;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, position.size()*sizeof(GLfloat), &position[0], GL_STATIC_DRAW );
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // 2.3 Create VAO - Relation between VBO organization and input variables of shaders
    // ******************************************* //
    GLuint vao = 0;
    glGenVertexArrays(1,&vao);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, nullptr );
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);






    // ******************************** //
    // Main loop
    // ******************************** //

    std::cout<<"*** Start GLFW loop ***"<<std::endl;
    while( !glfwWindowShouldClose(window) ) {

        // ************************************************* //
        //           3 - Displaying Data                     //
        // ************************************************* //

        glUseProgram(shader);             // Activate shader program
        glBindVertexArray(vao);           // Activate attributes for the drawing
        glDrawArrays(GL_TRIANGLES, 0, 3); // Draw 3 vertices
        glBindVertexArray(0);
        glUseProgram(0);


        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    std::cout<<"*** Terminate GLFW loop ***"<<std::endl;


    glfwTerminate();

    return 0;
}