- Published on
OpenGL Made Easy - 2
- Authors
- Name
- Kaan
Welcome back!
I see that you are back on track. It's nice that you have the motivation to learn OpenGL.
Here’s a reminder, if you don't know: if you really want to learn OpenGL, practice, practice, and practice!
What do I mean by practice?
You should be able to put what you learned into your code (memorizing functions isn't expected, just know how they work) and create your own programs with them.
So what will we learn in this tutorial? We will create a window!
Creating a window is not the "Hello World" of OpenGL. It's actually drawing a triangle.
But since OpenGL is too hard, you can think of it as part of "Hello World".
Also, I really suggest you to experiment. When we create a viewport, set up hints, or create a window in this tutorial, we will use some parameters by default only for the sake of this tutorial.
By entering your own parameters there, you may actually understand how things work.
Let's get started!
NOTE
You can write everything into your code in the order I explain it. But I'll give you the full code at the end of the tutorial!
Including libraries
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
CAUTION
You should include GLAD before GLFW. Why? Because GLFW uses OpenGL functions at some parts.
We include GLAD first so we can avoid using wrong headers.
Initializing GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); //OPTIONAL
Okay, let's break down everything!
glfwInit()
initializes its components.glfwWindowHint
sets specific options for our window, such as OpenGL version, OpenGL profile type, resizable setting, and more.- First parameter specifies which option we want to change or add.
- Second parameter is the value we want to assign.
GLFW_CONTEXT_VERSION_x
specifies the OpenGL version. Major sets x.3 and Minor sets 3.x.GLFW_OPENGL_PROFILE
sets up our profile mode.- You may ask "What's an OpenGL Profile?" It's a way to specify which features we want to use. We use Core since it's the modern option.
GLFW_RESIZABLE
sets whether we can resize our window. You may disable it for now.
By setting Major and Minor to 3, we say that we are using OpenGL 3.3.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
Creating Window
GLFWwindow* window = glfwCreateWindow(800, 600, "Hello World", NULL, NULL);
if (window == NULL)
{
std::cout << "Couldn't create the window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwCreateWindow
creates a window.- First two parameters specify the width and height.
- Third is the name of the window.
- Fourth is for full screen. We put
NULL
because we want windowed mode.- If you want to experiment with full screen, call
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
and write this variable instead of the NULL.
- If you want to experiment with full screen, call
- Fifth is not important for us right now.
glfwTerminate
closes everything if we fail.glfwMakeContextCurrent
tells GLFW "This is the window I'll use."
We check if the window creation is successful because finding errors in OpenGL is painful otherwise.
Initializing GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
NOTE
If you look at the code, you’ll notice we only used glfw
functions until now, not gl
.
By initializing GLAD, now we can start using OpenGL (gl
) functions!
I'll not waste your time: we just loaded our OpenGL functions.
Viewport
glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(window, resizeViewport);
void resizeViewport(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
glViewport
specifies the part of the window where we want to draw.- First and second parameters are the origin. (It's not important for now)
- Third and fourth parameters are width and height.
glfwSetFramebufferSizeCallback
says "When this window gets resized, run this function."
Imagine if resizing is enabled and a user changes the window size — without this callback, our render would stay the same size! By running a callback that adjusts the viewport size, we fix this.
Main Game Loop
while (!glfwWindowShouldClose(window))
{
processInput(window);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
void processInput(GLFWwindow *window)
{
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
Alright, now we have a running window.
Breaking it down:
glfwWindowShouldClose
checks if the window should close.processInput
checks for user input. (Our own function)
IMPORTANT
Always process input before drawing!
glfwSwapBuffers
swaps the back and front buffers.- Example: We have a program that draws red, green, and blue-colored triangles in order. We just drew the red one and are about to draw the green one. But when we run the draw function, we won’t see the new triangle instantly. It’s actually stored behind the old triangle. By running swap buffers, we swap the old triangle with the new one!
glfwPollEvents
checks for events like keyboard and mouse.glfwTerminate
frees memory when we're done.
Setting background color
Also let's setup the background color!
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor
tells OpenGL "Use this color next time you clear."- Parameters are like RGB but from 0 to 1, not 0 to 255. Also we have Alpha, which is between 1 and 0.
- I was actually using my own function that can convert by doing
(value / 255.0)
, which mathematically converts the value to be between 0 and 1. You might want to try something like that. f
after numbers tells C++ that it's a float.
glClear
means "Now, paint the screen with the color we set."
GL_COLOR_BUFFER_BIT
means we want to clear the screen color.
Full Code
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
void processInput(GLFWwindow *window);
void resizeViewport(GLFWwindow* window, int width, int height);
int main(){
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
//glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); //OPTIONAL
GLFWwindow* window = glfwCreateWindow(800, 600, "Hello World", NULL, NULL);
if (window == NULL)
{
std::cout << "Couldn't create the window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glViewport(0, 0, 800, 600);
glfwSetFramebufferSizeCallback(window, resizeViewport);
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
void resizeViewport(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow *window)
{
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}

End of this tutorial
The next tutorial will be tough for us!
Please let me know your thoughts and recommendations!