Create your own game
eng   рус

OpenGL First Program in Windows

Next tutorial: Rendering pipeline in OpenGL

In this tutorial we'll learn everything needed to run a program in C/C++ using OpenGL in Windows OS. Attached projects are made in Visual Studio 2019. In the tutorial, we'll examine full initialization of OpenGL.

I took list of libraries from OpenGL wiki. For the tutorial I've choosen the simplest options to setup.

First Program in OpenGL 4.6

We'll work with OpenGL 4.6. This version was released quite ago (July 2017). So, you shouldn't have problems with it. But, just in case, download new drivers for your video graphics card. AMD and NVidia drivers that support 4.6 were released in 2018. Hardware support is available since AMD Radeon HD 5000 (2009) and NVidia GeForce (2010). Intel drivers for integrated adapters were released in 2019. If your video card doesn't support 4th version of OpenGL, then I recommend you to look at Mesa3D - it's a software implementation of OpenGL.

As OpenGL is a cross-platform API, it means there is no standard way to initialize it. Initialization of OpenGL requires two steps: create OpenGL context and load OpenGL API functions. For each of these steps, there are different libraries.

We'll start with loading OpenGL functions.

How to load OpenGL API functions

There are many different functions in OpenGL specification. For example, the first function that we'll use is glGenVertexArrays. Our program needs to know about it. To achieve this we'll use one of the libraries: GLEW or glatter.

