Введение
Цель данного курса заметок по OpenGL является рассмотрение возможностей данной библиотеки и разработка приложения для рисования трехмерной графики.
В проекте будет использоваться компилятор MinGW (GCC 6.3.0).
В качестве IDE для разработки будет использоваться VS Code ввиду её скорости работы и простоты использования.
По аналогии с циклом заметок по Vulkan API для создания окна будет использоваться библиотека glfw3, которая обладает простым интерфейсом, а для инициализации функций OpenGL — glad. Скачанные библиотеки необходимо разместить в директории «dependencies» рядом с директорией проекта, так как одни и те же библиотеки будут использоваться в разных проектах.
Для библиотека glad компонуется на сайте разработчика под необходимые требования, для цикла заметок понадобится выбрать GL: Verison 4.6.
Библиотеки доступны в репозитории: dependencies.
Настройка правил сборки
По большей части данный раздел повторяет оригинальную заметку Vulkan API 01.
Для начала создадим директории для хранения исходных текстов программ (*.c, *.cpp) и назовем её «src«. Внутри этой директории создадим файл «main.cpp«.
А так же создадим папку для хранения заголовочных файлов (*.h, *.hpp) и назовем её «include«.
После этого настроим задачу сборки по умолчанию из меню «Терминал» выбрав одноименный пункт из этого меню. Содержимое меню представлено на рисунке 1.
Среда разработки уточнит адрес исполняемого файла компилятора и создаст файл.
В конфигурации по умолчанию не используются никакие библиотеки и собирается текущий открытый в редакторе файл как исполняемый.
Важное примечание: так как для ОС Windows нет особой разницы для написания пути через прямой или обратный слеш, то будет использоваться прямой для совместимости с ОС Linux.
Как следствие автор заменил все двойные обратные слеши на одинарные прямые. Отредактированная версия оригинального скрипта:
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe сборка активного файла",
"command": "C:/MinGW/bin/g++.exe",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Задача создана отладчиком."
}
],
"version": "2.0.0"
}
Стоит заметить, что ввиду форматирования страницы некоторые строки из файла занимают 2 и более в браузере.
Ключ «-g» с 9 строки нам не нужен. Его можно удалить.
В рамках курса заметок будет использоваться подход с дроблением исходных текстов программы на разные файлы с последующей компиляцией их в общий исполняемый файл. Для того чтобы собрать все файлы из папки src по шаблону «*.cpp» из директории src заменим 9 строку (10, если не удалять ключ -g) с адресом на:
"${workspaceRoot}/src/*.cpp",
"${workspaceRoot}/../dependencies/glad/src/glad.c",
Примечание: дополнительно указываются исходные тексты библиотеки glad для компиляции с проектом.
В дальнейшем при добавлении новых директорий с исходниками файл будет дополняться.
Добавим директорию с заголовочными файлами:
"-I${workspaceRoot}/include",
При желании можно указать конкретную версию компилятора:
"--std=c++11",
Добавим папки include и lib от GLFW, а так же include от GLAD. Так как они находятся на уровень выше директории проекта необходимо добавить «../«:
"-I${workspaceRoot}/../dependencies/GLFW/include",
"-L${workspaceRoot}/../dependencies/GLFW/lib-mingw",
"-I${workspaceFolder}/../dependencies/glad/include",
И добавим флаги:
"-static",
"-lopengl32",
"-lglfw3dll",
Разберемся с флагами:
- static — предотвращает линковку с разделяемыми библиотеками в системах, которые поддерживают динамическую линковку;
- lopengl32 — использует библиотеку OpenGL;
- lglfw3dll — использует статическую библиотеку GLFW3, подразумевающую дальнейшую работу приложения с динамической библиотекой.
В конце необходимо изменить имя исполняемого файла, для этого заменим строку:
"${fileDirname}/${fileBasenameNoExtension}.exe"
на строку:
"${workspaceRoot}/${workspaceFolderBasename}.exe"
Благодаря этой замене исполняемый файл будет создан в корне проекта с именем директории.
В результате файл должен иметь следующее содержание:
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe сборка активного файла",
"command": "C:/MinGW/bin/g++.exe",
"args": [
"-fdiagnostics-color=always",
"${workspaceRoot}/src/*.cpp",
"${workspaceRoot}/../dependencies/glad/src/glad.c",
"-I${workspaceRoot}/include",
"--std=c++11",
"-I${workspaceRoot}/../dependencies/GLFW/include",
"-L${workspaceRoot}/../dependencies/GLFW/lib-mingw",
"-I${workspaceFolder}/../dependencies/glad/include",
"-static",
"-lopengl32",
"-lglfw3dll",
"-o",
"${workspaceRoot}/${workspaceFolderBasename}.exe"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Задача создана отладчиком."
}
],
"version": "2.0.0"
}
После настроек сборки необходимо указать редактору директории с заголовочными файлами.
Настройка плагина intelliSense
В директории «.vscode» необходимо создать файл «c_cpp_properties.json» со следующим содержимым:
{
"configurations": [
{
"name": "some_name",
"includePath": [
"${workspaceFolder}/include",
"${workspaceFolder}/../dependencies/GLFW/include",
"${workspaceFolder}/../dependencies/glad/include"
],
"compilerPath": "C:/MinGW/bin/g++.exe",
"cStandard": "c11",
"cppStandard": "c++11"
}
],
"version": 4
}
В данном файле можно изменить настройки intelliSense:
- includePath — указать директории в которых дополнительно необходимо искать заголовочные файлы;
- compilerPath — путь до компилятора;
- cStandard — стандарт языка С;
- cppStandart — стандарт языка С++.
Важное замечание: intelliSenseMode — режим работы расширения лучше убрать для обеспечения гибкости при кроссплатформенной разработке.
Важно помнить что эти настройки распространяются только на плагин intelliSense, а не на компилятор
Создание окна
Рассмотрим следующий код:
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define WINDOW_CAPTION "OPENGL notes on rekovalev.site"
// Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
int main(void)
{
GLFWwindow* window; // Указатель на окно GLFW3
// Инициализация GLFW3
if (!glfwInit())
{
std::cout << "GLFW init error\n";
return -1;
}
// Завершение работы с GLFW3 перед выходом
atexit(glfwTerminate);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Мажорная версия спецификаций OpenGL
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); // Минорная версия спецификаций OpenGL
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Контекст OpenGL, который поддерживает только основные функции
// Создание окна GLFW3 с заданными шириной, высотой и заголовком окна
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_CAPTION, NULL, NULL);
if (!window)
{
std::cout << "GLFW create window error\n";
return -1;
}
// Установка основного контекста окна
glfwMakeContextCurrent(window);
// Установка callback-функции для изменения размеров окна и буфера кадра
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// Загрузка функций OpenGL с помощью GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "GLAD load GL error\n";
return -1;
}
// Установка цвета очистки буфера цвета
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Пока не произойдет событие запроса закрытия окна
while(!glfwWindowShouldClose(window))
{
// Очистка буфера цвета
glClear(GL_COLOR_BUFFER_BIT);
// Тут производится рендер
// ...
// Представление содержимого буфера цепочки показа на окно
glfwSwapBuffers(window);
// Обработка системных событий
glfwPollEvents();
}
return 0;
}
В определении функции main инициализируется glfw вызовом функции glfwInit(). Сразу после инициализации с помощью функции atexit задается вызов функции glfwTerminate, которая будет вызвана перед закрытием приложения. Такой подход позволяет избежать дублирования фрагментов кода с вызовом в случае ошибок инициализации библиотек, а так же возникновения «segmentation fault» ошибок деструкторов глобальных переменных в следствии явного вызова функции glfwTerminate в конце функции main.
С помощью функции glfwWindowHint задаются параметры для создаваемого окна, такие как: мажорная и минорная версии OpenGL и содержание контекста (поддержка расширений).
Для создания окна используется функция glfwCreateWindow, которая принимает в качестве аргументов ширину и высоту окна в пикселях, текст заголовка окна, а так же контекст монитора и контекст окна для обмена ресурсами. Последние два параметра не используются и заместо них передается NULL. В случае ошибки при создании окна выдается сообщение об ошибке и завершается работа приложения.
Далее производится установка основного контекста окна с помощью glfwMakeContextCurrent, а так же устанавливается callback-функция на событие изменения размеров окна, которая изменяет размеры буфера кадра с помощью функции glfwSetFramebufferSizeCallback. Рассмотрим передаваемую функцию подробнее:
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
Данная функция принимает в качестве аргументов указатель на объект структуры окна GLFWwindow, а так же новые ширину и высоту. В определении данной функции производится вызов функции glViewport, которая изменяет размеры буфера кадра.
Следующим этапом инициализации служит вызов функции gladLoadGLLoader из библиотеки GLAD, которая инициализирует функции OpenGL, так как в зависимости от драйверов функции могут быть недоступны и располагаться по разным адресам в памяти. В случае ошибки выдается соответствующее сообщение и завершается работа приложения.
Теперь можно задать цвет для функции очистки буфера с помощью glClearColor (r,g,b,a).
Важное замечание: функция glClearColor принимает значения цветов в диапазоне 0.0f-1.0f, что эквивалентно диапазону 0-255, который можно преобразовать с помощью формулы: компонента_цвета / 255.0f.
Далее следует жизненный цикл окна, пока окну не придёт сигнал закрытия от системы. Внутри этого цикла производится очистка буфера цвета, представление буфера на поверхность окна и обработка событий от ОС вызовом функции glfwPollEvents.
Теперь проект можно собрать, вызвав в меню «Терминал» пункт «Запустить задачу сборки».
Перед запуском необходимо положить файл glfw3.dll в корень проекта.
Дополнение
В репозиторий добавлена вертикальная синхронизация.
После инициализации контекста окна:
// Установка основного контекста окна
glfwMakeContextCurrent(window);
// Установка callback-функции для изменения размеров окна и буфера кадра
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSwapInterval(1); // Вертикальная синхронизация
// Загрузка функций OpenGL с помощью GLAD
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
Подробнее об этом можно прочитать в соответствующей заметке: ограничение частоты кадров.
Сборка под архитектуру x64
Для сборки 64-х разрядного приложения под OS Windows потребуется отдельная версия MinGW, которую можно скачать с репозитория (есть онлайн установщик, ссылка на который доступна в описании репозитория).
Изменим файл .vscode/tasks.json, добавив туда конфигурацию для сборки х64:
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++.exe сборка активного файла",
...
"detail": "Задача создана отладчиком."
},
{
"type": "cppbuild",
"label": "C/C++ x64: g++.exe сборка активного файла",
"command": "C:/MinGW64/bin/g++.exe",
"args": [
"-fdiagnostics-color=always",
"${workspaceRoot}/src/*.cpp",
"${workspaceRoot}/../dependencies/glad/src/glad.c",
"-I${workspaceRoot}/include",
"--std=c++11",
"-I${workspaceRoot}/../dependencies/GLFW/include",
"-L${workspaceRoot}/../dependencies/GLFW/lib-mingw-w64lib-mingw-w64",
"-I${workspaceFolder}/../dependencies/glad/include",
"-static",
"-lopengl32",
"-lglfw3dll",
"-o",
"${workspaceRoot}/${workspaceFolderBasename}.exe"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Задача создана отладчиком."
}
],
"version": "2.0.0"
}
Важное замечание: архитектура файла glfw3.dll должна соответствовать архитектуре собранного приложения, иначе приложение завершит работу без вывода соответствующей ошибки.
Использование Makefile в VScode
В процессе добавления кросплатформенных правил сборка приложения через .vscode/tasks.json становится неподъемной — требуется дублировать большой объем аргументов в аргументах задачи сборки, а так же отстутствует возможность скрыть задачи не подходящие под имеющуюся архитектуру.
Для решения данной проблемы можно воспользоваться классическим способом сборки C/C++ приложений — использование Makefile. Рассмотрим задачу использования Makefile в VS code для задач сборки OpenGL приложения.
Makefile — файл, содержащий в себе набор инструкций для утилиты make. Инструкции группируются в «цели». Цели могут выстраиваться в дерево зависимых «целей». Цель по умолчанию — all, зачастую так же присутствует цель clean, выполняющая очистку проекта.
Важное замечание: для сборки Makefile под ОС Windows необходимо установить утилиту GNU-make с официального сайта и добавить её адрес в переменную среды Path. В семействе Unix-систем данная утилита является частью системы.
Изменим файл .vscode/tasks.json, оставив одну задачу:
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: make сборка",
"command": "make",
"args": [],
"options": {
"cwd": "${workspaceRoot}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Задача создана отладчиком."
}
],
"version": "2.0.0"
}
Так как по умолчанию будет выполнятся цель all необходимо сделать несколько задач, либо добавить ввод с клавиатуры интересующей задачи:
{
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: make сборка",
"command": "make",
"args": [
"${input:target}"
],
"options": {
"cwd": "${workspaceRoot}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "Задача создана отладчиком."
}
],
"inputs": [
{
"id": "target",
"description": "Цель сборки (all, list, clean)",
"default": "all",
"type": "promptString"
},
],
"version": "2.0.0"
}
Теперь при запуске задачи сборки в VS code будет отображено поле для ввода цели сборки make с подсказкой основных целей и all по умолчанию. Пример такого окна ввода изображен на рисунке 2.
Теперь можно создать основной файл Makefile в корневой директории проекта.
Комментарии начинаются с символа #
Makefile поддерживает ветвление условным оператором ifeq, который может сравнивнить переменную среды и строку. В данном проекте данный оператор будет использоваться для определения целей и значений переменных, которые зависят от целевой платформы (переменная OS). Пример:
ifeq ($(OS), Windows_NT)
# Если ОС - Windows
else
# Остальные ОС
endif
Так же для сборки x32 приложений будет создана цель, на основании которой так же будет выполняться ветвление (переменная MAKECMDGOALS), но только в рамках ОС Windows. Сборка x64 будет выполняться по умолчанию.
Переменные по правилам написания Makefile используя оператор = могут изменять значение, с помощью оператора := могут быть константными при задании значения, или же дополняться используя +=
В созданном файле определим значения переменных CFLAGS (опции компилятора) и LDFLAGS (опции линкера) на основании старого tasks.json:
# Опции компилятора
CFLAGS += -c
CFLAGS += -I./include
CFLAGS += -I../dependencies/GLFW/include
CFLAGS += -I../dependencies/glad/include
# Опции линкера
LDFLAGS += --std=c++11
Далее следует определить платформозависимые опции линкера:
# Архитектурозависимые опции линкера
ifeq ($(OS), Windows_NT)
# GLFW в зависимости от архитектуры
ifeq ($(MAKECMDGOALS), x32)
LDFLAGS += -L../dependencies/GLFW/lib-mingw
else
LDFLAGS += -L../dependencies/GLFW/lib-mingw-w64
endif
LDFLAGS += -static
LDFLAGS += -lglfw3dll
LDFLAGS += -lopengl32
else
LDFLAGS += -lglfw
LDFLAGS += -lGL
endif
Важное замечание: для ОС Linux необходимо установить пакет с библиотекой GLFW3. В зависимости от дистрибутива имя пакета может меняться:
- libglfw3-dev — Ubuntu/Debian;
- glfw-x11 или glfw-wayland — Arch linux;
- glfw-devel — Fedora.
Важное замечание: для ОС Windows требуется флаг -static, для Linux данный флаг не требуется.
Определим переменные, связанные с библиотекой GLAD:
# Библиотека GLAD
GLAD := ../dependencies/glad/src/glad.c
GLAD_O := $(GLAD:.c=.o)
Примечание: конструкция $(GLAD:.c=.o) выполняет замену расширения файлов в переменной GLAD с .c на .o.
С помощью утилиты wildcard получим все файлы из директории src:
# Файлы из директории src
SOURCES_C = $(wildcard src/*.c)
SOURCES_CPP = $(wildcard src/*.cpp)
Определим название директории с объектными файлами и имена таких файлов:
# Директория с объектными файлами
OBJ_DIR := Obj
# Объектные файлы
OBJECTS = $(addprefix $(OBJ_DIR)/,$(SOURCES_CPP:src/%.cpp=%.o))
Осталось определить последние платформозависимые переменные:
# Компилятор и директория проекта
ifeq ($(OS), Windows_NT)
# С возможностью сборки x32
ifeq ($(MAKECMDGOALS), x32)
CC = C:/MinGW/bin/g++.exe
else
CC = C:/MinGW64/bin/g++.exe
endif
PROJECT_DIR = $(shell echo %cd%)
PATH_SEPARATOR = \\
# Имя исполняемого файла
EXECUTABLE = $(notdir $(strip $(PROJECT_DIR))).exe
else
CC = g++
PROJECT_DIR = $(shell pwd)
PATH_SEPARATOR = /
# Имя исполняемого файла
EXECUTABLE = $(notdir $(strip $(PROJECT_DIR)))
endif
Теперь можно приступить к определению целей. Пример общего вида цели:
цель1: зависимость1 зависимость2 зависимость3
команда_отображаемая_в_консоли
@команда_неотображаемая_в_консоли
Примечание: цель может не иметь зависимостей от других целей.
Основная цель all зависит от исполняемого файла, который тоже является целью:
# Цель по умолчанию, зависит от EXECUTABLE
all: $(EXECUTABLE)
Цель EXECUTABLE в свою очередь зависит от объектных файлов, объектного файла GLAD_O и наличия директории для объектных файлов, а в качестве действия выполняет сборку исполняемого файла с использованием флагов LDFLAGS.
рф
Здесь в свою очередь $@ — переменная с именем текущей цели (EXECUTABLE).
Важное замечание: флаги линковки должны быть заданы после объектных файлов во избежание ошибки сборки.
Цель для сборки GLAD_O имеет следующий вид:
# Цель для сборки GLAD
$(GLAD_O): $(GLAD)
$(CC) $(CFLAGS) $< -o $@
Цель OBJ_DIR необходима для решения возможных ошибок во время сборки объектных файлов, связанных с отсутствием таковой директории в корне проекта:
# Цель для создания директории с объектными файлами
$(OBJ_DIR):
@mkdir $(OBJ_DIR)
Цель сборки объектных файлов имеет следующий вид:
# Цель сборки объектных файлов
$(OBJ_DIR)/%.o: src/%.cpp
$(CC) $(CFLAGS) $< -o $@
Здесь $< переменная с зависимостями данной цели.
В качестве вспомогательной добавим цель list, которая выводит все объектные файлы, учавствующие в сборке:
# Цель вывода всех файлов, учавствтующих в сборке
list:
@echo "В сборке участвуют:" $(OBJECTS)
Осталось добавить цель clean, которая является платформозависимой из-за особенностей работы команды rm под Windows:
# Очистка
ifeq ($(OS), Windows_NT)
clean: $(OBJ_DIR)
@rmdir /s /q $(OBJ_DIR)
else
clean: $(OBJ_DIR)
@rm -f $(EXECUTABLE) $(OBJECTS)
endif
Итоговый вид Makefile:
# Компилятор и директория проекта
ifeq ($(OS), Windows_NT)
# С возможностью сборки x32
ifeq ($(MAKECMDGOALS), x32)
CC = C:/MinGW/bin/g++.exe
else
CC = C:/MinGW64/bin/g++.exe
endif
PROJECT_DIR = $(shell echo %cd%)
PATH_SEPARATOR = \\
# Имя исполняемого файла
EXECUTABLE = $(notdir $(strip $(PROJECT_DIR))).exe
else
CC = g++
PROJECT_DIR = $(shell pwd)
PATH_SEPARATOR = /
# Имя исполняемого файла
EXECUTABLE = $(notdir $(strip $(PROJECT_DIR)))
endif
# Опции компилятора
CFLAGS += -c -Wall
CFLAGS += -I./include
CFLAGS += -I../dependencies/GLFW/include
CFLAGS += -I../dependencies/glad/include
# Опции линкера
LDFLAGS += --std=c++11
# Архитектурозависимые опции линкера
ifeq ($(OS), Windows_NT)
# GLFW в зависимости от архитектуры
ifeq ($(MAKECMDGOALS), x32)
LDFLAGS += -L../dependencies/GLFW/lib-mingw
else
LDFLAGS += -L../dependencies/GLFW/lib-mingw-w64
endif
LDFLAGS += -static
LDFLAGS += -lglfw3dll
LDFLAGS += -lopengl32
else
LDFLAGS += -lglfw
LDFLAGS += -lGL
endif
# Библиотека GLAD
GLAD := ../dependencies/glad/src/glad.c
GLAD_O := $(GLAD:.c=.o)
# Файлы из директории src
SOURCES_C = $(wildcard src/*.c)
SOURCES_CPP = $(wildcard src/*.cpp)
# Директория с объектными файлами
OBJ_DIR := Obj
# Объектные файлы
OBJECTS = $(addprefix $(OBJ_DIR)/,$(SOURCES_C:src/%.c=%.o) $(SOURCES_CPP:src/%.cpp=%.o))
# Для x32 сборки под Windows
ifeq ($(OS), Windows_NT)
ifeq ($(MAKECMDGOALS), x32)
x32: all
endif
endif
# Цель по умолчанию, зависит от EXECUTABLE
all: $(EXECUTABLE)
# Цель сборки исполняемого файла, зависит от OBJ_DIR, OBJECTS и GLAD_O
$(EXECUTABLE): $(OBJ_DIR) $(OBJECTS) $(GLAD_O)
$(CC) $(OBJECTS) $(GLAD_O) $(LDFLAGS) -o $@
# Цель для сборки GLAD
$(GLAD_O): $(GLAD)
$(CC) $(CFLAGS) $< -o $@
# Цель для создания директории с объектными файлами
$(OBJ_DIR):
@mkdir $(OBJ_DIR)
# Цель сборки объектных файлов
$(OBJ_DIR)/%.o: src/%.c
$(CC) $(CFLAGS) $< -o $@
$(OBJ_DIR)/%.o: src/%.cpp
$(CC) $(CFLAGS) $< -o $@
# Цель вывода всех файлов, учавствтующих в сборке
list:
@echo "В сборке участвуют:" $(OBJECTS)
# Очистка
ifeq ($(OS), Windows_NT)
clean: $(OBJ_DIR)
@rmdir /s /q $(OBJ_DIR)
else
clean: $(OBJ_DIR)
@rm -f $(EXECUTABLE) $(OBJECTS)
endif
Использование Makefile позволит ускорить сборку проекта на последних заметках в виду объема компилируемого кода, так как неизмененные объектные файлы хранятся в отдельной папке и будут использованы для последующей компоновки с измененными. При изменении заголовочных файлов необходимо пересобрать весь проект с использованием цели clean:
make clean && make
Важное замечание: последующие заметки будут постепенно переведены на работу с Makefile, что может привести к отделению HEAD в git-директории. Для решения данной проблемы необходимо выполнить команду:
git checkout master
Заключение
В рамках данной заметки была произведена установка библиотек GLFW, GLAD и OpenGL, настройка VS code для работы с ними и сборка программы, создающей окно для дальнейшей работы.
Проект доступен в публичном репозитории: 01
Библиотеки: dependencies
2 ответа к “OpenGL 1: начало работы в VS Code”
Большое СПАСИБО !
Более полного и ясного изложения не встречал !
Всех благ !!!
Полезный материал, сам бы долго разбирался