Установка и работа с Opengl + SFML
Существует довольно много библиотек, которые способны отображать окна для Opengl - SDL, Glut (freeglut), QT, SFML, можно даже использовать нативные API операционной системы (вроде Winapi для Windows). Но SFML имеет ряд важных преимуществ, это мультимедийная библиотека, представляющая из себя объектно ориентированный аналог SDL, что делает её гораздо удобнее последней, но при этом более многофункциональной чем, например, Glut. В частности, SFML имеет интерфейс для управления текстурами, тогда как при использовании glut пришлось бы подключать дополнительные библиотеки, такие как SOIL2. Помимо этого, у SFML очень хорошая и удобная документация на официальном сайте.
Установка
Установить SFML и Opengl можно разными способами, но удобно воспользоваться для этого пакетными менеджерами. Для работы в Visual Studio можно воспользоваться nuget, но мне для c++ проектов показался удобнее vcpkg, относительно недавно появившийся мультиплатформенный пакетный менеджер от Microsoft.
Установка vcpkg производится слегка необычным образом, для этого необходимо клонировать репозиторий vcpkg (желательно чтобы в путях установки не было кириллицы, иначе могут возникнуть проблемы)
git clone https://github.com/Microsoft/vcpkg.git
И затем вызвать скрипт загрузки
.\vcpkg\bootstrap-vcpkg.bat
После этого можно устанавливать библиотеки
vcpkg install sfml
vcpkg install opengl
vcpkg install glew
Установка занимает довольно продолжительное время
Чтобы установленные пакеты были видны из Visual Studio, надо написать следующее
vcpkg integrate install
Работа с SFML и OpenGL
Обратите внимание, что по умолчанию устанавливаются последние версии пакетов — в частности, пакет sfml версии 3, который требует C++17.
Простая программа на SFMl выглядит следующим образом
#include <SFML/Graphics.hpp>
int main()
{
// Создаём окно
sf::RenderWindow window(sf::VideoMode({ 200, 200 }), "SFML window");
// Главный цикл
while (window.isOpen())
{
// Цикл обработки событий
while (const std::optional event = window.pollEvent())
{
// Событие закрытия окна
if (event->is<sf::Event::Closed>())
window.close();
}
// Перерисовка окна
window.display();
}
return 0;
}
Здесь просто создаётся окно, и до тех пор, пока оно открыто, происходит перерисовка.
Теперь запустим простую программу для работы с OpenGL, которая выводит на экран окно с разноцветным крутящимся квадратом.
ВАЖНО!!! СЛЕДУЮЩИЙ КОД НАПИСАН С ИСПОЛЬЗОВАНИЕМ УСТАРЕВШЕГО API OPENGL И СЛУЖИТ ИСКЛЮЧИТЕЛЬНО ДЛЯ ПРОВЕРКИ РАБОТОСПОСОБНОСТИ OPENGL И SFML. ОН НЕ ЯВЛЯЕТСЯ ПРИМЕРОМ ИЛИ ЗАГОТОВКОЙ ДЛЯ ВЫПОЛНЕНИЯ ЛАБОРАТОРНЫХ РАБОТ!
#include <SFML/OpenGL.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
void SetIcon(sf::Window& wnd);
void Init();
void Draw();
int main() {
// Создаём окно
sf::Window window(sf::VideoMode({ 600, 600 }), "My OpenGL window");
// Ставим иконку (окна с дефолтной картинкой это некрасиво)
SetIcon(window);
// Включаем вертикальную синхронизацию (синхронизация частоты отрисовки с частотой кадров монитора, чтобы картинка не фризила, делать это не обязательно)
window.setVerticalSyncEnabled(true);
// Активируем окно
window.setActive(true);
// Инициализация
Init();
// Главный цикл окна
while (window.isOpen()) {
// Цикл обработки событий окна, тут можно ловить нажатия клавиш, движения мышки и всякое такое
while (const std::optional event = window.pollEvent())
{
if (event->is<sf::Event::Closed>()) {
window.close();
}
else if (const sf::Event::Resized* resized = event->getIf<sf::Event::Resized>()) {
// Изменён размер окна, надо поменять и размер области Opengl отрисовки
glViewport(0, 0, resized->size.x, resized->size.y);
}
}
// Очистка буферов
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Рисуем сцену
Draw();
// Отрисовывает кадр - меняет передний и задний буфер местами
window.display();
}
return 0;
}
// В момент инициализации разумно произвести загрузку текстур, моделей и других вещей
void Init() {
// Очистка буфера тёмно жёлтым цветом
glClearColor(0.5f, 0.5f, 0.0f, 1.0f);
}
// Глобальные переменные это плохо, тут это сделано просто для примера
GLfloat rotate_z = 0;
// Функция непосредственно отрисовки сцены
void Draw() {
rotate_z += 0.5;
// Используем устаревшую функциональность установки единичной матрицы преобразования
glLoadIdentity();
// С использованием устаревшей функции glRotate домножаем на матрицу поворота
glRotatef(rotate_z, 0.0, 0.0, 1.0);
// Используем устаревшую конструкцию glBegin-glEnd для рисования квадрата
glBegin(GL_QUADS);
glColor3f(1.0, 0.0, 0.0); glVertex2f(-0.5f, -0.5f);
glColor3f(0.0, 1.0, 0.0); glVertex2f(-0.5f, 0.5f);
glColor3f(0.0, 0.0, 1.0); glVertex2f(0.5f, 0.5f);
glColor3f(1.0, 1.0, 1.0); glVertex2f(0.5f, -0.5f);
glEnd();
// Отправляем набор команд отрисовываться
glFlush();
}
void SetIcon(sf::Window& wnd)
{
sf::Vector2u size{ 8, 8 };
sf::Image image(size);
// Вместо рисования пикселей, можно загрузить иконку из файла (image.loadFromFile("icon.png"))
for (unsigned int i = 0; i < size.x; ++i)
for (unsigned int j = 0; j < size.y; ++j)
image.setPixel({ i, j }, {
(std::uint8_t)(i * 32), (std::uint8_t)(j * 32), 0 });
wnd.setIcon(image.getSize(), image.getPixelsPtr());
}