Initialize a Window and OpenGL

Creating a Window

The first essential step of a graphics program is to be able to display a window in which the visual results can be displayed.
This step is, to a large extent, independent of the approach put in place to achieve the graphic rendering. However, the window must be able to interact and synchronize with the graphics API used (in our case, it will be a OpenGL context).

Creating a window from scratch is a complex operation heavily depending on the operating system. In most case, we use external cross-platform libraries to handle this step.
In our case, we will use the library GLFW. GLFW is a lightweight C library able to create window compatible with an OpenGL context. GLFW can also handle user events such as the use of the keyboard and mouse.

Rem: The process to install GLFW depends on your system.

> Download, compile and execute the following code [ create_window.zip ]


Comments on code
// Include for GLFW headers - library handling the window
#include <GLFW/glfw3.h>
#include <iostream>

int main()
{
    // Initialize GLFW
    //  This step is required before creating the window
    glfwInit();

    // Create a new Window of size 500x500 with title "My Window"
    // The two last parameters are
    //   - the monitor for full screen mode (or nullptr for windowed mode in this case)
    //   - another pointer to a window in the case where ressources are shared (or nullptr to not share ressources).
    // The function returns a pointer to the newly created window (or nullptr in case of error).
    GLFWwindow* window = glfwCreateWindow(500, 500, "My Window", nullptr, nullptr);

    if( window==nullptr ) {
        std::cerr<<"GLFW Failed to create a Window"<<std::endl;
        glfwTerminate();
        exit(1);
    }

    // User defined loop
    // This loop will be active until the user close the window
    while( !glfwWindowShouldClose(window) ) {
        glfwSwapBuffers(window); // Double buffering (will be used to avoid flickering when animating a scene)
        glfwPollEvents();        // Handle GLFW events (ex. mouse clicks, etc)
    }

    glfwTerminate(); // Close the GLFW Window

    return 0;
}


Windows and OpenGL

Introduction to OpenGL

In the following, we will draw inside this window through the use of OpenGL.

OpenGL is a set of standardized functions (called an API) which allows to implement in a very efficient and generic way the "graphics rendering pipeline". More precisely, OpenGL consists of a set of functionalities allowing to communicate directly with the graphics card (GPU - Graphics Processing Unit), thus offering an optimal approach to display 3D data in real time.

Rem. OpenGL is not a "code library", it is only a standard for calling functions and types. The actual implementation of these functions depends on your system, your graphics card, and the driver you have installed. OpenGL calls are said to be "low level": They allow direct communication with your graphics card very efficient, but require a significant work of setting up.

Programm using OpenGL

> Download, compile and execute the following code: [ create_window_opengl_context.zip ].
#include "../external/glad/include/glad/glad.hpp" // glad.h should be included before glfw or any OpenGL related include

#include <GLFW/glfw3.h>
#include <iostream>
#include <cmath>

int main()
{
    glfwInit();

    // Indicate to GLFW to setup context compatible with OpenGL 3.3 core profile
    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(500, 500, "My Window", nullptr, nullptr);

    if( window==nullptr ) {
        std::cerr<<"GLFW Failed to create a Window"<<std::endl;
        glfwTerminate();
        exit(1);
    }

    // Enable the window to handle OpenGL Context
    glfwMakeContextCurrent(window);

    // Load OpenGL Functions
    gladLoadGL();

    // Print OpenGL Information
    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;

    while( !glfwWindowShouldClose(window) ) {
        
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

In a classic OpenGL scene, containing an animation or a user interaction, the display of the image is refreshed several times per second. This regular display request is made by the loop contained in the instruction.

while( !glfwWindowShouldClose(window) ){ ... }

This loop is thus executed as long as the user does not close the window. At each iteration of this loop, it is common practice to completely erase the screen to redisplay the scene in its entirety. To obtain a smooth animation impression, each new frame must be recalculated in, at most, 40ms (or 25 frames per second - fps).

Modify the loop code as follows

while( !glfwWindowShouldClose(window) ) {

    // Set the (R,G,B,A) color to clear the screen
    glClearColor(1.0f, 1.0f, 0.5f, 1.0f);
    // Clear the screen (designated by the color buffer)
    glClear(GL_COLOR_BUFFER_BIT);


    glfwSwapBuffers(window);
    glfwPollEvents();
}

Check that the window is now displayed in yellow.


Explanation



Rem. The glClearColor and glClear functions are OpenGL functions. We will find the same naming convention for all OpenGL functions and variables.:

Temporal modification

Now consider the following code for the animation loop:

int counter = 0;
while( !glfwWindowShouldClose(window) ) {

    counter = (counter+1)%100;
    float u = counter/99.0f;

    // Set the (R,G,B,A) color to clear the screen
    glClearColor(0.5+std::cos(2*3.14f*u)/2.0f, 1.0f, 0.5f, 1.0f);

    // Clear the screen (designated by the color buffer)
    glClear(GL_COLOR_BUFFER_BIT);

    glfwSwapBuffers(window);
    glfwPollEvents();
}

Note that you can experiment with other functions to get other color change effects.


Rem: Note the explicit syntax "counter/99.0f" and not "counter/99"