Инициализация OpenGL в Windows
Сегодня мы узнаем всё (реально всё), что нужно, чтобы запустить программу на C/C++, использующую OpenGL на Windows. Прикреплённые проекты сделаны в Visual Studio 2019. В уроке мы рассмотрим полную инициализацию OpenGL.
Список библиотек я брал из вики для OpenGL. Для урока я выбрал наиболее простые варианты в настройке.

Версия 4.6, которую мы будем рассматривать вышла довольно давно (июль 2017). Поэтому, у вас не должно возникнуть проблем, но, на всякий случай, установите последнюю версию драйверов. Драйвера, поддерживающие OpenGL 4.6, для видеокарт AMD и NVidia вышли в 2018. Аппаратная поддержка доступна начиная c AMD Radeon HD 5000 (2009г.) и NVidia GeForce 400 (2010г.). Драйвера для встроенных адаптеров Intel вышли в первой половине 2019г. В случае, если ваша видеокарта не поддерживает четвёртую версию OpenGL, рекомендую обратить внимание на Mesa3D - это программная реализация OpenGL.
Так как OpenGL является кроссплатформенным API, то не существует стандартного способа инициализации. Для использования OpenGL в программе необходимо сделать две вещи: создать OpenGL контекст и загрузить функции OpenGL API. Для каждой из этих задач существуют разные библиотеки.
Начнём мы с загрузки OpenGL функций.
Загрузка функций OpenGL API
В спецификации OpenGL описываются множество разных функций. Например, самая первая OpenGL функция, которую мы будем использовать: glGenVertexArrays. Необходимо чтобы наша программа узнала, что такая функция существует. Для этого мы будем использовать одну из библиотек: GLEW или glatter.
В спецификации имена OpenGL функций выглядят так: GenVertexArrays, BindVertexArray, BeginQuery. В реальном коде к этим именам нужно добавлять префикс gl (зависит от библиотеки, в некоторых это не так): glGenVertexArrays, glBindVertexArray, glBeginQuery, glUseProgram.
GLEW (OpenGL Extension Wrangler)
Скачиваем GLEW (первый файл для Windows, на данный момент это glew-2.1.0-win32.zip). Распаковываем в любую папку. В настройках проекта добавляем папку include и lib (lib\Release\x64). Из папки bin\Release\x64 копируем файл glew32.dll в папку с нашим проектом.
У меня все библиотеки лежат в папке: C:\prog\libs, соотвественно, путь к glew: C:\prog\libs\glew-2.1.0. Свойства проекта в Visual Studio открываются через пункт меню Проект → Свойства (Project → Properties) или через контекстное меню проекта в обозревателе решений.

В коде после создание контекста (об этом ниже) нужно вызвать функцию glewInit. Вот весь код, касающийся GLEW:
После вызова glewInit мы можем пользоваться функциями OpenGL.
По поводу имени библиотеки GLEW. GLEW расшифровывается как OpenGL Extension Wrangler. Wrangler - пастух. Соотвественно, название библиотеки можно понимать как: тот, кто управляет расширенями OpenGL. Про расширения мы будем говрить позже.
glatter
Второй вариант - glatter. Скачиваем и распаковываем. Если вы не пользовались github, то проходите по ссылке, нажимайте зелёную кнопку Clone or download (справа) → Download Zip. После разархивирования, добавляем папку include к проекту:

