Копия с проекта 05
This commit is contained in:
parent
b70020a6c3
commit
a2898c2203
20
.vscode/c_cpp_properties.json
vendored
Normal file
20
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "some_name",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/include",
|
||||
"${workspaceFolder}/../dependencies/GLFW/include",
|
||||
"${workspaceFolder}/../dependencies/glad/include",
|
||||
"${workspaceFolder}/../dependencies/glm",
|
||||
"${workspaceFolder}/../dependencies/stb",
|
||||
"${workspaceFolder}/../dependencies/tinyobjloader"
|
||||
],
|
||||
"compilerPath": "C:/MinGW/bin/g++.exe",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++11",
|
||||
"intelliSenseMode": "gcc-x86"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
48
.vscode/settings.json
vendored
Normal file
48
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"fstream": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"map": "cpp",
|
||||
"atomic": "cpp",
|
||||
"new": "cpp",
|
||||
"array": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"random": "cpp",
|
||||
"string": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp"
|
||||
}
|
||||
}
|
79
.vscode/tasks.json
vendored
Normal file
79
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
{
|
||||
"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",
|
||||
"-I${workspaceFolder}/../dependencies/stb",
|
||||
"-I${workspaceFolder}/../dependencies/tinyobjloader",
|
||||
"-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",
|
||||
"-I${workspaceFolder}/../dependencies/stb",
|
||||
"-I${workspaceFolder}/../dependencies/tinyobjloader",
|
||||
"-static",
|
||||
"-lopengl32",
|
||||
"-lglfw3dll",
|
||||
"-o",
|
||||
"${workspaceRoot}/${workspaceFolderBasename}.exe"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${fileDirname}"
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"detail": "Задача создана отладчиком."
|
||||
}
|
||||
],
|
||||
"version": "2.0.0"
|
||||
}
|
45
include/Buffers.h
Normal file
45
include/Buffers.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef BUFFERS_H
|
||||
#define BUFFERS_H
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
|
||||
|
||||
// Объект массива вершин
|
||||
class VAO
|
||||
{
|
||||
public:
|
||||
VAO(); // Создает VAO и активирует его
|
||||
~VAO(); // Уничтожает VAO
|
||||
|
||||
void use(); // Активация VAO
|
||||
static void disable(); // Деактивация активного VAO
|
||||
|
||||
GLuint get_handler(); // возвращает дескриптор
|
||||
|
||||
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
|
49
include/Camera.h
Normal file
49
include/Camera.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef CAMERA_H
|
||||
#define CAMERA_H
|
||||
|
||||
#include <GLM/glm.hpp>
|
||||
|
||||
// Ближняя граница области отсечения
|
||||
#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
|
59
include/Model.h
Normal file
59
include/Model.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef MODEL_H
|
||||
#define MODEL_H
|
||||
|
||||
#include "Buffers.h"
|
||||
#include "Texture.h"
|
||||
|
||||
#include <GLM/glm.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define DEFAULT_MTL_DIR "./"
|
||||
class GrouptedModel loadOBJtoGroupted(const char* filename, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR);
|
||||
|
||||
// Класс определяющий положение, вращение и размер объекта
|
||||
class Movable
|
||||
{
|
||||
public:
|
||||
Movable(); // Конструктор без параметров
|
||||
Movable(const Movable& copy); // Конструктор копирования
|
||||
|
||||
glm::vec3 position; // позиция модели
|
||||
glm::vec3 rotation; // поворот модели
|
||||
glm::vec3 scale; // масштабирование модели
|
||||
glm::mat4 getTransformMatrix(); // Матрица трансформации модели
|
||||
};
|
||||
|
||||
// Класс модели с примененным материалом
|
||||
class Model : public Movable
|
||||
{
|
||||
public:
|
||||
Model(); // Конструктор без параметров
|
||||
Model(const Model& copy); // Конструктор копирования
|
||||
~Model();
|
||||
void render(const GLuint &mvp_uniform, const glm::mat4& global_tranform = glm::mat4(1)); // Вызов отрисовки
|
||||
void load_verteces(glm::vec3* verteces, GLuint count); // Загрузка вершин в буфер
|
||||
void load_indices(GLuint* indices, GLuint count); // Загрузка индексов в буфер
|
||||
void load_texCoords(glm::vec2* texCoords, GLuint count); // Загрузка текстурных координат в буфер
|
||||
void load_normals(glm::vec3* normals, GLuint count); // Загрузка нормалей в буфер
|
||||
void set_texture(Texture& texture); // Привязка текстуры к модели
|
||||
void set_index_range(GLuint beg, GLuint count); // Ограничение диапазона из буфера индексов
|
||||
|
||||
private:
|
||||
VAO *vao;
|
||||
VBO *vertex_vbo, *index_vbo; // вершинный и индексный
|
||||
VBO *normals_vbo, *texCoords_vbo; // буферы с нормалями и текстурными координатами
|
||||
GLuint verteces_count; // Количество вершин
|
||||
GLuint first_index, indices_count; // Первый и количество индексов
|
||||
Texture texture_diffuse; // Диффузная текстура
|
||||
};
|
||||
|
||||
// Класс сгруппированной модели
|
||||
class GrouptedModel: public Movable
|
||||
{
|
||||
public:
|
||||
void render(const GLuint &mvp_uniform); // Вызов отрисовки
|
||||
std::vector<Model> parts;
|
||||
};
|
||||
|
||||
#endif // MODEL_H
|
34
include/Texture.h
Normal file
34
include/Texture.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef TEXTURE_H
|
||||
#define TEXTURE_H
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
enum TexType {
|
||||
TEX_DIFFUSE,
|
||||
TEX_AVAILABLE_COUNT
|
||||
};
|
||||
|
||||
class Texture
|
||||
{
|
||||
public:
|
||||
Texture(GLuint type = TEX_AVAILABLE_COUNT, const std::string& filename = ""); // Загрузка текстуры с диска или использование "пустой"
|
||||
Texture(const Texture& other); // Конструктор копирования
|
||||
~Texture();
|
||||
|
||||
Texture& operator=(const Texture& other); // Оператор присваивания
|
||||
|
||||
static void init_textures(GLuint programID); // Инициализация текстур на шейдере
|
||||
void use(); // Привязка текстуры
|
||||
static void disable(GLuint type); // Отвязка текстуры по типу
|
||||
GLuint getType(); // Возвращает тип текстуры
|
||||
private:
|
||||
GLuint handler; // Дескриптор текстуры
|
||||
GLuint type; // Тип текстуры, соответствует её слоту
|
||||
static std::map<std::string, int> filename_handler; // Получение дескриптора текстуры по её имени
|
||||
static std::map<int, int> handler_count; // Получение количества использований по дескриптору текстуры (Shared pointer)
|
||||
};
|
||||
|
||||
#endif // TEXTURE_H
|
13
shaders/shader.frag
Normal file
13
shaders/shader.frag
Normal file
@ -0,0 +1,13 @@
|
||||
#version 330 core
|
||||
|
||||
in vec2 texCoord;
|
||||
|
||||
uniform sampler2D tex_diffuse;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
void main()
|
||||
{
|
||||
color = texture(tex_diffuse, texCoord);
|
||||
}
|
||||
|
15
shaders/shader.vert
Normal file
15
shaders/shader.vert
Normal file
@ -0,0 +1,15 @@
|
||||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec3 pos;
|
||||
layout(location = 1) in vec2 inTexCoord;
|
||||
layout(location = 2) in vec3 normals;
|
||||
|
||||
uniform mat4 mvp;
|
||||
|
||||
out vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = mvp * vec4(pos, 1.0);
|
||||
texCoord = inTexCoord;
|
||||
}
|
65
src/Buffers.cpp
Normal file
65
src/Buffers.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#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
|
||||
}
|
||||
|
||||
// возвращает дескриптор
|
||||
GLuint VAO::get_handler()
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
|
||||
// Создает пустой буфер, привязывает к активному 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); // Привязка элементного буфера
|
||||
}
|
141
src/Camera.cpp
Normal file
141
src/Camera.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
#include "Camera.h"
|
||||
|
||||
#include <GLM/gtc/matrix_transform.hpp>
|
||||
#include <GLM/ext/matrix_transform.hpp>
|
||||
|
||||
// Защищенный (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;
|
||||
}
|
355
src/Model.cpp
Normal file
355
src/Model.cpp
Normal file
@ -0,0 +1,355 @@
|
||||
#include "Model.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "Camera.h"
|
||||
extern Camera camera;
|
||||
|
||||
// Словарь для хранения количества моделей, использующих общие VAO
|
||||
std::map<GLuint, GLuint> vaos_count;
|
||||
|
||||
// Конструктор без параметров
|
||||
Movable::Movable() : position(0), rotation(0), scale(1) {}
|
||||
// Конструктор копирования
|
||||
Movable::Movable(const Movable& copy) : position(copy.position), rotation(copy.rotation), scale(copy.scale) {}
|
||||
|
||||
// Конструктор без параметров
|
||||
Model::Model() :
|
||||
verteces_count(0), first_index(0), indices_count(0),
|
||||
vertex_vbo(0), index_vbo(0), normals_vbo(0), texCoords_vbo(0)
|
||||
{
|
||||
// Создаем новый буфер
|
||||
vao = new VAO();
|
||||
// Запоминаем, что для нового VAO количество моделей, использующих его, = 1
|
||||
vaos_count[vao->get_handler()] = 1;
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
Model::Model(const Model& copy) :
|
||||
vao(copy.vao),
|
||||
verteces_count(copy.verteces_count), first_index(copy.first_index), indices_count(copy.indices_count),
|
||||
vertex_vbo(copy.vertex_vbo), index_vbo(copy.index_vbo), normals_vbo(copy.normals_vbo), texCoords_vbo(copy.texCoords_vbo),
|
||||
texture_diffuse(copy.texture_diffuse)
|
||||
{
|
||||
// Если создается копия модели, то запоминаем поля и инкрементируем словарь с количеством
|
||||
vaos_count[vao->get_handler()]++;
|
||||
}
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
// При уничтожении модели проверяем: если это последний пользователь меша, то осовобождаем из под него память
|
||||
if (--vaos_count[vao->get_handler()] < 1)
|
||||
{
|
||||
if (vertex_vbo)
|
||||
delete vertex_vbo;
|
||||
if (index_vbo)
|
||||
delete index_vbo;
|
||||
if (texCoords_vbo)
|
||||
delete texCoords_vbo;
|
||||
if (normals_vbo)
|
||||
delete normals_vbo;
|
||||
delete vao;
|
||||
}
|
||||
}
|
||||
|
||||
// Вызов отрисовки
|
||||
void Model::render(const GLuint &mvp_uniform, const glm::mat4& global_tranform)
|
||||
{
|
||||
// Расчитаем матрицу трансформации
|
||||
glm::mat4 mvp = camera.getVP() * global_tranform * this->getTransformMatrix();
|
||||
glUniformMatrix4fv(mvp_uniform, 1, GL_FALSE, &mvp[0][0]);
|
||||
|
||||
// Подключаем текстуры
|
||||
texture_diffuse.use();
|
||||
|
||||
// Подключаем VAO
|
||||
vao->use();
|
||||
// Если есть индексы - рисуем с их использованием
|
||||
if (indices_count)
|
||||
glDrawElements(GL_TRIANGLES, indices_count, GL_UNSIGNED_INT, (void*)(first_index*sizeof(GLuint)));
|
||||
// Если есть вершины - рисуем на основании массива вершин
|
||||
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();
|
||||
|
||||
// Если до этого такого буфера не было - создаем его, иначе используем
|
||||
if (!vertex_vbo)
|
||||
vertex_vbo = new VBO(VERTEX, vertex_attrib_config);
|
||||
else
|
||||
vertex_vbo->use();
|
||||
|
||||
// Загрузка вершин в память буфера
|
||||
vertex_vbo->load(verteces, sizeof(glm::vec3)*count);
|
||||
// Запоминаем количество вершин для отрисовки
|
||||
verteces_count = count;
|
||||
}
|
||||
|
||||
// Загрузка индексов в буфер
|
||||
void Model::load_indices(GLuint* indices, GLuint count)
|
||||
{
|
||||
// Подключаем VAO
|
||||
vao->use();
|
||||
|
||||
// Если до этого такого буфера не было - создаем его, иначе используем
|
||||
if (!index_vbo)
|
||||
index_vbo = new VBO(ELEMENT);
|
||||
else
|
||||
index_vbo->use();
|
||||
|
||||
// Загрузка вершин в память буфера
|
||||
index_vbo->load(indices, sizeof(GLuint)*count);
|
||||
// Запоминаем количество вершин для отрисовки
|
||||
indices_count = count;
|
||||
}
|
||||
|
||||
// Функция для конфигурации атрибута вершинного буфера
|
||||
void texCoords_attrib_config()
|
||||
{
|
||||
// Включаем необходимый атрибут у выбранного VAO
|
||||
glEnableVertexAttribArray(1);
|
||||
// Устанавливаем связь между VAO и привязанным VBO
|
||||
glVertexAttribPointer( 1 // индекс атрибута, должен совпадать с Layout шейдера
|
||||
, 2 // количество компонент одного элемента
|
||||
, GL_FLOAT // тип
|
||||
, GL_FALSE // нормализованность значений
|
||||
, 0 // шаг
|
||||
, (void *)0 // отступ с начала массива
|
||||
);
|
||||
}
|
||||
|
||||
// Загрузка текстурных координат в буфер
|
||||
void Model::load_texCoords(glm::vec2* texCoords, GLuint count)
|
||||
{
|
||||
// Подключаем VAO
|
||||
vao->use();
|
||||
|
||||
// Если до этого такого буфера не было - создаем его, иначе используем
|
||||
if (!texCoords_vbo)
|
||||
texCoords_vbo = new VBO(VERTEX, texCoords_attrib_config);
|
||||
else
|
||||
texCoords_vbo->use();
|
||||
|
||||
// Загрузка вершин в память буфера
|
||||
texCoords_vbo->load(texCoords, sizeof(glm::vec2)*count);
|
||||
|
||||
}
|
||||
|
||||
// Функция для конфигурации атрибута вершинного буфера
|
||||
void normals_attrib_config()
|
||||
{
|
||||
// Включаем необходимый атрибут у выбранного VAO
|
||||
glEnableVertexAttribArray(2);
|
||||
// Устанавливаем связь между VAO и привязанным VBO
|
||||
glVertexAttribPointer( 2 // индекс атрибута, должен совпадать с Layout шейдера
|
||||
, 3 // количество компонент одного элемента
|
||||
, GL_FLOAT // тип
|
||||
, GL_FALSE // нормализованность значений
|
||||
, 0 // шаг
|
||||
, (void *)0 // отступ с начала массива
|
||||
);
|
||||
}
|
||||
|
||||
// Загрузка нормалей в буфер
|
||||
void Model::load_normals(glm::vec3* normals, GLuint count)
|
||||
{
|
||||
// Подключаем VAO
|
||||
vao->use();
|
||||
|
||||
// Если до этого такого буфера не было - создаем его, иначе используем
|
||||
if (!normals_vbo)
|
||||
normals_vbo = new VBO(VERTEX, normals_attrib_config);
|
||||
else
|
||||
normals_vbo->use();
|
||||
|
||||
// Загрузка вершин в память буфера
|
||||
normals_vbo->load(normals, sizeof(glm::vec3)*count);
|
||||
|
||||
}
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
// Матрица трансформации модели
|
||||
glm::mat4 Movable::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;
|
||||
}
|
||||
|
||||
// Привязка текстуры к модели
|
||||
void Model::set_texture(Texture& texture)
|
||||
{
|
||||
GLuint type = texture.getType();
|
||||
switch(type)
|
||||
{
|
||||
case TEX_DIFFUSE:
|
||||
texture_diffuse = texture;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
// Ограничение диапазона из буфера индексов
|
||||
void Model::set_index_range(GLuint beg, GLuint count)
|
||||
{
|
||||
first_index = beg;
|
||||
indices_count = count;
|
||||
}
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "tiny_obj_loader.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
inline void hash_combine(std::size_t& seed) { }
|
||||
|
||||
template <typename T, typename... Rest>
|
||||
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
hash_combine(seed, rest...);
|
||||
}
|
||||
|
||||
GrouptedModel loadOBJtoGroupted(const char* filename, const char* mtl_directory, const char* texture_directory)
|
||||
{
|
||||
GrouptedModel result;
|
||||
Model model;
|
||||
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
|
||||
std::string err;
|
||||
|
||||
// Если в процессе загрузки возникли ошибки - выдадим исключение
|
||||
if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, mtl_directory))
|
||||
throw std::runtime_error(err);
|
||||
|
||||
std::vector<GLuint> indices; // индексы модели
|
||||
std::vector<glm::vec3> verteces; // вершины
|
||||
std::vector<glm::vec3> normals; // нормали
|
||||
std::vector<glm::vec2> texCords; // текстурные координаты
|
||||
size_t hash; // Для уникальных вершин
|
||||
std::map <int, int> uniqueVerteces; // словарь для уникальных вершин: ключ - хеш, значение - индекс вершины
|
||||
|
||||
int last_material_index = 0; // индекс последнего материала (для группировки моделей)
|
||||
int count = 0, offset; // для индексов начала и конца в индексном буфере
|
||||
std::vector<int> materials_range; // хранилище индексов
|
||||
std::vector<int> materials_ids; // индексы материалов
|
||||
|
||||
materials_range.push_back(count); // Закидываем начало отрезка в индексном буфере
|
||||
// Цикл по считанным моделям
|
||||
for (const auto& shape : shapes)
|
||||
{
|
||||
offset = count; // Переменная для
|
||||
last_material_index = shape.mesh.material_ids[(count - offset)/3]; // Запоминаем индекс материала
|
||||
|
||||
// Цикл по индексам модели
|
||||
for (const auto& index : shape.mesh.indices)
|
||||
{
|
||||
hash = 0;
|
||||
hash_combine( hash
|
||||
, attrib.vertices[3 * index.vertex_index + 0], attrib.vertices[3 * index.vertex_index + 1], attrib.vertices[3 * index.vertex_index + 2]
|
||||
, attrib.normals[3 * index.normal_index + 0], attrib.normals[3 * index.normal_index + 1], attrib.normals[3 * index.normal_index + 2]
|
||||
, attrib.texcoords[2 * index.texcoord_index + 0], attrib.texcoords[2 * index.texcoord_index + 1]);
|
||||
|
||||
if (!uniqueVerteces.count(hash))
|
||||
{
|
||||
uniqueVerteces[hash] = verteces.size();
|
||||
|
||||
// группируем вершины в массив на основании индексов
|
||||
verteces.push_back({ attrib.vertices[3 * index.vertex_index + 0]
|
||||
, attrib.vertices[3 * index.vertex_index + 1]
|
||||
, attrib.vertices[3 * index.vertex_index + 2]
|
||||
});
|
||||
// группируем нормали в массив на основании индексов
|
||||
normals.push_back({ attrib.normals[3 * index.normal_index + 0]
|
||||
, attrib.normals[3 * index.normal_index + 1]
|
||||
, attrib.normals[3 * index.normal_index + 2]
|
||||
});
|
||||
// группируем текстурные координаты в массив на основании индексов
|
||||
texCords.push_back({ attrib.texcoords[2 * index.texcoord_index + 0]
|
||||
, 1-attrib.texcoords[2 * index.texcoord_index + 1]
|
||||
});
|
||||
}
|
||||
// Сохраняем индекс в массив
|
||||
indices.push_back(uniqueVerteces[hash]);
|
||||
|
||||
// Если индекс последнего материала изменился, то необходимо сохранить его
|
||||
if (last_material_index != shape.mesh.material_ids[(count - offset)/3])
|
||||
{
|
||||
materials_range.push_back(count); // как конец отрезка
|
||||
materials_ids.push_back(last_material_index); // как используемый материал
|
||||
last_material_index = shape.mesh.material_ids[(count - offset)/3];
|
||||
}
|
||||
count++;
|
||||
} // for (const auto& index : shape.mesh.indices)
|
||||
|
||||
// Если последний материал не загружен - загружаем его
|
||||
if (materials_range[materials_range.size()-1] != count-1)
|
||||
{
|
||||
materials_range.push_back(count); // последний конец отрезка
|
||||
materials_ids.push_back(last_material_index); // последний используемый материал
|
||||
}
|
||||
} // for (const auto& shape : shapes)
|
||||
|
||||
|
||||
|
||||
// Загрузка в буферы
|
||||
model.load_verteces (&verteces[0], verteces.size());
|
||||
model.load_normals (&normals[0], normals.size());
|
||||
model.load_texCoords(&texCords[0], texCords.size());
|
||||
// Загрузка индексного буфера
|
||||
model.load_indices (&indices[0], indices.size());
|
||||
|
||||
|
||||
// Создаем копии модели, которые будут рендериться в заданном диапазоне
|
||||
// И присваиваем текстуры копиям на основании материала
|
||||
for (int i = 0; i < materials_range.size()-1; i++)
|
||||
{
|
||||
result.parts.push_back(model); // Создание копии с общим VAO
|
||||
auto s = --result.parts.end();
|
||||
s->set_index_range(materials_range[i], materials_range[i+1]-materials_range[i]);
|
||||
|
||||
Texture diffuse(TEX_DIFFUSE, texture_directory + materials[materials_ids[i]].diffuse_texname);
|
||||
s->set_texture(diffuse);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Вызов отрисовки групповой модели
|
||||
void GrouptedModel::render(const GLuint &mvp_uniform)
|
||||
{
|
||||
glm::mat4 transform = this->getTransformMatrix();
|
||||
for (auto& model : parts)
|
||||
model.render(mvp_uniform, transform);
|
||||
}
|
129
src/Texture.cpp
Normal file
129
src/Texture.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
#include "Texture.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
std::map<std::string, int> Texture::filename_handler; // Получение дескриптора текстуры по её имени
|
||||
std::map<int, int> Texture::handler_count; // Получение количества использований по дескриптору текстуры (Shared pointer)
|
||||
|
||||
// Загрузка текстуры с диска или использование "пустой"
|
||||
Texture::Texture(GLuint t, const std::string& filename) : type(t)
|
||||
{
|
||||
if (!filename_handler.count(filename))
|
||||
{
|
||||
std::string empty = "";
|
||||
int width, height, channels; // Ширина, высота и цветовые каналы текстуры
|
||||
unsigned char* image = stbi_load(filename.c_str(), &width, &height, &channels, STBI_default); // Загрузка в оперативную память изображения
|
||||
// Если изображение успешно счиитано с диска или отсутствует пустая текстура
|
||||
if (image || !filename_handler.count(empty))
|
||||
{
|
||||
glActiveTexture(type + GL_TEXTURE0);
|
||||
glGenTextures(1, &handler); // Генерация одной текстуры
|
||||
glBindTexture(GL_TEXTURE_2D, handler); // Привязка текстуры как активной
|
||||
|
||||
filename_handler[filename] = handler; // Запоминим её дескриптор для этого имени файла
|
||||
handler_count[handler] = 0; // Создадим счетчик использований дескриптора, который будет изменен в конце
|
||||
|
||||
// Если изображение успешно считано
|
||||
if (image)
|
||||
{
|
||||
// Загрузка данных с учетом прозрачности
|
||||
if (channels == 3) // RGB
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
|
||||
else if (channels == 4) // RGBA
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D); // Генерация мипмапа для активной текстуры
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Отвязка активной текстуры
|
||||
|
||||
stbi_image_free(image); // Освобождение оперативной памяти
|
||||
}
|
||||
// Иначе изображение не считано и надо создать пустую текстуру
|
||||
else
|
||||
{
|
||||
image = new unsigned char[3] {255,255,255}; // RGB по 1 байту на
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, image); // Загрузка данных на видеокарту
|
||||
delete image; // Освобождение оперативной памяти
|
||||
|
||||
filename_handler[empty] = handler; // Запоминим дополнительно её дескриптор для NULL-строки
|
||||
}
|
||||
}
|
||||
// Иначе используем существующую пустую текстуру (текстура не загружена, пустую создавать не нужно)
|
||||
else
|
||||
handler = filename_handler[empty];
|
||||
}
|
||||
// Иначе используем уже существующую по имени файла
|
||||
else
|
||||
handler = filename_handler[filename];
|
||||
|
||||
handler_count[handler]++;
|
||||
}
|
||||
|
||||
// Конструктор копирования
|
||||
Texture::Texture(const Texture& other) : handler(other.handler), type(other.type)
|
||||
{
|
||||
// Делаем копию и увеличиваем счетчик
|
||||
handler_count[handler]++;
|
||||
}
|
||||
|
||||
// Оператор присваивания
|
||||
Texture& Texture::operator=(const Texture& other)
|
||||
{
|
||||
// Если это разные текстуры
|
||||
if (handler != other.handler)
|
||||
{
|
||||
this->~Texture(); // Уничтожаем имеющуюся
|
||||
// Заменяем новой
|
||||
handler = other.handler;
|
||||
handler_count[handler]++;
|
||||
}
|
||||
type = other.type;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Texture::~Texture()
|
||||
{
|
||||
if (!--handler_count[handler]) // Если количество ссылок = 0
|
||||
{
|
||||
glDeleteTextures(1, &handler); // Удаление текстуры
|
||||
// Удаление из словаря имен файлов и дескрипторов
|
||||
for (auto it = filename_handler.begin(); it != filename_handler.end();)
|
||||
{
|
||||
if (it->second == handler)
|
||||
it = filename_handler.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* textures_base_shader_names[] = {"tex_diffuse"};
|
||||
|
||||
// Инициализация текстур на шейдере
|
||||
void Texture::init_textures(GLuint programID)
|
||||
{
|
||||
// Цикл по всем доступным текстурам
|
||||
for (int i = 0; i < TEX_AVAILABLE_COUNT; i++)
|
||||
glUniform1i(glGetUniformLocation(programID, textures_base_shader_names[i]), i);
|
||||
}
|
||||
|
||||
// Привязка текстуры
|
||||
void Texture::use()
|
||||
{
|
||||
glActiveTexture(type + GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, handler); // Привязка текстуры как активной
|
||||
}
|
||||
|
||||
// Отвязка текстуры по типу
|
||||
void Texture::disable(GLuint type)
|
||||
{
|
||||
glActiveTexture(type + GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Отвязка текстуры
|
||||
}
|
||||
|
||||
// Возвращает тип текстуры
|
||||
GLuint Texture::getType()
|
||||
{
|
||||
return type;
|
||||
}
|
226
src/main.cpp
Normal file
226
src/main.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLM/glm.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "Camera.h"
|
||||
#include "Model.h"
|
||||
#include "Texture.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 <fstream>
|
||||
#include <sstream>
|
||||
|
||||
// Функция чтения шейдера из файла
|
||||
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;
|
||||
}
|
||||
|
||||
// Включаем проверку по буферу глубины
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
// Компиляция шейдеров
|
||||
GLuint shaderProgram = LoadShaders("shaders/shader.vert", "shaders/shader.frag");
|
||||
// Активация шейдера
|
||||
glUseProgram(shaderProgram);
|
||||
// Установим значения текстур
|
||||
Texture::init_textures(shaderProgram);
|
||||
// camera.move({0,0,-20});
|
||||
|
||||
// Загрузка сцены из obj файла
|
||||
GrouptedModel scene = loadOBJtoGroupted("../resources/models/cubes.obj", "../resources/models/", "../resources/textures/");
|
||||
|
||||
// Установка цвета очистки буфера цвета
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Расположение Uniform-переменной
|
||||
GLuint mvp_uniform = glGetUniformLocation(shaderProgram, "mvp");
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Использование уменьшенных версий mipmap
|
||||
|
||||
// Пока не произойдет событие запроса закрытия окна
|
||||
while(!glfwWindowShouldClose(window))
|
||||
{
|
||||
// Очистка буфера цвета
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Тут производится рендер
|
||||
scene.render(mvp_uniform);
|
||||
|
||||
// Представление содержимого буфера цепочки показа на окно
|
||||
glfwSwapBuffers(window);
|
||||
// Обработка системных событий
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
// Удаление шейдерной программы
|
||||
glDeleteProgram(shaderProgram);
|
||||
|
||||
// Отключение атрибутов
|
||||
glDisableVertexAttribArray(0);
|
||||
|
||||
// Завершение работы с GLFW3 перед выходом
|
||||
glfwTerminate();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user