In OpenGL specification name of functions look like this: GenVertexArrays, BindVertexArray, BeginQuery. But in real code you need to add prefix gl to these names (it depends on the library, in some, it's not so): glGenVertexArrays, glBindVertexArray, glBeginQuery, glUseProgram.

GLEW (OpenGL Extension Wrangler)

Download GLEW (first file for Windows, now it's Unpack it in any folder. In project settings add include and lib (lib\release\x64) folders. Copy file glew32.dll from folder bin\Release\x64 to your project folder.

All my libraries are located in the folder C:\prog\libs, so, my path to GLEW is C:\prog\libs\glew-2.1.0. Project settings in Visual Studio you can open through menu Project → Properties or through the context menu of a project in Solution Explorer.

You need to call function glewInit after context creation (we'll talk about it below) in your code. Here is all code related to GLEW:

#include <GL/glew.h> // include header file #pragma comment( lib, "glew32.lib" ) // load static library // Don't forget to copy dll in the folder with your project int main(int argc, char* argv[]) { // create OpenGL context glewInit(); }

We can use OpenGL functions after glewInit call.


Second option is glatter. Download and unpack it. If you didn't used github before, go to the page, click green button Clone or Download (right side) → Download Zip. After it's unpackedd, add include folder to your project:

In your code you need just include the header file and after that, you can call OpenGL functions. You don't need to initialize anything (but before calling OpenGL functions you need to create OpenGL context):

#include <glatter/glatter.h>

Other Libraries for Loading OpenGL API

There are many different other libraries for loading OpenGL functions, but they require more work than GLEW or glatter. Some of these libraries:: GL3W (uses Python script for generating OpengGL header files), glLoadGen (Uses Lua script), Galogen (command-line utility), Glad (application in Python or web page). There are more dependencies in these libraries than in GLEW/glatter.

Apart from this, you can manually load OpenGL functions. In Windows, you need to use function wglGetProcAddress. It accepts one argument - the name of OpenGL function we want to load (char*), it returns the address of the requested function. Using wglGetProcAddress you'll need to load each OpenGL function you are using in the program. wglGetProcAddress is declared in wingdi.h, and to use it you need to add Opengl32.lib and Opengl32.dll libraries. We'll not use this way in following tutorials.

Now let's see how to create OpenGL Context.

How to create OpenGL Context

What exactly is OpenGL context we'll discuss in the next tutorial. Now we only need to know that this context is bound to a window. In different operating systems windows are created in different ways and it means OpenGL context can be created differently too. There is no information about how to create OpenGL context in the specification. There are different libraries that solve this problem. We'll discuss freeglut, SDL2 and GLFW. These libraries manage window creation, OpenGL context creation, swapping buffers and managing event queue.

Important note: you need to choose Console App (or even better - Empty Project) for your Visual Studio Project. All libraries that we'll discuss use console apps and they create windows on their own. Also, you need to use this form of main:

int main(int argc, char* argv[]) { }

freeglut requires parameters arc and argv, SDL2 requires exactly that version of main. For GLFW main parameters are not important.

Also pay attention when glewInit is called (always after context creation).

In all cases you need to add OpenGL32.lib library. It defines the oldest OpenGL functions (from first version), like: glClear, glClearColor. Architecture doesn't matter, you need to use the same file for both x86 or x64.

Programs for any library have same structure:

  • OpenGL initalization (context creation)
  • GLEW initialization (unless you are using glatter)
  • Main loop:
    • Checking events (keyboard/mouse buttons were pushed) in event queue
    • Clearing frame buffer (glClear, glClearColor)
    • Frame rendering (here we'll use OpenGL functions that were loaded with GLEW). We'll talk about this phase in next tutorial
    • Frame buffer swapping (showing current frame on the screen). There are two 2d images - back and front buffers. Front buffer - it's the image user sees on the screen. While user look at front buffer, the program draw next frame in back buffer. After new frame is rendered, we switch pointers of buffers and back buffer becomes front and vice versa. Now user sees new frame and the program can render new frame in back buffer.
  • Clearing resources


Download GLFW (Graphics Library Framework). Choose 64-bit Windows binaries under header Windows pre-compiled binaries. Unpack it. For me it's folder: C:\prog\libs\glfw-3.3.2.bin.WIN64. Header files are in the folder include, as usual, libraries are in lib-vc2019. Also, you need to copy glfw3.dll to your project folder.

Full code for first OpenGL program:

#include <GL/glew.h> #include <GLFW/glfw3.h> #pragma comment( lib, "glew32.lib" ) #pragma comment( lib, "glfw3.lib" ) #pragma comment (lib, "OpenGL32.lib") int width = 800; int height = 600; int main(int argc, char* argv[]) { glfwInit(); GLFWwindow* window = glfwCreateWindow(width, height, "OpenGL first program", nullptr, nullptr); glfwMakeContextCurrent(window); glewInit(); while (!glfwWindowShouldClose(window)) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; }

In the program with GLFW we are using these functions: glfwInit, glfwCreateWindow, glfwMakeContextCurrent, glfwWindowShouldClose, glfwGetKey, glfwSetWindowShouldClose, glfwSwapBuffers, glfwPollEvents, glfwTerminate.

First, there is an initialization of GLFW, then window creation and after that new OpenGL context is created bound to the window. We pass window width/height and title to glfwCreateWindow (other arguments doesn't interesting). After that, it's time to initialize GLEW.

In the main loop we check if button Escape was pushed and if it was, we set a close flag (we check this flag in the condition of the main loop with glfwWindowShouldClose). Pay attention that GLFW defines own constants to manage input (GLFW_KEY_ESCAPE, GLFW_PRESS), their names are self-explanatory.

Then in main loop we clear frame buffer, render a frame and check event queue.

After the main loop we need to clear resources so we call glfwTerminate.

glClearColor sets the color that will be used during the clearing of the buffer (it's 2d image to which we render 3d scene). glClear clears the buffer. Here we clear only the color by passing GL_COLOR_BUFFER_BIT flag. Also, we can clear depth buffer, but we'll talk about it later.

glfwSwapBuffers shows the content on the screen. We achieve this with the function glfwSwapBuffers. Other libraries have similar function.


SDL (Simple DirectMedia Layer) library can work with 2d graphics and sound apart from OpenGL.

Go to download page. Under the header Development Libraries choose file Then unpack and setup project folders.

#include <GL/glew.h> #include <SDL.h> #pragma comment( lib, "glew32.lib") #pragma comment( lib, "SDL2.lib") #pragma comment( lib, "SDL2main.lib") #pragma comment( lib, "OpenGL32.lib") int width = 800; int height = 600; int main(int argc, char* argv[]) { SDL_Init(SDL_INIT_EVERYTHING); SDL_Window* window = SDL_CreateWindow("OpenGL first program", 100, 100, width, height, SDL_WINDOW_OPENGL); SDL_GLContext context = SDL_GL_CreateContext(window); glewInit(); bool quit = false; SDL_Event e; while (!quit) { while (SDL_PollEvent(&e) != 0) { if (e.type == SDL_QUIT) { quit = true; } } glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); SDL_GL_SwapWindow(window); } SDL_GL_DeleteContext(context); SDL_DestroyWindow(window); SDL_Quit(); return 0; }

In SDL2 we use these functions: SDL_Init, SDL_CreateWindow, SDL_GL_CreateContext, SDL_PollEvent, SDL_GL_SwapWindow, SDL_GL_DeleteContext, SDL_DestroyWindow, SDL_Quit. First, we initialize SDL2 using flag SDL_INIT_EVERYTHING. This flag initializes all SDL parts: graphics, sound, timers, input devices. In our case, we could use only SDL_INIT_VIDEO flag. After that, we create window and OpenGL context.

In the main loop we check event queue (SDL_PollEvent), clear buffer and show it's content by swapping buffers (SDL_GL_SwapWindow).

If event SDL_QUIT happened we terminate loop by changing variable quit, then we destroy context, window and free all resources.


I put information about freeglut (The Open-Source OpenGL Utility Toolkit) in this tutorial as there was a freeglut tutorial I wrote several years ago. At this moment I recommend using GLFW or SDL2. freeglut suits more for Linux.

FreeGLUT is based on the library GLUT, which was created in 1994 (and GLUT is obsolete for 20 years now).

Go to this page and look there for "Download freeglut 3.0.0 for MSVC" under the header freeglut 3.0.0 MSVC Package. Unpack and setup folders in your Visual Studio project. Also you need to copy freeglut.dll into the project folder.

#include <GL/glew.h> #include <GL/freeglut.h> #pragma comment( lib, "glew32.lib" ) #pragma comment( lib, "freeglut.lib" ) #pragma comment (lib, "OpenGL32.lib") int width = 640; int height = 480; void displayFunc(void); int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitWindowSize(width, height); int id = glutCreateWindow("OpenGL first program"); glewInit(); glutDisplayFunc(displayFunc); glutMainLoop(); exit(0); } void displayFunc(void) { glClearColor(0.5f, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glutSwapBuffers(); }

We are using these freeglut functions: glutInit, glutInitWindowSize, glutCreateWindow, glutDisplayFunc, glutMainLoop, glutSwapBuffers. Similar to other libraries: freeglut initialization, window creation with specific width/height. Pay attention that we set the function that will be called each frame (displayFunc). Then there is the main loop. In each frame, we clear the buffer and show it on the screen with glutSwapBuffers.


There three projects in the attached solution for Visual Studio 2019 for each library: GLFW, SDL, freeglut. They all use GLEW. These projects contain all needed files: header files and libraries (they are in project folders). In the next tutorials you need to set up folders by yourself (just follow steps from this tutorial). I will try to provide code for GLFW/SDL2 with GLEW.

I would like to put in this tutorial information about how to create OpenGL program in VSCode and Linux, but not sure if it's needed to anyone and writing tutorial takes much time. Maybe someday...

Now when you have the base of the program, you can check OpenGL version with function glGetString:

const GLubyte* version = glGetString(GL_VERSION);

You can check the value of variable version in the debugger or typecast it and output in console (don't forget that all programs GLFW, SDl2 and freeglut have a console).

As usual, I didn't put in this tutorial checking of return values. If you have problems, write in comments (it will allow me to improve this tutorial), I will answer asap.


Aug. 19, 2020, 6:10 p.m.
2 Guest
Hello there! I could have sworn I've been to your blog before but after going through a few of the articles I realized it's new to me. Regardless, I'm definitely happy I came across it and I'll be bookmarking it and checking back regularly! maillot de bayern munich
Aug. 19, 2020, 5:57 p.m.
1 Guest
great post, very informative. I'm wondering why the other specialists of this sector do not notice this. You must proceed your writing. I am confident, you've a huge readers' base already! liverpool fotbollströjor
Sept. 26, 2020, 10:50 p.m.
3 Guest
Hey just wanted to give you a quick heads up. The text in your article seem to be running off the screen in Safari. I'm not sure if this is a format issue or something to do with internet browser compatibility but I figured I'd post to let you know. The design and style look great though! Hope you get the issue resolved soon. Kudos Koszulka Roma
Sept. 27, 2020, 1:44 p.m.
4 Guest
What a data of un-ambiguity and preserveness of precious familiarity regarding unpredicted emotions. Koszulka Inter Mediolan
Sept. 27, 2020, 10:30 p.m.
5 Guest
I'm not sure exactly why but this web site is loading extremely slow for me. Is anyone else having this issue or is it a issue on my end? I'll check back later on and see if the problem still exists. voetbaltenue
Sept. 28, 2020, 7:57 p.m.
6 Guest
Greetings! I've been following your weblog for a long time now and finally got the courage to go ahead and give you a shout out from Humble Tx! Just wanted to say keep up the excellent work! Achetez dès maintenant le nouveau Maillot Monaco 2020/2021