Теперь в коде осталось только включить заголовочный файл и можно вызывать OpenGL функции. Инициализировать ничего не надо (вызов функций можно делать только после создания OpenGL контекста):
Я не смог найти значение названия библиотеки glatter. Автор из Германии и там это слово есть - одна из форм слова "блестящий".
Другие библиотеки для загрузки OpenGL API
Существуют и другие библиотеки для загрузки OpenGL функций, но они требуют больше действий чем GLEW или glatter. Некоторые из этих вариантов: GL3W (использует скрипт на Python для генерациий заголовочных файлов OpenGL), glLoadGen (использует Lua скрипт), Galogen (командная утилита), Glad (приложение на Python или веб страница). В этих библиотеках используются дополнительные зависимости.
Кроме того, вы можете самостоятельно загрузить OpenGL функции, не используя вышеперечисленные библиотеки. В Windows для этого используется функция wglGetProcAddress. В качестве аргумента мы передаём имя функции (в виде строки char*), которую мы хотим получить, а возвращает она, соответственно, адрес этой функции. При таком способе вам нужно будет самостоятельно загружать каждую OpenGL функцию. wglGetProcAddress объявлена в wingdi.h, а для её использования необходимо подключить библиотеки Opengl32.lib, Opengl32.dll. Это информация для общего развития, в дальнейших уроках мы будем пользоваться только GLEW или glatter.
Теперь мы переходим к созданию контекста OpenGL.
Создание OpenGL контекста
Что такое OpenGL контекст мы поговорим в следующем уроке. Сейчас нам важно, что OpenGL контекст привязывается к окну. Так как OpenGL - кросплатформенная API, а в разных операционных системах окна создаются совершенно по-разному, это означает, что и создание контекста происходит по-разному. В спецификации OpenGL ничего не сказано, как создавать контекст. Существуют разные библиотеки для решения этой задачи. Мы рассмотрим freeglut, SDL2 и GLFW. Эти библиотеки отвечают за создание окна, OpenGL контекста, смену кадров, очередь сообщений.
Важно: При создании проекта для любой библиотеки выбирайте консольное приложение. Все библиотеки используют консольное приложение и самостоятельно создают окна. При этом, мы будем использовать следующую форму main:
freeglut требует аргументы arc и argv, а SDL2 требует именно этот вариант main. Для GLFW аргументы main не имеют значения.
Также, обратите внимание, в какой момент вызывается glewInit (после создания контекста).
Ещё одна ремарка: во всех случаях необходимо подключить библиотеку OpenGL32.lib. В ней определены самые старые функции OpenGL (ещё с первой версии), такие как, glClear, glClearColor. Архиктура не имеет значения, x86 и x64 должны использовать один и тот же файл.
Приложения на всех библиотеках имеют одинаковую структуру:
- Инициализация OpenGL
- Инициализация GLEW
- Главный цикл:
- Проверка событий (нажатие клавиш клавиатуры/мышки...) в очереди
- Очистка буфера кадра (glClear, glClearColor)
- Рендеринг кадра (именно здесь будут использоваться функции OpenGL, загруженные с помощью GLEW). В этом уроке этого не будет
- Смена кадров (вывод буфера на экран). У нас есть две 2д картинки - фоновый буфер и основной. Основной буфер - это то, что пользователь видит на экране. Пока пользователь смотрит на основной буфер, мы рисуем в фоновом следующий кадр. Кода мы отрисовали кадр, мы меняем указатели буферов местами: фоновый становится основным и наоборот. Теперь пользователь видит новый кадр, а мы можем рисовать новый в фоновом буфере
- Освобождение ресурсов
GLFW
Скачиваем GLFW (Graphics Library Framework). Под заголовком Windows pre-compiled binaries выбираем 64-bit Windows binaries. Распаковываем. У меня это папка C:\prog\libs\glfw-3.3.2.bin.WIN64. Заголовочные файлы, как обычно в папке include, а библиотеки в lib-vc2019. Нужно скопировать glfw3.dll в папку с вашим проектом.

