From 8486c27fda42013b80efeb337acb747d3d775000 Mon Sep 17 00:00:00 2001 From: "re.kovalev" Date: Tue, 26 Jul 2022 13:13:30 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9A=D0=BE=D0=BF=D0=B8=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D0=B5=D0=BA=D1=82=D0=B0=20=D1=81=2002?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/c_cpp_properties.json | 18 +++ .vscode/settings.json | 8 ++ .vscode/tasks.json | 75 +++++++++++ include/Buffers.h | 43 +++++++ shaders/shader.frag | 8 ++ shaders/shader.vert | 9 ++ src/Buffers.cpp | 59 +++++++++ src/main.cpp | 227 ++++++++++++++++++++++++++++++++++ 8 files changed, 447 insertions(+) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 include/Buffers.h create mode 100644 shaders/shader.frag create mode 100644 shaders/shader.vert create mode 100644 src/Buffers.cpp create mode 100644 src/main.cpp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..3555d44 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "some_name", + "includePath": [ + "${workspaceFolder}/include", + "${workspaceFolder}/../dependencies/GLFW/include", + "${workspaceFolder}/../dependencies/glad/include", + "${workspaceFolder}/../dependencies/glm" + ], + "compilerPath": "C:/MinGW/bin/g++.exe", + "cStandard": "c11", + "cppStandard": "c++11", + "intelliSenseMode": "gcc-x86" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..560de08 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "files.associations": { + "fstream": "cpp", + "iosfwd": "cpp", + "map": "cpp", + "atomic": "cpp" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..b9f665d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,75 @@ +{ + "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", + "-I${workspaceFolder}/../dependencies/glm", + "-static", + "-lopengl32", + "-lglfw3dll", + "-o", + "${workspaceRoot}/${workspaceFolderBasename}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "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-w64", + "-I${workspaceFolder}/../dependencies/glad/include", + "-I${workspaceFolder}/../dependencies/glm", + "-static", + "-lopengl32", + "-lglfw3dll", + "-o", + "${workspaceRoot}/${workspaceFolderBasename}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "Задача создана отладчиком." + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git a/include/Buffers.h b/include/Buffers.h new file mode 100644 index 0000000..f427336 --- /dev/null +++ b/include/Buffers.h @@ -0,0 +1,43 @@ +#ifndef BUFFERS_H +#define BUFFERS_H + +#include + + + +// Объект массива вершин +class VAO +{ + public: + VAO(); // Создает VAO и активирует его + ~VAO(); // Уничтожает VAO + + void use(); // Активация VAO + static void disable(); // Деактивация активного VAO + + private: + GLuint handler; // Дескриптор +}; + +// Тип буфера +enum BUFFER_TYPE { VERTEX = GL_ARRAY_BUFFER + , ELEMENT = GL_ELEMENT_ARRAY_BUFFER + }; + +// Объект вершинного буфера +class VBO +{ + public: + VBO(BUFFER_TYPE type, void (*attrib_config)() = 0); // Создает пустой буфер, привязывает к активному VAO + VBO(BUFFER_TYPE type, const void *data, int size, void (*attrib_config)() = 0); // Создает , привязывает к активному VAO и загружает туда данные + ~VBO(); // Уничтожает буфер + + void load(const void *data, int size, GLuint mode = GL_STATIC_DRAW); // Загрузка вершин в + void use(); + + private: + GLuint handler; // Дескриптор + BUFFER_TYPE type; // Тип буфера +}; + +#endif // BUFFERS_H \ No newline at end of file diff --git a/shaders/shader.frag b/shaders/shader.frag new file mode 100644 index 0000000..3f0ad51 --- /dev/null +++ b/shaders/shader.frag @@ -0,0 +1,8 @@ +#version 330 core + +out vec3 color; + +void main() +{ + color = vec3(1, 0, 0); +} diff --git a/shaders/shader.vert b/shaders/shader.vert new file mode 100644 index 0000000..16f3963 --- /dev/null +++ b/shaders/shader.vert @@ -0,0 +1,9 @@ +#version 330 core + +layout(location = 0) in vec3 pos; + +void main() +{ + gl_Position.xyz = pos; + gl_Position.w = 1.0; +} diff --git a/src/Buffers.cpp b/src/Buffers.cpp new file mode 100644 index 0000000..e6864c7 --- /dev/null +++ b/src/Buffers.cpp @@ -0,0 +1,59 @@ +#include "Buffers.h" + +// Создает VAO и активирует его +VAO::VAO() +{ + glGenVertexArrays(1, &handler); // Генерация одного объекта массива вершин + glBindVertexArray(handler); // Привязка для использования +} + +// Уничтожает VAO +VAO::~VAO() +{ + glDeleteVertexArrays(1, &handler); +} + +// Активация VAO +void VAO::use() +{ + glBindVertexArray(handler); // Привязка VAO для использования +} + +// Деактивация активного VAO +void VAO::disable() +{ + glBindVertexArray(0); // Отключение VAO +} + +// Создает пустой буфер, привязывает к активному VAO, если нужно конфигурирует атрибуты +VBO::VBO(BUFFER_TYPE t, void (*attrib_config)()) : type(t) +{ + glGenBuffers(1, &handler); // Генерация одного объекта буфера вершин + glBindBuffer(type, handler); // Привязка элементного буфера + + if (attrib_config) + attrib_config(); +} + +// Создает буфер, привязывает к активному VAO и загружает туда данные, если нужно конфигурирует атрибуты +VBO::VBO(BUFFER_TYPE t, const void *data, int size, void (*attrib_config)()) : VBO(t, attrib_config) +{ + load(data, size); +} + +// Уничтожает буфер +VBO::~VBO() +{ + glDeleteBuffers(1, &handler); +} + +// Загрузка вершин в буфер +void VBO::load(const void *data, int size, GLuint mode) +{ + glBufferData(type, size, data, mode); +} + +void VBO::use() +{ + glBindBuffer(type, handler); // Привязка элементного буфера +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..8fa1cd9 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,227 @@ + +#include +#include +#include + +#include + +#include "Buffers.h" + +#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); +} + +#include +#include + +// Функция чтения шейдера из файла +std::string readFile(const char* filename) +{ + std::string text; + std::ifstream file(filename, std::ios::in); // Открываем файл на чтение + // Если файл доступен и успешно открыт + if (file.is_open()) + { + std::stringstream sstr; // Буфер для чтения + sstr << file.rdbuf(); // Считываем файл + text = sstr.str(); // Преобразуем буфер к строке + file.close(); // Закрываем файл + } + + return text; +} + +// Функция для загрузки шейдеров +// Принимает два адреса вершинного и фрагментного шейдеров +// Возвращает дескриптор шейдерной программы +GLuint LoadShaders(const char *vertex_file, const char *fragment_file) +{ + // Создание дескрипторов вершинного и фрагментного шейдеров + GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER); + GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); + + // Переменные под результат компиляции + GLint result = GL_FALSE; + int infoLogLength; + + // Считываем текст вершинного шейдера + std::string code = readFile(vertex_file); + const char* pointer = code.c_str(); // Преобразование к указателю на const char, так как функция принимает массив си-строк + + // Компиляция кода вершинного шейдера + glShaderSource(vertexShaderID, 1, &pointer, NULL); + glCompileShader(vertexShaderID); + + // Проверка результата компиляции + glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &result); + glGetShaderiv(vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength); + if (infoLogLength > 0) + { + char* errorMessage = new char[infoLogLength + 1]; + glGetShaderInfoLog(vertexShaderID, infoLogLength, NULL, errorMessage); + std::cout << errorMessage; + delete errorMessage; + } + + // Считываем текст вершинного шейдера + code = readFile(fragment_file); + pointer = code.c_str(); // Преобразование к указателю на const char, так как функция принимает массив си-строк + + // Компиляция кода фрагментного шейдера + glShaderSource(fragmentShaderID, 1, &pointer, NULL); + glCompileShader(fragmentShaderID); + + // Проверка результата компиляции + glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &result); + glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength); + if (infoLogLength > 0) + { + char* errorMessage = new char[infoLogLength + 1]; + glGetShaderInfoLog(fragmentShaderID, infoLogLength, NULL, errorMessage); + std::cout << errorMessage; + delete errorMessage; + } + + // Привязка скомпилированных шейдеров + GLuint programID = glCreateProgram(); + glAttachShader(programID, vertexShaderID); + glAttachShader(programID, fragmentShaderID); + glLinkProgram(programID); + + // Проверка программы + glGetProgramiv(programID, GL_LINK_STATUS, &result); + glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength); + if (infoLogLength > 0) + { + char* errorMessage = new char[infoLogLength + 1]; + glGetProgramInfoLog(programID, infoLogLength, NULL, errorMessage); + std::cout << errorMessage; + delete errorMessage; + } + + // Освобождение дескрипторов шейдеров + glDeleteShader(vertexShaderID); + glDeleteShader(fragmentShaderID); + + return programID; +} + +// Функция для конфигурации атрибутов +void attrib_config() +{ + // Включаем необходимый атрибут у выбранного VAO + glEnableVertexAttribArray(0); + // Устанавливаем связь между VAO и привязанным VBO + glVertexAttribPointer( 0 // индекс атрибута, должен совпадать с Layout шейдера + , 3 // количество компонент одного элемента + , GL_FLOAT // тип + , GL_FALSE // нормализованность значений + , 0 // шаг + , (void *)0 // отступ с начала массива + ); +} + +int main(void) +{ + GLFWwindow* window; // Указатель на окно GLFW3 + + // Инициализация GLFW3 + if (!glfwInit()) + { + std::cout << "GLFW init error\n"; + return -1; + } + + 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"; + glfwTerminate(); // Завершение работы с GLFW3 в случае ошибки + return -1; + } + + // Установка основного контекста окна + glfwMakeContextCurrent(window); + // Установка callback-функции для изменения размеров окна и буфера кадра + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + + glfwSwapInterval(1); // Вертикальная синхронизация + + // Загрузка функций OpenGL с помощью GLAD + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "GLAD load GL error\n"; + glfwTerminate(); // Завершение работы с GLFW3 в случае ошибки + return -1; + } + + // Компиляция шейдеров + GLuint shaderProgram = LoadShaders("shaders/shader.vert", "shaders/shader.frag"); + // Активация шейдера + glUseProgram(shaderProgram); + + // Вершины треугольника + glm::vec3 verticies[] = { {-0.5f, -0.5f, 0.0f} + , { 0.5f, -0.5f, 0.0f} + , { 0.5f, 0.5f, 0.0f} + , {-0.5f, 0.5f, 0.0f} + }; + + // VAO + VAO vao; + // VBO вершинный + VBO vbo_vert(VERTEX, attrib_config); + + // Загрузка вершин в используемый буфер вершин + vbo_vert.load(verticies, sizeof(verticies)); + + // индексы вершин + GLuint indices[] = {0, 1, 2, 2, 3, 0}; + + // VBO элементный (индексы вершин) + VBO vbo_elem(ELEMENT); + + // Загрузка индексов в используемый элементный буфер + vbo_elem.load(indices, sizeof(indices)); + + // Установка цвета очистки буфера цвета + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + + // Пока не произойдет событие запроса закрытия окна + while(!glfwWindowShouldClose(window)) + { + // Очистка буфера цвета + glClear(GL_COLOR_BUFFER_BIT); + + // Тут производится рендер + vao.use(); + glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(GLuint), GL_UNSIGNED_INT, (void*)0); + vao.disable(); + + // Представление содержимого буфера цепочки показа на окно + glfwSwapBuffers(window); + // Обработка системных событий + glfwPollEvents(); + } + + // Удаление шейдерной программы + glDeleteProgram(shaderProgram); + + // Отключение атрибутов + glDisableVertexAttribArray(0); + + // Завершение работы с GLFW3 перед выходом + glfwTerminate(); +}