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..999dba4 --- /dev/null +++ b/include/Buffers.h @@ -0,0 +1,50 @@ +#ifndef BUFFERS_H +#define BUFFERS_H + +#include + +#include + +// Объект массива вершин +class VAO +{ + public: + VAO(); // Создает VAO и активирует его + ~VAO(); // Уничтожает VAO + VAO(const VAO & copy); // Конструктор копирования + VAO& operator=(const VAO & other); // Оператор присваивания + + void use(); // Активация VAO + static void disable(); // Деактивация активного VAO + + private: + GLuint handler; // Дескриптор + static std::map handler_count; // Счетчик использований дескриптора +}; + +// Тип буфера +enum BUFFER_TYPE { VERTEX = GL_ARRAY_BUFFER + , ELEMENT = GL_ELEMENT_ARRAY_BUFFER + }; + +// Объект вершинного буфера +class BO +{ + public: + BO(BUFFER_TYPE type); // Создает пустой буфер заданного типа + BO(BUFFER_TYPE type, const void *data, int size); // Создает и загружает туда данные + ~BO(); // Уничтожает буфер + BO(const BO & copy); // Конструктор копирования + BO& operator=(const BO & other); // Оператор присваивания + + void load(const void *data, int size, GLuint mode = GL_STATIC_DRAW); // Загрузка данных в буфер + void use(); + + protected: + GLuint handler; // Дескриптор + BUFFER_TYPE type; // Тип буфера + private: + static std::map handler_count; // Счетчик использований дескриптора +}; + +#endif // BUFFERS_H \ No newline at end of file diff --git a/include/Camera.h b/include/Camera.h new file mode 100644 index 0000000..3357cba --- /dev/null +++ b/include/Camera.h @@ -0,0 +1,49 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include + +// Ближняя граница области отсечения +#define CAMERA_NEAR 0.1f +// Дальняя граница области отсечения +#define CAMERA_FAR 100.0f +// Вектор, задающий верх для камеры +#define CAMERA_UP_VECTOR glm::vec3(0.0f, 1.0f, 0.0f) +// Стандартный угол обзора +#define CAMERA_FOVy 60.0f + +class Camera +{ + public: + Camera(float aspect, const glm::vec3 &position = glm::vec3(0.0f, 0.0f, 0.0f), const glm::vec2 &xyOffset = glm::vec2(90.0f, 0.0f), float fovy = CAMERA_FOVy); // Конструктор камеры с проекцией перспективы + Camera(float width, float height, const glm::vec3 &position = glm::vec3(0.0f, 0.0f, 0.0f), const glm::vec2 &xyOffset = glm::vec2(90.0f, 0.0f)); // Конструктор ортографической камеры + virtual ~Camera(); // Деструктор + const glm::mat4& getVP(); // Возвращает ссылку на константную матрицу произведения матриц вида и проекции + const glm::mat4& getProjection(); // Возвращает ссылку на константную матрицу проекции + const glm::mat4& getView(); // Возвращает ссылку на константную матрицу вида + void rotate(const glm::vec2 &xyOffset); // Поворачивает камеру на dx и dy пикселей + void move(const glm::vec3 &posOffset); // Сдвигает камеру на указанный вектор (dx,dy,dz) + void setPosition(const glm::vec3 &position); // Устанавливает местоположение + void setRotation(const glm::vec2 &xyOffset); // Устанавливает угол поворота камеры + void setPerspective(float fov, float aspect); // Устанавливает заданную матрицу перспективы + void setOrtho(float width, float height); // Устанавливает заданную ортографическую матрицу + void setSensitivity(float sensitivity); // Изменяет чувствительность мыши + protected: + Camera(const glm::vec3 &position, const glm::vec2 &xyOffset); // Защищенный (protected) констуктор камеры без перспективы + void recalcTarget(); // Пересчет цели, на которую смотрит камера + void recalcView(); // Пересчет матрицы вида + void recalcVP(); // Пересчет произведения матриц + + glm::vec3 position; // Местоположение камеры + glm::vec3 target; // Цель, на которую смотрит камера + glm::vec2 currentRotation; // Текущий поворот камеры + glm::mat4 projection; // Матрица проекции + glm::mat4 view; // Матрица вида + glm::mat4 vp; // Матрица произведения вида и проекции + bool requiredRecalcVP; // Необходимость пересчета матрицы вида и проекции камеры + bool requiredRecalcView; // Необходимость пересчета матрицы вида камеры + float sensitivity; // Чувствительность мыши +}; + + +#endif // CAMERA_H \ No newline at end of file diff --git a/include/Model.h b/include/Model.h new file mode 100644 index 0000000..62d21df --- /dev/null +++ b/include/Model.h @@ -0,0 +1,31 @@ +#ifndef MODEL_H +#define MODEL_H + +#include "Buffers.h" + +#include + +class Model +{ + public: + Model(); // Конструктор без параметров + Model(const Model& copy); // Конструктор копирования + ~Model(); + void render(const GLuint &mvp_uniform); // Вызов отрисовки + void load_verteces(glm::vec3* verteces, GLuint count); // Загрузка вершин в буфер + void load_indices(GLuint* indices, GLuint count); // Загрузка индексов в буфер + + glm::vec3 position; // позиция модели + glm::vec3 rotation; // поворот модели + glm::vec3 scale; // мастабирование модели + glm::mat4 getTransformMatrix(); // Матрица трансформации модели + + private: + VAO vao; + BO vertex_vbo, index_vbo; // вершинный и индексный буферы + GLuint verteces_count; // Количество вершин + GLuint indices_count; // Количество индексов + +}; + +#endif // MODEL_H 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..c4739dc --- /dev/null +++ b/shaders/shader.vert @@ -0,0 +1,10 @@ +#version 330 core + +layout(location = 0) in vec3 pos; + +uniform mat4 mvp; + +void main() +{ + gl_Position = mvp * vec4(pos, 1.0); +} diff --git a/src/Buffers.cpp b/src/Buffers.cpp new file mode 100644 index 0000000..cb47cd2 --- /dev/null +++ b/src/Buffers.cpp @@ -0,0 +1,119 @@ +#include "Buffers.h" + +// Счетчики использований дескрипторов +std::map VAO::handler_count; +std::map BO::handler_count; + +// Создает VAO и активирует его +VAO::VAO() +{ + glGenVertexArrays(1, &handler); // Генерация одного объекта массива вершин + glBindVertexArray(handler); // Привязка для использования + handler_count[handler] = 1; // Инициализация счетчика для дескриптора +} + +// Уничтожает VAO +VAO::~VAO() +{ + // Если дескриптор никем не используется - освободим его + if (!--handler_count[handler]) + { + glDeleteVertexArrays(1, &handler); + handler_count.erase(handler); // Удаление из словаря + } +} + +// Конструктор копирования +VAO::VAO(const VAO & copy) : handler(copy.handler) +{ + handler_count[handler]++; +} + +// Оператор присваивания +VAO& VAO::operator=(const VAO & other) +{ + // Если это разные дескрипторы + if (handler != other.handler) + { // то следуюет удалить текущий перед заменой + this->~VAO(); + handler = other.handler; + handler_count[handler]++; + } + + return *this; +} + +// Активация VAO +void VAO::use() +{ + glBindVertexArray(handler); // Привязка VAO для использования +} + +// Деактивация активного VAO +void VAO::disable() +{ + glBindVertexArray(0); // Отключение VAO +} + +// Создает пустой буфер заданного типа +BO::BO(BUFFER_TYPE t) : type(t) +{ + glGenBuffers(1, &handler); // Генерация одного объекта буфера + handler_count[handler] = 1; + use(); // Привязка буфера +} + +// Создает и загружает туда данные +BO::BO(BUFFER_TYPE t, const void *data, int size) : BO(t) +{ + load(data, size); +} + +// Уничтожает буфер +BO::~BO() +{ + if (handler) // Если буфер был создан + { + // Если дескриптор никем не используется - освободим его + if (!--handler_count[handler]) + { + glDeleteBuffers(1, &handler); + handler_count.erase(handler); // Удаление из словаря + } + handler = 0; + } +} + +// Конструктор копирования +BO::BO(const BO & copy) : handler(copy.handler), type(copy.type) +{ + handler_count[handler]++; +} + +// Оператор присваивания +BO& BO::operator=(const BO & other) +{ + // Если это разные дескрипторы + if (handler != other.handler) + { // то следуюет удалить текущий перед заменой + this->~BO(); + handler = other.handler; + handler_count[handler]++; + } + // Изменим тип + type = other.type; + + return *this; +} + +// Загрузка вершин в буфер +void BO::load(const void *data, int size, GLuint mode) +{ + use(); // Привязка буфера + glBufferData(type, size, data, mode); +} + +void BO::use() +{ + glBindBuffer(type, handler); // Привязка элементного буфера +} diff --git a/src/Camera.cpp b/src/Camera.cpp new file mode 100644 index 0000000..d1f6431 --- /dev/null +++ b/src/Camera.cpp @@ -0,0 +1,141 @@ +#include "Camera.h" + +#include +#include + +// Защищенный (protected) конструктор камеры без перспективы +Camera::Camera(const glm::vec3 &pos, const glm::vec2 &xyOffset) +: position(pos), currentRotation(xyOffset) +{ + sensitivity = 0.05; + recalcTarget(); +} + +// Конструктор камеры с проекцией перспективы +Camera::Camera(float aspect, const glm::vec3 &position, const glm::vec2 &xyOffset, float fovy) +: Camera(position, xyOffset) +{ + setPerspective(fovy, aspect); +} + +// Конструктор ортографической камеры +Camera::Camera(float width, float height, const glm::vec3 &position, const glm::vec2 &xyOffset) +: Camera(position, xyOffset) +{ + setOrtho(width, height); +} + +// Деструктор +Camera::~Camera() { } + +// Пересчет цели, на которую смотрит камера +void Camera::recalcTarget() +{ + if(currentRotation.y > 89.0f) + currentRotation.y = 89.0f; + if(currentRotation.y < -89.0f) + currentRotation.y = -89.0f; + + target.x = cos(glm::radians(currentRotation.x)) * cos(glm::radians(currentRotation.y)); + target.y = sin(glm::radians(currentRotation.y)); + target.z = sin(glm::radians(currentRotation.x)) * cos(glm::radians(currentRotation.y)); + + requiredRecalcView = true; + requiredRecalcVP = true; +} + +// Пересчет матрицы вида +void Camera::recalcView() +{ + view = glm::lookAt(position, position + target, CAMERA_UP_VECTOR); + requiredRecalcView = false; +} + +// Пересчет произведения матриц +void Camera::recalcVP() +{ + vp = projection * view; + requiredRecalcVP = false; +} + +// Возвращает ссылку на константную матрицу проекции +const glm::mat4& Camera::getProjection() +{ + return projection; +} + +// Возвращает ссылку на константную матрицу вида +const glm::mat4& Camera::getView() +{ + if (requiredRecalcView) + recalcView(); + return view; +} + +// Возвращает ссылку на константную матрицу вида +const glm::mat4& Camera::getVP() +{ + if (requiredRecalcVP) + { + if (requiredRecalcView) + recalcView(); + recalcVP(); + } + return vp; +} + +// Поворачивает камеру на dx и dy пикселей +void Camera::rotate(const glm::vec2 &xyOffset) +{ + currentRotation += xyOffset * sensitivity; + + recalcTarget(); + requiredRecalcView = true; + requiredRecalcVP = true; +} + +// Сдвигает камеру на указанный вектор (dx,dy,dz) +void Camera::move(const glm::vec3 &posOffset) +{ + position += posOffset; + + requiredRecalcView = true; + requiredRecalcVP = true; +} + +// Устанавливает местоположение +void Camera::setPosition(const glm::vec3 &pos) +{ + position = pos; + + requiredRecalcView = true; + requiredRecalcVP = true; +} + +// Устанавливает угол поворота камеры +void Camera::setRotation(const glm::vec2 &xyOffset) +{ + currentRotation = xyOffset; + recalcTarget(); +} + +// Устанавливает заданную матрицу перспективы +void Camera::setPerspective(float fovy, float aspect) +{ + projection = glm::perspective(glm::radians(fovy), aspect, CAMERA_NEAR, CAMERA_FAR); + requiredRecalcVP = true; +} + +// Устанавливает заданную ортографическую матрицу +void Camera::setOrtho(float width, float height) +{ + const float aspect = width / height; + projection = glm::ortho(-1.0f, 1.0f, -1.0f/aspect, 1.0f/aspect, CAMERA_NEAR, CAMERA_FAR); + requiredRecalcVP = true; +} + +// Изменяет чувствительность мыши +void Camera::setSensitivity(float sens) +{ + sensitivity = sens; +} diff --git a/src/Model.cpp b/src/Model.cpp new file mode 100644 index 0000000..650a144 --- /dev/null +++ b/src/Model.cpp @@ -0,0 +1,97 @@ +#include "Model.h" +#include "Camera.h" +extern Camera camera; + +// Конструктор без параметров +Model::Model() : verteces_count(0), indices_count(0), vertex_vbo(VERTEX), index_vbo(ELEMENT), position(0), rotation(0), scale(1) +{ + +} + +// Конструктор копирования +Model::Model(const Model& copy) : vao(copy.vao), verteces_count(copy.verteces_count), indices_count(copy.indices_count), vertex_vbo(copy.vertex_vbo), index_vbo(copy.index_vbo), position(copy.position), rotation(copy.rotation), scale(copy.scale) +{ + +} + +Model::~Model() +{ + +} + +// Вызов отрисовки +void Model::render(const GLuint &mvp_uniform) +{ + // Расчитаем матрицу трансформации + glm::mat4 mvp = camera.getVP() * this->getTransformMatrix(); + glUniformMatrix4fv(mvp_uniform, 1, GL_FALSE, &mvp[0][0]); + + // Подключаем VAO + vao.use(); + // Если есть индексы - рисуем с их использованием + if (indices_count) + glDrawElements(GL_TRIANGLES, indices_count, GL_UNSIGNED_INT, (void*)0); + // Если есть вершины - рисуем на основании массива вершин + else if (verteces_count) + glDrawArrays(GL_TRIANGLES, 0, verteces_count); +} + +// Функция для конфигурации атрибута вершинного буфера +void vertex_attrib_config() +{ + // Включаем необходимый атрибут у выбранного VAO + glEnableVertexAttribArray(0); + // Устанавливаем связь между VAO и привязанным VBO + glVertexAttribPointer( 0 // индекс атрибута, должен совпадать с Layout шейдера + , 3 // количество компонент одного элемента + , GL_FLOAT // тип + , GL_FALSE // нормализованность значений + , 0 // шаг + , (void *)0 // отступ с начала массива + ); +} + +// Загрузка вершин в буфер +void Model::load_verteces(glm::vec3* verteces, GLuint count) +{ + // Подключаем VAO и вершинный буфер + vao.use(); + vertex_vbo.use(); + + // Загрузка вершин в память буфера + vertex_vbo.load(verteces, sizeof(glm::vec3)*count); + vertex_attrib_config(); + // Запоминаем количество вершин для отрисовки + verteces_count = count; +} + +// Загрузка индексов в буфер +void Model::load_indices(GLuint* indices, GLuint count) +{ + // Подключаем VAO и индексный буфер + vao.use(); + index_vbo.use(); + + // Загрузка вершин в память буфера + index_vbo.load(indices, sizeof(GLuint)*count); + // Запоминаем количество вершин для отрисовки + indices_count = count; +} + +#include + +// Матрица трансформации модели +glm::mat4 Model::getTransformMatrix() +{ + glm::mat4 transformMatrix = glm::mat4(1.0f); + // Перемещение модели + transformMatrix = glm::translate(transformMatrix, position); + // Поворот модели + transformMatrix = glm::rotate(transformMatrix, glm::radians(rotation.x), glm::vec3(1.0, 0.0, 0.0)); + transformMatrix = glm::rotate(transformMatrix, glm::radians(rotation.y), glm::vec3(0.0, 1.0, 0.0)); + transformMatrix = glm::rotate(transformMatrix, glm::radians(rotation.z), glm::vec3(0.0, 0.0, 1.0)); + // Масштабирование + transformMatrix = glm::scale(transformMatrix, scale); + + return transformMatrix; +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..427d25a --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,235 @@ + +#include +#include +#include + +#include + +#include "Camera.h" +#include "Model.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; +} + + +Camera camera(800.0f/600.0f); + +bool firstMouse = true; +float lastX, lastY; + +void mouse_callback(GLFWwindow* window, double xpos, double ypos) +{ + if (firstMouse) + { + lastX = xpos; + lastY = ypos; + firstMouse = false; + } + + glm::vec2 offset(xpos - lastX, lastY - ypos); + lastX = xpos; + lastY = ypos; + + camera.rotate(offset); +} + +int main(void) +{ + GLFWwindow* window; // Указатель на окно GLFW3 + + // Инициализация GLFW3 + if (!glfwInit()) + { + std::cout << "GLFW init error\n"; + return -1; + } + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // Мажорная версия спецификаций OpenGL + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); // Минорная версия спецификаций 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); // Вертикальная синхронизация + + // Установка callback-функции для мыши и камеры + glfwSetCursorPosCallback(window, mouse_callback); + + // Загрузка функций 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} + }; + // Модель прямоугольника + Model rectangle; + + // Загрузка вершин модели + rectangle.load_verteces(verticies, sizeof(verticies)/sizeof(glm::vec3)); + + // индексы вершин + GLuint indices[] = {0, 1, 2, 2, 3, 0}; + + // Загрузка индексов модели + rectangle.load_indices(indices, sizeof(indices)); + + rectangle.position.z = 2; + rectangle.rotation = glm::vec3(45); + + // Установка цвета очистки буфера цвета + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + + // Расположение Uniform-переменной + GLuint mvp_uniform = glGetUniformLocation(shaderProgram, "mvp"); + + // Пока не произойдет событие запроса закрытия окна + while(!glfwWindowShouldClose(window)) + { + // Очистка буфера цвета + glClear(GL_COLOR_BUFFER_BIT); + + // Тут производится рендер + rectangle.render(mvp_uniform); + + // Представление содержимого буфера цепочки показа на окно + glfwSwapBuffers(window); + // Обработка системных событий + glfwPollEvents(); + } + + // Удаление шейдерной программы + glDeleteProgram(shaderProgram); + + // Отключение атрибутов + glDisableVertexAttribArray(0); + + // Завершение работы с GLFW3 перед выходом + glfwTerminate(); +}