Теперь полный код:
В программе с GLFW мы используем следующие функции: glfwInit, glfwCreateWindow, glfwMakeContextCurrent, glfwWindowShouldClose, glfwGetKey, glfwSetWindowShouldClose, glfwSwapBuffers, glfwPollEvents, glfwTerminate.
Сначала инициализируем GLFW, создаём окно и присваиваем ему контекст. При создании окна с помощью glfwCreateWindow мы указываем ширину/высоту окна и заголовок, остальные аргументы не важны. Затем инициализируем GLEW.
В основном цикле мы проверяем, была ли нажата клавиша Escape, и если да, то устанавливливаем закрывающий флаг (его мы проверяем в условии цикла с помощью glfwWindowShouldClose). Обратите внимание, что для управления вводом GLFW определяет свои константы (GLFW_KEY_ESCAPE, GLFW_PRESS), их имена говорят сами за себя.
Затем, в основном цикле мы очищаем буфер кадра, выводим содержимое на экран и проверяем события в очереди событий.
После окончания основного цикла мы вызываем glfwTerminate.
glClearColor задаёт цвет, которым будет заполняться фоновый буфер (это 2д картинка, в которой происходит рисование кадра) при очистке. glClear очищает фоновый буфер. Здесь мы очищаем только цвет - GL_COLOR_BUFFER_BIT. Ещё мы можем очищать буфер глубины, но об этом позже.
glfwSwapBuffers выводит содержимое на экран. Имя функции - swap buffers - поменять буферы местами. В других библиотеках тоже есть подобная функция.
SDL2
Библиотека SDL (Simple DirectMedia Layer), помимо OpenGL, имеет возможности для работы с 2д графикой и звуком.
Переходим. В разделе Development Libraries выбираем файл SDL2-devel-2.0.10-VC.zip. Распаковываем архив и настраиваем папки проекта.

В SDL2 мы используем следующие функции: SDL_Init, SDL_CreateWindow, SDL_GL_CreateContext, SDL_PollEvent, SDL_GL_SwapWindow, SDL_GL_DeleteContext, SDL_DestroyWindow, SDL_Quit. Сначала мы инициализируем SDL, используя флаг SDL_INIT_EVERYTHING (everything - всё), который говорит, что мы хотим инициализировать все системы SDL: графику, звук, таймеры, устройства ввода. В нашем случае можно обойтись только SDL_INIT_VIDEO. После этого мы создаём окно и OpenGL контекст.
В основном цикле мы проверяем очередь событий (SDL_PollEvent), очищаем буфер и выводим содержимое на экран с помощью смены кадров (SDL_GL_SwapWindow).
Если произошло событие SDL_QUIT, мы заканчиваем цикл, изменяя переменную quit, затем удаляем контекст, окно, и освобождаем все ресурсы.
freeglut
Я упоминаю здесь freeglut (The Open-Source OpenGL Utility Toolkit) только для соотстветсвия с английской версией урока, который я писал несколько лет назад. На данный момент рекомендую использовать GLFW или SDL. freeglut больше подходит для Linux.
FreeGLUT основывается на библиотеке GLUT, которая была создана в 1994г. (да и устарела GLUT уже как двадцать лет).
Проходим по Ссылке и ищем там "Download freeglut 3.0.0 for MSVC" в разделе freeglut 3.0.0 MSVC Package. После распаковки архива указываем в своём проекте пути к заголовчным файлам и библиотеке. Также, необходимо скопировать freeglut.dll в папку с проектом.

Здесь мы используем функции из freeglut: glutInit, glutInitWindowSize, glutCreateWindow, glutDisplayFunc, glutMainLoop, glutSwapBuffers. Собственно, инициализируем саму библиотеку, задаём размер окна и затем создаём его, указываем функцию, которая будет вызываться каждый кадр (displayFunc), запускаем основной цикл. В каждом кадре мы очищаем буфер и выводим содержимое буфера на экран с помощью glutSwapBuffers.
Заключение
В прикреплённом решении для Visual Studio 2019 есть три проекта для GLFW, SDL, freeglut. Везде используется GLEW. В данных проектах есть все нужные файлы: включаемые файлы и библиотеки, и они находятся в папках проектов. В следующих уроках вам нужно будет самостоятельно добавлять библиотеки. Я постраюсь поддерживать код для GLFW/SDL2 в связке с GLEW.
Я бы, конечно, хотел добавить проекты для VSCode и Linux, но не уверен, что это кому-нибудь нужно, а на проверку и написание уходит много времени.
Теперь, когда есть основа программы, версию OpenGL можно проверить с помощью функции glGetString:
Значение можно посмотреть в отладчике или привести тип и вывести в консоль (все приложения GLFW, SDl2 и freeglut - консольные).
За рамками урока, как обычно, осталась проверка возвращаемых значений разных функций. Если возникнут проблемы, пишите в комментарии (это позволит дополнить урок), отвечу, по возможности, быстро.