Копия проекта с 07
This commit is contained in:
		
							parent
							
								
									5e846c951c
								
							
						
					
					
						commit
						6de0a3af8d
					
				
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
{
 | 
			
		||||
    "files.associations": {
 | 
			
		||||
        "fstream": "cpp",
 | 
			
		||||
        "iosfwd": "cpp",
 | 
			
		||||
        "map": "cpp",
 | 
			
		||||
        "atomic": "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"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
{
 | 
			
		||||
    "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"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,101 @@
 | 
			
		||||
# Компилятор и директория проекта
 | 
			
		||||
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
 | 
			
		||||
CFLAGS += -I./include
 | 
			
		||||
CFLAGS += -I../dependencies/GLFW/include
 | 
			
		||||
CFLAGS += -I../dependencies/glad/include
 | 
			
		||||
CFLAGS += -I../dependencies/glm
 | 
			
		||||
CFLAGS += -I../dependencies/stb
 | 
			
		||||
CFLAGS += -I../dependencies/tinyobjloader
 | 
			
		||||
 | 
			
		||||
# Опции линкера
 | 
			
		||||
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
 | 
			
		||||
							
								
								
									
										62
									
								
								include/Buffers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								include/Buffers.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
#ifndef BUFFERS_H
 | 
			
		||||
#define BUFFERS_H
 | 
			
		||||
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
// Объект массива вершин
 | 
			
		||||
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<GLuint, GLuint> handler_count; // Счетчик использований дескриптора
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Тип буфера
 | 
			
		||||
enum BUFFER_TYPE {  VERTEX = GL_ARRAY_BUFFER
 | 
			
		||||
                  , ELEMENT = GL_ELEMENT_ARRAY_BUFFER
 | 
			
		||||
                  , UNIFORM = GL_UNIFORM_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<GLuint, GLuint> handler_count; // Счетчик использований дескриптора
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Объект uniform-буфера
 | 
			
		||||
class UBO : public BO
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        UBO(int size, int binding); // Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | 
			
		||||
        UBO(const void *data, int size, int binding); // Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | 
			
		||||
 | 
			
		||||
        void rebind(int binding); // Перепривязка
 | 
			
		||||
        void loadSub(const void *data, int size, int offset = 0); // Загрузка с отступом
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // BUFFERS_H
 | 
			
		||||
							
								
								
									
										73
									
								
								include/Camera.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								include/Camera.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
			
		||||
#ifndef CAMERA_H
 | 
			
		||||
#define CAMERA_H
 | 
			
		||||
 | 
			
		||||
#include <GLM/glm.hpp>
 | 
			
		||||
#include <GLM/gtx/euler_angles.hpp>
 | 
			
		||||
#include <GLM/gtc/matrix_transform.hpp>
 | 
			
		||||
#include <GLM/ext/matrix_transform.hpp>
 | 
			
		||||
 | 
			
		||||
#include "Model.h"
 | 
			
		||||
 | 
			
		||||
// Ближняя граница области отсечения
 | 
			
		||||
#define CAMERA_NEAR 0.1f
 | 
			
		||||
// Дальняя граница области отсечения
 | 
			
		||||
#define CAMERA_FAR 100.0f
 | 
			
		||||
// Вектор, задающий верх для камеры
 | 
			
		||||
#define CAMERA_UP_VECTOR glm::vec3(0.0f, 1.0f, 0.0f)
 | 
			
		||||
// Вектор, задающий стандартный поворот углами Эйлера (в положительном направлении оси Z)
 | 
			
		||||
#define CAMERA_DEFAULT_ROTATION glm::vec3(0.0f, 180.0f, 0.0f)
 | 
			
		||||
// Стандартный угол обзора 
 | 
			
		||||
#define CAMERA_FOVy 60.0f
 | 
			
		||||
// Стандартная чувствительность
 | 
			
		||||
#define CAMERA_DEFAULT_SENSIVITY 0.005f
 | 
			
		||||
 | 
			
		||||
// Данные о камере для шейдера
 | 
			
		||||
struct CameraData
 | 
			
		||||
{
 | 
			
		||||
    glm::mat4 projection;
 | 
			
		||||
    glm::mat4 view;
 | 
			
		||||
    glm::vec3 position;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Класс камеры
 | 
			
		||||
class Camera : public Node
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        Camera(float aspect, const glm::vec3 &position = glm::vec3(0.0f), const glm::vec3 &initialRotation = CAMERA_DEFAULT_ROTATION, float fovy = CAMERA_FOVy); // Конструктор камеры с проекцией перспективы
 | 
			
		||||
        Camera(float width, float height, const glm::vec3 &position = glm::vec3(0.0f), const glm::vec3 &initialRotation = CAMERA_DEFAULT_ROTATION); // Конструктор ортографической камеры
 | 
			
		||||
        Camera(const Camera& copy); // Конструктор копирования камеры
 | 
			
		||||
        Camera& operator=(const Camera& other); // Оператор присваивания
 | 
			
		||||
        virtual ~Camera(); // Деструктор
 | 
			
		||||
 | 
			
		||||
        const glm::mat4& getVP(); // Возвращает ссылку на константную матрицу произведения матриц вида и проекции
 | 
			
		||||
        const glm::mat4& getProjection(); // Возвращает ссылку на константную матрицу проекции 
 | 
			
		||||
        const glm::mat4& getView(); // Возвращает ссылку на константную матрицу вида
 | 
			
		||||
        
 | 
			
		||||
        void rotate(const glm::vec2 &xyOffset); // Поворачивает камеру на dx и dy пикселей с учетом чувствительности
 | 
			
		||||
        
 | 
			
		||||
        void setPerspective(float fov, float aspect); // Устанавливает заданную матрицу перспективы
 | 
			
		||||
        void setOrtho(float width, float height); // Устанавливает заданную ортографическую матрицу
 | 
			
		||||
        void setSensitivity(float sensitivity); // Изменяет чувствительность мыши
 | 
			
		||||
        const float& getSensitivity() const; // Возвращает чувствительность мыши
 | 
			
		||||
        
 | 
			
		||||
        void use(); // Использование этой камеры как текущей
 | 
			
		||||
        static Camera& current(); // Ссылка на текущую используемую камеру
 | 
			
		||||
        
 | 
			
		||||
        CameraData& getData(); // Данные о камере для шейдера
 | 
			
		||||
    protected:
 | 
			
		||||
        Camera(const glm::vec3 &position, const glm::vec3 &initialRotation); // Защищенный (protected) конструктор камеры без перспективы 
 | 
			
		||||
 | 
			
		||||
        glm::mat4 view; // Матрица вида
 | 
			
		||||
        glm::mat4 projection; // Матрица проекции
 | 
			
		||||
        glm::mat4 vp; // Матрица произведения вида и проекции
 | 
			
		||||
        bool requiredRecalcVP; // Необходимость пересчета матрицы вида и проекции камеры
 | 
			
		||||
        
 | 
			
		||||
        float sensitivity; // Чувствительность мыши
 | 
			
		||||
        
 | 
			
		||||
        virtual void recalcMatrices(); // Метод пересчета матрицы вида и произведения Вида*Проекции по необходимости, должен сбрасывать флаг changed
 | 
			
		||||
 | 
			
		||||
        static Camera* p_current; // Указатель на текущую используемую камеру
 | 
			
		||||
};      
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // CAMERA_H
 | 
			
		||||
							
								
								
									
										13
									
								
								include/Lights.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								include/Lights.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
#ifndef LIGHTS_H
 | 
			
		||||
#define LIGHTS_H
 | 
			
		||||
 | 
			
		||||
#include <GLM/glm.hpp>
 | 
			
		||||
 | 
			
		||||
// Точечный источник света
 | 
			
		||||
struct LightData 
 | 
			
		||||
{
 | 
			
		||||
    alignas(16) glm::vec3 position; // Позиция
 | 
			
		||||
    alignas(16) glm::vec3 color; // Цвет 
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // LIGHTS_H
 | 
			
		||||
							
								
								
									
										95
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,95 @@
 | 
			
		||||
#ifndef MODEL_H
 | 
			
		||||
#define MODEL_H
 | 
			
		||||
 | 
			
		||||
#include "Buffers.h"
 | 
			
		||||
#include "Texture.h"
 | 
			
		||||
 | 
			
		||||
#include <GLM/glm.hpp>
 | 
			
		||||
#include <GLM/gtc/quaternion.hpp>
 | 
			
		||||
#include <GLM/gtc/matrix_transform.hpp>
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
// Класс узла сцены
 | 
			
		||||
class Node 
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        Node(Node* parent = NULL); // Конструктор с заданным родителем (по умолчанию NULL)
 | 
			
		||||
        Node(const Node& copy); // Конструктор копирования
 | 
			
		||||
        Node& operator=(const Node& other); // Оператор присваивания
 | 
			
		||||
        virtual ~Node();
 | 
			
		||||
 | 
			
		||||
        void setParent(Node * parent); // Устанавливает родителя для узла
 | 
			
		||||
 | 
			
		||||
        virtual const glm::mat4& getTransformMatrix(); // Возвращает матрицу трансформации модели
 | 
			
		||||
        bool isChanged(); // Возвращает необходимость пересчета матрицы трансформации
 | 
			
		||||
 | 
			
		||||
        const glm::vec3& c_position() const; // Константный доступ к позиции
 | 
			
		||||
        const glm::quat& c_rotation() const; // Константный доступ к повороту
 | 
			
		||||
        const glm::vec3& c_scale() const; // Константный доступ к масштабированию
 | 
			
		||||
        virtual glm::vec3& e_position(); // Неконстантная ссылка для изменений позиции
 | 
			
		||||
        virtual glm::quat& e_rotation(); // Неконстантная ссылка для изменений поворота
 | 
			
		||||
        virtual glm::vec3& e_scale(); // Неконстантная ссылка для изменений масштабирования 
 | 
			
		||||
 | 
			
		||||
        Node* getParent(); // Возвращает указатель на родителя
 | 
			
		||||
        const std::vector<Node*>& getChildren() const; // Возвращает ссылку на вектор дочерних узлов
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        Node *parent; // Родительский узел
 | 
			
		||||
        std::vector<Node*> children; // Узлы-потомки !Не должны указывать на NULL!
 | 
			
		||||
 | 
			
		||||
        glm::vec3 position; // позиция модели
 | 
			
		||||
        glm::quat rotation; // поворот модели
 | 
			
		||||
        glm::vec3 scale;    // масштабирование модели
 | 
			
		||||
 | 
			
		||||
        bool changed; // Флаг необходимости пересчета матрицы трансформации
 | 
			
		||||
        glm::mat4 transform; // Матрица трансформации модели
 | 
			
		||||
        bool parent_changed; // Флаг изменений у родителя - необходимость пересчета итоговой трансформации
 | 
			
		||||
        glm::mat4 result_transform; // Итоговая трансформация с учетом родительской
 | 
			
		||||
 | 
			
		||||
        virtual void recalcMatrices(); // Метод пересчета матрицы трансформации по необходимости, должен сбрасывать флаг changed
 | 
			
		||||
        void invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Материал модели
 | 
			
		||||
struct Material
 | 
			
		||||
{
 | 
			
		||||
    alignas(16) glm::vec3 ka; // коэф. фонового отражения (цвет фонового освещения)
 | 
			
		||||
    alignas(16) glm::vec3 kd; // коэф. диффузного отражения (цвет объекта)
 | 
			
		||||
    alignas(16) glm::vec3 ks; // коэф. зеркального блика
 | 
			
		||||
    float p; // показатель глянцевости
 | 
			
		||||
    // Значения по умолчанию
 | 
			
		||||
    Material() : ka(0.2f), kd(0.2f), ks(0.2f), p(1) { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Класс модели
 | 
			
		||||
class Model : public Node
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        Model(Node *parent = NULL); // Конструктор по умолчанию
 | 
			
		||||
        Model(const Model& copy); // Конструктор копирования
 | 
			
		||||
        Model& operator=(const Model& other); // Оператор присваивания
 | 
			
		||||
        virtual ~Model();
 | 
			
		||||
 | 
			
		||||
        void render(const GLuint &model_uniform, UBO &material_buffer); // Вызов отрисовки
 | 
			
		||||
 | 
			
		||||
        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_index_range(size_t first_byteOffset, size_t count); // Ограничение диапазона из буфера индексов
 | 
			
		||||
        void set_texture(Texture& texture); // Привязка текстуры к модели
 | 
			
		||||
        
 | 
			
		||||
        Material material; // Материал модели
 | 
			
		||||
    private:
 | 
			
		||||
        VAO vao;
 | 
			
		||||
        BO vertex_vbo, index_vbo; // вершинный и индексный буферы
 | 
			
		||||
        BO normals_vbo, texCoords_vbo; // буферы с нормалями и текстурными координатами
 | 
			
		||||
        GLuint verteces_count; // Количество вершин
 | 
			
		||||
        size_t first_index_byteOffset, indices_count; // Сдвиг в байтах для первого и количество индексов
 | 
			
		||||
        Texture texture_diffuse; // Диффузная текстура
 | 
			
		||||
        Texture texture_ambient; // Текстура фонового освщения
 | 
			
		||||
        Texture texture_specular; // Текстура зеркального отражения
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // MODEL_H
 | 
			
		||||
							
								
								
									
										37
									
								
								include/Scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								include/Scene.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
#ifndef SCENE_H
 | 
			
		||||
#define SCENE_H
 | 
			
		||||
 | 
			
		||||
#include <list>
 | 
			
		||||
 | 
			
		||||
#include "Model.h"
 | 
			
		||||
#include "Camera.h"
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_MTL_DIR "./"
 | 
			
		||||
class Scene loadOBJtoScene(const char* filename, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR);
 | 
			
		||||
 | 
			
		||||
// Класс сцены
 | 
			
		||||
class Scene
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        Scene(); // Конструктор пустой сцены
 | 
			
		||||
        Scene(const Scene ©); // Конструктор копирования
 | 
			
		||||
        Scene& operator=(const Scene& other); // Оператор присваивания
 | 
			
		||||
 | 
			
		||||
        void render(const GLuint &model_uniform, UBO &material_buffer); // Рендер сцены
 | 
			
		||||
 | 
			
		||||
        Node root; // Корневой узел
 | 
			
		||||
 | 
			
		||||
        // Списки объектов, выступающих узлами
 | 
			
		||||
        std::list<Node> nodes; // Список пустых узлов
 | 
			
		||||
        std::list<Model> models; // Список моделей для рендера
 | 
			
		||||
        std::list<Camera> cameras; // Список камер
 | 
			
		||||
    
 | 
			
		||||
    protected:
 | 
			
		||||
        void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
 | 
			
		||||
        template <class T>
 | 
			
		||||
        void rebuild_Nodes_list(T& nodes, const Scene& from); // Перестройка узлов выбранного списка
 | 
			
		||||
        template <class T>
 | 
			
		||||
        void move_parent(Node& for_node, const std::list<T>& from_nodes, std::list<T>& this_nodes); // Сдвигает родителя узла между двумя списками при условии его принадлежности к оригинальному
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // SCENE_H
 | 
			
		||||
							
								
								
									
										30
									
								
								include/Shader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								include/Shader.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
#ifndef SHADER_H
 | 
			
		||||
#define SHADER_H
 | 
			
		||||
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
// Класс шейдерной программы
 | 
			
		||||
class ShaderProgram
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        ShaderProgram();
 | 
			
		||||
        ShaderProgram(const ShaderProgram ©);
 | 
			
		||||
        ~ShaderProgram();
 | 
			
		||||
        ShaderProgram& operator=(const ShaderProgram& other);
 | 
			
		||||
 | 
			
		||||
        void use(); // Использование шейдеров
 | 
			
		||||
        void load(GLuint type, const char* filename); // Функция для загрузки шейдеров
 | 
			
		||||
        void link(); // Формирование программы из загруженных шейдеров
 | 
			
		||||
        GLuint getUniformLoc(const char* name); // Возвращает местоположение uniform-переменной
 | 
			
		||||
        void bindUniformBlock(const char* name, int binding); // Привязка uniform-блока
 | 
			
		||||
        void bindTextures(const char* textures_base_shader_names[], int count); // Инициализация текстур на шейдере
 | 
			
		||||
    private:
 | 
			
		||||
        GLuint program; // Дескриптор
 | 
			
		||||
        static std::map<int, int> handler_count; // Получение количества использований по дескриптору шейдера (Shared pointer)
 | 
			
		||||
        std::map<const char*, GLuint> uniformLocations; // Местоположения uniform-переменных
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // SHADER_H
 | 
			
		||||
							
								
								
									
										35
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
#ifndef TEXTURE_H
 | 
			
		||||
#define TEXTURE_H
 | 
			
		||||
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
enum TexType {
 | 
			
		||||
    TEX_DIFFUSE,
 | 
			
		||||
    TEX_AMBIENT,
 | 
			
		||||
    TEX_SPECULAR,
 | 
			
		||||
    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); // Оператор присваивания
 | 
			
		||||
 | 
			
		||||
        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
 | 
			
		||||
							
								
								
									
										41
									
								
								shaders/shader.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								shaders/shader.frag
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
#version 420 core 
 | 
			
		||||
 | 
			
		||||
in vec2 texCoord;
 | 
			
		||||
 | 
			
		||||
in vec3 Cam_vertex; // Позиция камеры относительно вершины
 | 
			
		||||
in vec3 L_vertex; // Позиция источника света относительно вершины
 | 
			
		||||
in vec3 N; // Нормаль
 | 
			
		||||
 | 
			
		||||
layout(std140, binding = 1) uniform Material
 | 
			
		||||
{
 | 
			
		||||
    vec3 ka;
 | 
			
		||||
    vec3 kd;
 | 
			
		||||
    vec3 ks;
 | 
			
		||||
    float p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
layout(std140, binding = 2) uniform Light
 | 
			
		||||
{
 | 
			
		||||
    vec3 position;
 | 
			
		||||
    vec3 color;
 | 
			
		||||
} light_f;
 | 
			
		||||
 | 
			
		||||
uniform sampler2D tex_diffuse;
 | 
			
		||||
uniform sampler2D tex_ambient;
 | 
			
		||||
uniform sampler2D tex_specular;
 | 
			
		||||
 | 
			
		||||
out vec4 color; 
 | 
			
		||||
 | 
			
		||||
void main() 
 | 
			
		||||
{ 
 | 
			
		||||
    // Диффузная составляющая
 | 
			
		||||
    float diffuse = max(dot(L_vertex, N), 0.0); // скалярное произведение с отсеканием значений < 0
 | 
			
		||||
    
 | 
			
		||||
    // Вектор половины пути
 | 
			
		||||
    vec3 H = normalize(L_vertex + Cam_vertex);
 | 
			
		||||
    // Зеркальная составляющая
 | 
			
		||||
    float specular = pow(max(dot(H, N), 0.0), p*4); // скалярное произведение с отсеканием значений < 0 в степени p
 | 
			
		||||
 | 
			
		||||
    color = vec4(light_f.color*ka, 1)*texture(tex_ambient, texCoord) + vec4(light_f.color*kd*diffuse, 1)*texture(tex_diffuse, texCoord) + vec4(light_f.color*ks*specular, 1)*texture(tex_specular, texCoord);
 | 
			
		||||
} 
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								shaders/shader.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								shaders/shader.vert
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
#version 420 core 
 | 
			
		||||
 | 
			
		||||
layout(location = 0) in vec3 pos; 
 | 
			
		||||
layout(location = 1) in vec2 inTexCoord;
 | 
			
		||||
layout(location = 2) in vec3 normals; 
 | 
			
		||||
 | 
			
		||||
layout(std140, binding = 0) uniform Camera
 | 
			
		||||
{
 | 
			
		||||
    mat4 projection;
 | 
			
		||||
    mat4 view;
 | 
			
		||||
    vec3 position;
 | 
			
		||||
} camera;
 | 
			
		||||
 | 
			
		||||
layout(std140, binding = 2) uniform Light
 | 
			
		||||
{
 | 
			
		||||
    vec3 position;
 | 
			
		||||
    vec3 color;
 | 
			
		||||
} light_v;
 | 
			
		||||
 | 
			
		||||
uniform mat4 model;
 | 
			
		||||
 | 
			
		||||
out vec2 texCoord;
 | 
			
		||||
 | 
			
		||||
out vec3 Cam_vertex; // Позиция камеры относительно вершины
 | 
			
		||||
out vec3 L_vertex; // Позиция источника света относительно вершины
 | 
			
		||||
out vec3 N; // Нормаль трансформированноая
 | 
			
		||||
 | 
			
		||||
void main() 
 | 
			
		||||
{ 
 | 
			
		||||
    vec4 P = model * vec4(pos, 1.0); // трансформация вершины
 | 
			
		||||
 | 
			
		||||
    Cam_vertex = normalize(camera.position - P.xyz);
 | 
			
		||||
    L_vertex = normalize(light_v.position - P.xyz);
 | 
			
		||||
    N = normalize(mat3(model) * normals);
 | 
			
		||||
 | 
			
		||||
    gl_Position = camera.projection * camera.view * P;
 | 
			
		||||
    texCoord = inTexCoord;
 | 
			
		||||
} 
 | 
			
		||||
							
								
								
									
										144
									
								
								src/Buffers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								src/Buffers.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,144 @@
 | 
			
		||||
#include "Buffers.h"
 | 
			
		||||
 | 
			
		||||
// Счетчики использований дескрипторов
 | 
			
		||||
std::map<GLuint, GLuint> VAO::handler_count; 
 | 
			
		||||
std::map<GLuint, GLuint> 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); // Привязка элементного буфера
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | 
			
		||||
UBO::UBO(int size, int binding) : BO(UNIFORM, 0, size)
 | 
			
		||||
{
 | 
			
		||||
    rebind(binding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | 
			
		||||
UBO::UBO(const void *data, int size, int binding) : BO(UNIFORM, data, size)
 | 
			
		||||
{
 | 
			
		||||
    rebind(binding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// перепривязка
 | 
			
		||||
void UBO::rebind(int binding)
 | 
			
		||||
{
 | 
			
		||||
    glBindBufferBase(type, binding, handler); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Загрузка с отступом
 | 
			
		||||
void UBO::loadSub(const void *data, int size, int offset)
 | 
			
		||||
{
 | 
			
		||||
    use();
 | 
			
		||||
    glBufferSubData(type, offset, size, data);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										191
									
								
								src/Camera.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								src/Camera.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,191 @@
 | 
			
		||||
#include "Camera.h"
 | 
			
		||||
 | 
			
		||||
// Указатель на текущую используемую камеру
 | 
			
		||||
Camera* Camera::p_current = NULL; 
 | 
			
		||||
 | 
			
		||||
// Защищенный (protected) конструктор камеры без перспективы 
 | 
			
		||||
Camera::Camera(const glm::vec3 &pos, const glm::vec3 &initialRotation) : Node(NULL) // Пусть по умолчанию камера не относится к сцене
 | 
			
		||||
{
 | 
			
		||||
    sensitivity = CAMERA_DEFAULT_SENSIVITY;
 | 
			
		||||
    position = pos; // задаем позицию
 | 
			
		||||
    // Определяем начальный поворот
 | 
			
		||||
    glm::quat rotationAroundX = glm::angleAxis( glm::radians(initialRotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
 | 
			
		||||
    glm::quat rotationAroundY = glm::angleAxis(-glm::radians(initialRotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
 | 
			
		||||
    glm::quat rotationAroundZ = glm::angleAxis( glm::radians(initialRotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
 | 
			
		||||
    rotation = rotationAroundX * rotationAroundY * rotationAroundZ;
 | 
			
		||||
    // Признак изменения
 | 
			
		||||
    changed = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор камеры с проекцией перспективы
 | 
			
		||||
Camera::Camera(float aspect, const glm::vec3 &position, const glm::vec3 &initialRotation, float fovy)
 | 
			
		||||
: Camera(position, initialRotation)
 | 
			
		||||
{
 | 
			
		||||
    setPerspective(fovy, aspect);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор ортографической камеры
 | 
			
		||||
Camera::Camera(float width, float height, const glm::vec3 &position, const glm::vec3 &initialRotation)
 | 
			
		||||
: Camera(position, initialRotation)
 | 
			
		||||
{
 | 
			
		||||
    setOrtho(width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования камеры
 | 
			
		||||
Camera::Camera(const Camera& copy) 
 | 
			
		||||
: Node(copy), projection(copy.projection), requiredRecalcVP(copy.requiredRecalcVP), sensitivity(copy.sensitivity)
 | 
			
		||||
{
 | 
			
		||||
    // Если у оригинала не было изменений - перепишем матрицу вида-проекции
 | 
			
		||||
    if (!requiredRecalcVP)
 | 
			
		||||
        vp = copy.vp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
Camera& Camera::operator=(const Camera& other)
 | 
			
		||||
{
 | 
			
		||||
    Node::operator=(other); // Вызов родительского оператора= для переноса узла
 | 
			
		||||
    
 | 
			
		||||
    projection = other.projection;
 | 
			
		||||
    requiredRecalcVP = other.requiredRecalcVP;
 | 
			
		||||
    sensitivity = other.sensitivity;
 | 
			
		||||
 | 
			
		||||
    // Если у оригинала не было изменений - перепишем матрицу вида-проекции
 | 
			
		||||
    if (!requiredRecalcVP)
 | 
			
		||||
        vp = other.vp;
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Деструктор
 | 
			
		||||
Camera::~Camera() 
 | 
			
		||||
{ 
 | 
			
		||||
    if (p_current == this)
 | 
			
		||||
        p_current = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает ссылку на константную матрицу проекции
 | 
			
		||||
const glm::mat4& Camera::getProjection()
 | 
			
		||||
{
 | 
			
		||||
    return projection;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает ссылку на константную матрицу вида
 | 
			
		||||
const glm::mat4& Camera::getView()
 | 
			
		||||
{
 | 
			
		||||
    recalcMatrices();
 | 
			
		||||
 | 
			
		||||
    return view;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает ссылку на константную матрицу вида
 | 
			
		||||
const glm::mat4& Camera::getVP()
 | 
			
		||||
{
 | 
			
		||||
    recalcMatrices();
 | 
			
		||||
 | 
			
		||||
    return vp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Устанавливает заданную матрицу перспективы
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает чувствительность мыши
 | 
			
		||||
const float& Camera::getSensitivity() const
 | 
			
		||||
{
 | 
			
		||||
    return sensitivity; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Метод пересчета матрицы вида и произведения Вида*Проекции по необходимости, должен сбрасывать флаг changed
 | 
			
		||||
void Camera::recalcMatrices()
 | 
			
		||||
{
 | 
			
		||||
    if (changed || parent_changed)
 | 
			
		||||
    {
 | 
			
		||||
        glm::vec3 _position = position;
 | 
			
		||||
        glm::quat _rotation = rotation;
 | 
			
		||||
        if (parent) // Если есть родитель
 | 
			
		||||
        {
 | 
			
		||||
            glm::mat4 normalized_transform = parent->getTransformMatrix();
 | 
			
		||||
            for (int i = 0; i < 3; i++) 
 | 
			
		||||
            {
 | 
			
		||||
                glm::vec3 axis = glm::vec3(normalized_transform[i]);
 | 
			
		||||
                normalized_transform[i] = glm::vec4(glm::normalize(axis), normalized_transform[i].w);
 | 
			
		||||
            }
 | 
			
		||||
            glm::vec4 tmp = normalized_transform * glm::vec4(_position, 1.0f);
 | 
			
		||||
            tmp /= tmp.w;
 | 
			
		||||
            _position = glm::vec3(tmp);
 | 
			
		||||
            _rotation = glm::quat_cast(normalized_transform) * _rotation;
 | 
			
		||||
        }
 | 
			
		||||
        glm::mat4 rotationMatrix = glm::mat4_cast(glm::conjugate(_rotation));
 | 
			
		||||
        glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0f), -_position);
 | 
			
		||||
        view = rotationMatrix * translationMatrix;
 | 
			
		||||
        requiredRecalcVP = true;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    Node::recalcMatrices();
 | 
			
		||||
 | 
			
		||||
    if (requiredRecalcVP)
 | 
			
		||||
    {
 | 
			
		||||
        vp = projection * view;
 | 
			
		||||
        requiredRecalcVP = false; // Изменения применены
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Поворачивает камеру на dx и dy пикселей с учетом чувствительности
 | 
			
		||||
void Camera::rotate(const glm::vec2 &xyOffset)
 | 
			
		||||
{
 | 
			
		||||
    // xyOffset - сдвиги координат мыши, xyOffset.x означает поворот вокруг оси Y, а xyOffset.y - поворот вокруг оси X
 | 
			
		||||
    
 | 
			
		||||
    // Вращение вокруг оси Y
 | 
			
		||||
    glm::quat qY = glm::angleAxis(-xyOffset.x * sensitivity, glm::vec3(0.0f, 1.0f, 0.0f));
 | 
			
		||||
    
 | 
			
		||||
    // Вращение вокруг оси X
 | 
			
		||||
    glm::quat qX = glm::angleAxis(xyOffset.y * sensitivity, glm::vec3(1.0f, 0.0f, 0.0f));
 | 
			
		||||
 | 
			
		||||
    // Сначала применяем вращение вокруг Y, затем вокруг X
 | 
			
		||||
    rotation = qY * rotation * qX;
 | 
			
		||||
 | 
			
		||||
    changed = true;
 | 
			
		||||
    invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Использование этой камеры как текущей
 | 
			
		||||
void Camera::use()
 | 
			
		||||
{
 | 
			
		||||
    p_current = this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Ссылка на текущую используемую камеру
 | 
			
		||||
Camera& Camera::current()
 | 
			
		||||
{
 | 
			
		||||
    static Camera default_cam(800.0f/600.0f);
 | 
			
		||||
 | 
			
		||||
    if (!p_current)
 | 
			
		||||
        return default_cam;
 | 
			
		||||
    else
 | 
			
		||||
        return *p_current;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Данные о камере для шейдера
 | 
			
		||||
CameraData& Camera::getData()
 | 
			
		||||
{
 | 
			
		||||
    static CameraData data;
 | 
			
		||||
    data = {getProjection(), getView(), position};
 | 
			
		||||
    return data;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										398
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										398
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,398 @@
 | 
			
		||||
#include "Model.h"
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
// Конструктор с заданным родителем (по умолчанию NULL)
 | 
			
		||||
Node::Node(Node* parent_) : parent(parent_), result_transform(1), parent_changed(false),
 | 
			
		||||
position(0), rotation(1.0f, 0.0f, 0.0f, 0.0f), scale(1), changed(false), transform(1)
 | 
			
		||||
{
 | 
			
		||||
    if (parent)
 | 
			
		||||
    {
 | 
			
		||||
        // Запишем себя в потомки
 | 
			
		||||
        parent->children.push_back(this);
 | 
			
		||||
        parent_changed = true;
 | 
			
		||||
    }
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
Node::Node(const Node& copy): position(copy.position), rotation(copy.rotation), scale(copy.scale),
 | 
			
		||||
parent(copy.parent), changed(copy.changed), parent_changed(copy.parent_changed), transform(1), result_transform(1)
 | 
			
		||||
{
 | 
			
		||||
    // Запишем себя в потомки
 | 
			
		||||
    if (parent)
 | 
			
		||||
        parent->children.push_back(this);
 | 
			
		||||
    // Если у оригинала не было изменений - перепишем матрицу трансформации
 | 
			
		||||
    if (!changed)
 | 
			
		||||
        transform = copy.transform;
 | 
			
		||||
    // Если у родителя не было изменений для оригинала - перепишем результирующую матрицу трансформации
 | 
			
		||||
    if (!parent_changed)
 | 
			
		||||
        result_transform = copy.result_transform;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Node::~Node()
 | 
			
		||||
{
 | 
			
		||||
    setParent(NULL); // Удаляем себя из потомков
 | 
			
		||||
    // Сообщаем потомкам об удалении родителя
 | 
			
		||||
    for (Node* child : children)
 | 
			
		||||
        child->setParent(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает необходимость пересчета матрицы трансформации
 | 
			
		||||
bool Node::isChanged() 
 | 
			
		||||
{ 
 | 
			
		||||
    return changed; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Константный доступ к позиции
 | 
			
		||||
const glm::vec3& Node::c_position() const 
 | 
			
		||||
{ 
 | 
			
		||||
    return position; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Константный доступ к повороту
 | 
			
		||||
const glm::quat& Node::c_rotation() const 
 | 
			
		||||
{ 
 | 
			
		||||
    return rotation; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Константный доступ к масштабированию
 | 
			
		||||
const glm::vec3& Node::c_scale() const 
 | 
			
		||||
{ 
 | 
			
		||||
    return scale; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Неконстантная ссылка для изменений позиции
 | 
			
		||||
glm::vec3& Node::e_position() 
 | 
			
		||||
{ 
 | 
			
		||||
    changed = true; // Флаг о изменении
 | 
			
		||||
    invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
 | 
			
		||||
    return position; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Неконстантная ссылка для изменений поворота
 | 
			
		||||
glm::quat& Node::e_rotation() 
 | 
			
		||||
{ 
 | 
			
		||||
    changed = true; // Флаг о изменении
 | 
			
		||||
    invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
 | 
			
		||||
    return rotation; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Неконстантная ссылка для изменений масштабирования         
 | 
			
		||||
glm::vec3& Node::e_scale() 
 | 
			
		||||
{ 
 | 
			
		||||
    changed = true; // Флаг о изменении
 | 
			
		||||
    invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
 | 
			
		||||
    return scale; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Возвращает матрицу трансформации модели
 | 
			
		||||
const glm::mat4& Node::getTransformMatrix() 
 | 
			
		||||
{
 | 
			
		||||
    // Если требуется - пересчитаем матрицу
 | 
			
		||||
    recalcMatrices();
 | 
			
		||||
        
 | 
			
		||||
    return result_transform;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Пересчет матрицы трансформации модели, если это требуется
 | 
			
		||||
void Node::recalcMatrices() 
 | 
			
		||||
{
 | 
			
		||||
    // Если было изменение по векторам позиции, поворота и масштабирования
 | 
			
		||||
    if  (changed)
 | 
			
		||||
    {
 | 
			
		||||
        transform = glm::mat4(1.0f);
 | 
			
		||||
        // Перемещение модели
 | 
			
		||||
        transform = glm::translate(transform, position);
 | 
			
		||||
        // Поворот модели
 | 
			
		||||
        transform = transform * glm::mat4_cast(rotation);
 | 
			
		||||
        // Масштабирование
 | 
			
		||||
        transform = glm::scale(transform, scale);  
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Если собственная или родительская матрицы менялись - необходимо пересчитать итоговую
 | 
			
		||||
    if (changed || parent_changed)
 | 
			
		||||
    {
 | 
			
		||||
        if (parent) // Если есть родитель
 | 
			
		||||
            result_transform = parent->getTransformMatrix() * transform;
 | 
			
		||||
        else // Если нет родителя
 | 
			
		||||
            result_transform = transform;
 | 
			
		||||
 | 
			
		||||
        parent_changed = changed = false; // Изменения применены
 | 
			
		||||
    }
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Проход потомков в глубину с изменением флага parent_changed
 | 
			
		||||
void Node::invalidateParent()
 | 
			
		||||
{
 | 
			
		||||
    // Цикл по потомкам
 | 
			
		||||
    for (Node* child : children)
 | 
			
		||||
    {
 | 
			
		||||
        child->parent_changed = true; // Флаг 
 | 
			
		||||
        child->invalidateParent(); // Рекурсивный вызов для потомков выбранного потомка
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Устанавливает родителя для узла
 | 
			
		||||
void Node::setParent(Node * parent)
 | 
			
		||||
{
 | 
			
		||||
    // Если замена происходит на другого родителя
 | 
			
		||||
    if (parent != this->parent)
 | 
			
		||||
    {
 | 
			
		||||
        Node* tmp = parent;
 | 
			
		||||
        // Проверка на зацикливание об самого себя
 | 
			
		||||
        while (tmp)
 | 
			
		||||
        {
 | 
			
		||||
            if (tmp == this)
 | 
			
		||||
                return; // Можно выдать exception
 | 
			
		||||
            tmp = tmp->parent;
 | 
			
		||||
        }
 | 
			
		||||
        // Если есть старый родитель - удалим себя из его потомков
 | 
			
		||||
        if (this->parent)
 | 
			
		||||
        {
 | 
			
		||||
            // Поиск в списке родительских потомков
 | 
			
		||||
            auto position = std::find(this->parent->children.begin(), this->parent->children.end(), this);
 | 
			
		||||
            // Если итератор указывает в конец - ничего не найдено
 | 
			
		||||
            if (position != this->parent->children.end()) 
 | 
			
		||||
                this->parent->children.erase(position); // Само удаление
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        this->parent = parent; // Заменяем указатель на родителя
 | 
			
		||||
        // Если родитель не NULL - добавляем себя в детей
 | 
			
		||||
        if (parent) 
 | 
			
		||||
            parent->children.push_back(this);
 | 
			
		||||
        // В любом случае необходимо пересчитать собственную итоговую матрицу
 | 
			
		||||
        parent_changed = true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает указатель на родителя
 | 
			
		||||
Node* Node::getParent() 
 | 
			
		||||
{ 
 | 
			
		||||
    return parent; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает ссылку на вектор дочерних узлов
 | 
			
		||||
const std::vector<Node*>& Node::getChildren() const 
 | 
			
		||||
{ 
 | 
			
		||||
    return children; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
Node& Node::operator=(const Node& other)
 | 
			
		||||
{
 | 
			
		||||
    position = other.position;
 | 
			
		||||
    rotation = other.rotation;
 | 
			
		||||
    scale = other.scale;
 | 
			
		||||
    changed = other.changed;
 | 
			
		||||
 | 
			
		||||
    if (!changed)
 | 
			
		||||
        transform = other.transform;
 | 
			
		||||
        
 | 
			
		||||
    setParent(other.parent);
 | 
			
		||||
    
 | 
			
		||||
    // Если у other флаг parent_changed == false, то можно переписать матрицу результата с него
 | 
			
		||||
    if (!other.parent_changed)
 | 
			
		||||
    {
 | 
			
		||||
        result_transform = other.result_transform;
 | 
			
		||||
        parent_changed = false; // Сбрасываем флаг после смены родителя
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор по умолчанию
 | 
			
		||||
Model::Model(Node *parent) : Node(parent), verteces_count(0), first_index_byteOffset(0), indices_count(0), 
 | 
			
		||||
vertex_vbo(VERTEX), index_vbo(ELEMENT), normals_vbo(VERTEX), texCoords_vbo(VERTEX)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
Model::Model(const Model& copy) : Node(copy),
 | 
			
		||||
vao(copy.vao), 
 | 
			
		||||
verteces_count(copy.verteces_count), first_index_byteOffset(copy.first_index_byteOffset), 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), texture_ambient(copy.texture_ambient), texture_specular(copy.texture_specular), 
 | 
			
		||||
material(copy.material)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
Model& Model::operator=(const Model& other)
 | 
			
		||||
{
 | 
			
		||||
    Node::operator=(other); // Явный вызов родительского оператора копирования
 | 
			
		||||
    
 | 
			
		||||
    vao = other.vao; 
 | 
			
		||||
    verteces_count = other.verteces_count;
 | 
			
		||||
    first_index_byteOffset = other.first_index_byteOffset;
 | 
			
		||||
    indices_count = other.indices_count;
 | 
			
		||||
    
 | 
			
		||||
    vertex_vbo = other.vertex_vbo;
 | 
			
		||||
    index_vbo = other.index_vbo;
 | 
			
		||||
    texCoords_vbo = other.texCoords_vbo;
 | 
			
		||||
 | 
			
		||||
    texture_diffuse = other.texture_diffuse;
 | 
			
		||||
    texture_ambient = other.texture_ambient;
 | 
			
		||||
    texture_specular = other.texture_specular;
 | 
			
		||||
    
 | 
			
		||||
    material = other.material;
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Model::~Model()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Вызов отрисовки
 | 
			
		||||
void Model::render(const GLuint &model_uniform, UBO &material_buffer) 
 | 
			
		||||
{
 | 
			
		||||
    // Загрузим матрицу трансформации
 | 
			
		||||
    glUniformMatrix4fv(model_uniform, 1, GL_FALSE, &getTransformMatrix()[0][0]);
 | 
			
		||||
 | 
			
		||||
    // Подключаем текстуры
 | 
			
		||||
    texture_diffuse.use();
 | 
			
		||||
    texture_ambient.use();
 | 
			
		||||
    texture_specular.use();
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Загружаем данные о материале
 | 
			
		||||
    material_buffer.load(&material, sizeof(material));
 | 
			
		||||
 | 
			
		||||
    // Подключаем VAO
 | 
			
		||||
    vao.use();
 | 
			
		||||
    // Если есть индексы - рисуем с их использованием
 | 
			
		||||
    if (indices_count)
 | 
			
		||||
    {
 | 
			
		||||
        index_vbo.use();
 | 
			
		||||
        glDrawElements(GL_TRIANGLES, indices_count, GL_UNSIGNED_INT, (void*)(first_index_byteOffset));
 | 
			
		||||
    }
 | 
			
		||||
    // Если есть вершины - рисуем на основании массива вершин
 | 
			
		||||
    else if (verteces_count)
 | 
			
		||||
        glDrawArrays(GL_TRIANGLES, 0, verteces_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция для конфигурации атрибута вершинного буфера
 | 
			
		||||
void vertex_attrib_config()
 | 
			
		||||
{
 | 
			
		||||
    // Определим спецификацию атрибута
 | 
			
		||||
    glVertexAttribPointer(  0         // индекс атрибута, должен совпадать с Layout шейдера
 | 
			
		||||
                          , 3         // количество компонент одного элемента
 | 
			
		||||
                          , GL_FLOAT  // тип
 | 
			
		||||
                          , GL_FALSE  // необходимость нормировать значения
 | 
			
		||||
                          , 0         // шаг
 | 
			
		||||
                          , (void *)0 // отступ с начала массива
 | 
			
		||||
                         );
 | 
			
		||||
    // Включаем необходимый атрибут у выбранного VAO
 | 
			
		||||
    glEnableVertexAttribArray(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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция для конфигурации атрибута вершинного буфера
 | 
			
		||||
void texCoords_attrib_config()
 | 
			
		||||
{
 | 
			
		||||
    // Определим спецификацию атрибута
 | 
			
		||||
    glVertexAttribPointer(  1         // индекс атрибута, должен совпадать с Layout шейдера
 | 
			
		||||
                          , 2         // количество компонент одного элемента
 | 
			
		||||
                          , GL_FLOAT  // тип
 | 
			
		||||
                          , GL_FALSE  // необходимость нормировать значения
 | 
			
		||||
                          , 0         // шаг
 | 
			
		||||
                          , (void *)0 // отступ с начала массива
 | 
			
		||||
                         );
 | 
			
		||||
    // Включаем необходимый атрибут у выбранного VAO
 | 
			
		||||
    glEnableVertexAttribArray(1);
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Загрузка текстурных координат в буфер
 | 
			
		||||
void Model::load_texCoords(glm::vec2* texCoords, GLuint count)
 | 
			
		||||
{
 | 
			
		||||
    // Подключаем VAO
 | 
			
		||||
    vao.use();
 | 
			
		||||
 | 
			
		||||
    texCoords_vbo.use();
 | 
			
		||||
 | 
			
		||||
    // Загрузка вершин в память буфера
 | 
			
		||||
    texCoords_vbo.load(texCoords, sizeof(glm::vec2)*count);
 | 
			
		||||
    texCoords_attrib_config();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция для конфигурации атрибута вершинного буфера
 | 
			
		||||
void normals_attrib_config()
 | 
			
		||||
{
 | 
			
		||||
    // Устанавливаем связь между VAO и привязанным VBO
 | 
			
		||||
    glVertexAttribPointer(  2         // индекс атрибута, должен совпадать с Layout шейдера
 | 
			
		||||
                          , 3         // количество компонент одного элемента
 | 
			
		||||
                          , GL_FLOAT  // тип
 | 
			
		||||
                          , GL_FALSE  // необходимость нормировать значения
 | 
			
		||||
                          , 0         // шаг
 | 
			
		||||
                          , (void *)0 // отступ с начала массива
 | 
			
		||||
                         );
 | 
			
		||||
    // Включаем необходимый атрибут у выбранного VAO
 | 
			
		||||
    glEnableVertexAttribArray(2);
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Загрузка нормалей в буфер
 | 
			
		||||
void Model::load_normals(glm::vec3* normals, GLuint count) 
 | 
			
		||||
{
 | 
			
		||||
    // Подключаем VAO
 | 
			
		||||
    vao.use();
 | 
			
		||||
 | 
			
		||||
    normals_vbo.use();
 | 
			
		||||
 | 
			
		||||
    // Загрузка вершин в память буфера
 | 
			
		||||
    normals_vbo.load(normals, sizeof(glm::vec3)*count);
 | 
			
		||||
    normals_attrib_config();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Ограничение диапазона из буфера индексов
 | 
			
		||||
void Model::set_index_range(size_t first_byteOffset, size_t count)
 | 
			
		||||
{
 | 
			
		||||
    first_index_byteOffset = first_byteOffset;
 | 
			
		||||
    indices_count = count;
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Привязка текстуры к модели
 | 
			
		||||
void Model::set_texture(Texture& texture)
 | 
			
		||||
{
 | 
			
		||||
    GLuint type = texture.getType();
 | 
			
		||||
    switch(type)
 | 
			
		||||
    {
 | 
			
		||||
        case TEX_DIFFUSE:
 | 
			
		||||
            texture_diffuse = texture;
 | 
			
		||||
            break;
 | 
			
		||||
        case TEX_AMBIENT:
 | 
			
		||||
            texture_ambient = texture;
 | 
			
		||||
            break;
 | 
			
		||||
        case TEX_SPECULAR:
 | 
			
		||||
            texture_specular = texture;
 | 
			
		||||
            break;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										224
									
								
								src/Scene.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								src/Scene.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,224 @@
 | 
			
		||||
#include "Scene.h"
 | 
			
		||||
 | 
			
		||||
// Конструктор пустой сцены
 | 
			
		||||
Scene::Scene()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
Scene::Scene(const Scene ©): root(copy.root), 
 | 
			
		||||
nodes(copy.nodes), models(copy.models), cameras(copy.cameras)
 | 
			
		||||
{
 | 
			
		||||
    rebuld_tree(copy);
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
Scene& Scene::operator=(const Scene& other) 
 | 
			
		||||
{
 | 
			
		||||
    root = other.root;
 | 
			
		||||
    nodes = other.nodes;
 | 
			
		||||
    models = other.models;
 | 
			
		||||
    cameras = other.cameras;
 | 
			
		||||
 | 
			
		||||
    rebuld_tree(other);
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Рендер сцены
 | 
			
		||||
void Scene::render(const GLuint &model_uniform, UBO &material_buffer) 
 | 
			
		||||
{
 | 
			
		||||
    for (auto & model : models)
 | 
			
		||||
        model.render(model_uniform, material_buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Перестройка узлов выбранного списка
 | 
			
		||||
template <class T>
 | 
			
		||||
void Scene::rebuild_Nodes_list(T& nodes, const Scene& from)
 | 
			
		||||
{
 | 
			
		||||
    for (auto it = nodes.begin(); it != nodes.end(); it++)
 | 
			
		||||
    {
 | 
			
		||||
        // Берем родителя, который указывает на оригинальный объект
 | 
			
		||||
        Node* parent = it->getParent();
 | 
			
		||||
        
 | 
			
		||||
        // Если родитель - оригинальный корневой узел, то меняем на собственный корневой узел
 | 
			
		||||
        if (parent == &from.root) 
 | 
			
		||||
        {
 | 
			
		||||
            it->setParent(&root);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Если можно привести к модели, то ищем родителя среди моделей
 | 
			
		||||
        if (dynamic_cast<Model*>(parent))
 | 
			
		||||
            move_parent(*it, from.models, this->models);
 | 
			
		||||
        else
 | 
			
		||||
        // Иначе проверяем на принадлежность к камерам
 | 
			
		||||
        if (dynamic_cast<Camera*>(parent))
 | 
			
		||||
            move_parent(*it, from.cameras, this->cameras);
 | 
			
		||||
        // Иначе это пустой узел
 | 
			
		||||
        else
 | 
			
		||||
            move_parent(*it, from.nodes, this->nodes);
 | 
			
		||||
            
 | 
			
		||||
        // Не нашли родителя - значит он не часть этой сцены 
 | 
			
		||||
        // и изменений по нему не требуется
 | 
			
		||||
    }
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Сдвигает родителя узла между двумя списками при условии его принадлежности к оригинальному
 | 
			
		||||
template <class T>
 | 
			
		||||
void Scene::move_parent(Node& for_node, const std::list<T>& from_nodes, std::list<T>& this_nodes)
 | 
			
		||||
{
 | 
			
		||||
    // Возьмем адрес родителя
 | 
			
		||||
    Node* parent = for_node.getParent();
 | 
			
		||||
    // Цикл по элементам списков для перемещения родителя
 | 
			
		||||
    // Списки в процессе копирования идеинтичные, вторая проверка не требуется
 | 
			
		||||
    for (auto it_from = from_nodes.begin(), it_this = this_nodes.begin(); it_from != from_nodes.end(); ++it_from, ++it_this)
 | 
			
		||||
        // Если адрес объекта, на который указывает итератор, совпадает с родителем - меняем родителя по второму итератору (it_this)
 | 
			
		||||
        if (&(*it_from) == parent)
 | 
			
		||||
            for_node.setParent(&(*it_this));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Перестройка дерева после копирования или присваивания
 | 
			
		||||
void Scene::rebuld_tree(const Scene& from)
 | 
			
		||||
{    
 | 
			
		||||
    // Восстановим родителей в пустых узлах для копии
 | 
			
		||||
    rebuild_Nodes_list(nodes, from);
 | 
			
		||||
    rebuild_Nodes_list(models, from);
 | 
			
		||||
    rebuild_Nodes_list(cameras, from);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#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...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Scene loadOBJtoScene(const char* filename, const char* mtl_directory, const char* texture_directory)
 | 
			
		||||
{
 | 
			
		||||
    Scene result;
 | 
			
		||||
    Model model;
 | 
			
		||||
    // Все модели образованные на основании этой модели будут иметь общего родителя
 | 
			
		||||
    model.setParent(&result.root); 
 | 
			
		||||
 | 
			
		||||
    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.models.push_back(model); // Создание копии с общим VAO
 | 
			
		||||
        auto s = --result.models.end();
 | 
			
		||||
        s->set_index_range(materials_range[i]*sizeof(GLuint), materials_range[i+1]-materials_range[i]);
 | 
			
		||||
 | 
			
		||||
        // Текстуры
 | 
			
		||||
        Texture diffuse(TEX_DIFFUSE, texture_directory + materials[materials_ids[i]].diffuse_texname);
 | 
			
		||||
        s->set_texture(diffuse);
 | 
			
		||||
        Texture ambient(TEX_AMBIENT, texture_directory + materials[materials_ids[i]].ambient_texname);
 | 
			
		||||
        s->set_texture(ambient);
 | 
			
		||||
        Texture specular(TEX_SPECULAR, texture_directory + materials[materials_ids[i]].specular_texname);
 | 
			
		||||
        s->set_texture(specular);
 | 
			
		||||
 | 
			
		||||
        // Материал
 | 
			
		||||
        s->material.ka = glm::vec3(materials[materials_ids[i]].ambient[0],  materials[materials_ids[i]].ambient[1],  materials[materials_ids[i]].ambient[2]);
 | 
			
		||||
        s->material.kd = glm::vec3(materials[materials_ids[i]].diffuse[0],  materials[materials_ids[i]].diffuse[1],  materials[materials_ids[i]].diffuse[2]);
 | 
			
		||||
        s->material.ks = glm::vec3(materials[materials_ids[i]].specular[0], materials[materials_ids[i]].specular[1], materials[materials_ids[i]].specular[2]);
 | 
			
		||||
        s->material.p  = (materials[materials_ids[i]].shininess > 0.0f) ? 1000.0f / materials[materials_ids[i]].shininess : 1000.0f;
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										154
									
								
								src/Shader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/Shader.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,154 @@
 | 
			
		||||
#include "Shader.h"
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
std::map<int, int> ShaderProgram::handler_count; // Получение количества использований по дескриптору ШП (Shared pointer)
 | 
			
		||||
 | 
			
		||||
ShaderProgram::ShaderProgram()
 | 
			
		||||
{
 | 
			
		||||
    program = glCreateProgram();
 | 
			
		||||
    handler_count[program] = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ShaderProgram::ShaderProgram(const ShaderProgram ©) : program(copy.program)
 | 
			
		||||
{
 | 
			
		||||
    handler_count[program]++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ShaderProgram::~ShaderProgram()
 | 
			
		||||
{
 | 
			
		||||
    if (!--handler_count[program]) // Если количество ссылок = 0
 | 
			
		||||
    {
 | 
			
		||||
        // Удаление шейдерной программы
 | 
			
		||||
        glDeleteProgram(program);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
ShaderProgram& ShaderProgram::operator=(const ShaderProgram& other)
 | 
			
		||||
{
 | 
			
		||||
    // Если это разные шейдерные программы
 | 
			
		||||
    if (program != other.program)
 | 
			
		||||
    {
 | 
			
		||||
        this->~ShaderProgram(); // Уничтожаем имеющуюся
 | 
			
		||||
        // Заменяем новой
 | 
			
		||||
        program = other.program;
 | 
			
		||||
        handler_count[program]++;
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Использование шейдеров
 | 
			
		||||
void ShaderProgram::use()
 | 
			
		||||
{
 | 
			
		||||
    glUseProgram(program);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция чтения шейдера из файла
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция для загрузки шейдеров
 | 
			
		||||
void ShaderProgram::load(GLuint type, const char* filename)
 | 
			
		||||
{
 | 
			
		||||
    // Создание дескрипторов шейдера
 | 
			
		||||
    GLuint handler = glCreateShader(type);
 | 
			
		||||
 | 
			
		||||
    // Переменные под результат компиляции
 | 
			
		||||
    GLint result = GL_FALSE;
 | 
			
		||||
    int infoLogLength;
 | 
			
		||||
 | 
			
		||||
    // Считываем текст вершинного шейдера
 | 
			
		||||
    std::string code = readFile(filename);
 | 
			
		||||
    const char* pointer = code.c_str(); // Преобразование к указателю на const char, так как функция принимает массив си-строк
 | 
			
		||||
 | 
			
		||||
    // Компиляция кода вершинного шейдера
 | 
			
		||||
    glShaderSource(handler, 1, &pointer, NULL);
 | 
			
		||||
    glCompileShader(handler);
 | 
			
		||||
 | 
			
		||||
    // Проверка результата компиляции
 | 
			
		||||
    glGetShaderiv(handler, GL_COMPILE_STATUS, &result);
 | 
			
		||||
    glGetShaderiv(handler, GL_INFO_LOG_LENGTH, &infoLogLength);
 | 
			
		||||
    if (infoLogLength > 0)
 | 
			
		||||
    {
 | 
			
		||||
        char* errorMessage = new char[infoLogLength + 1];
 | 
			
		||||
        glGetShaderInfoLog(handler, infoLogLength, NULL, errorMessage);
 | 
			
		||||
        std::cout << errorMessage;
 | 
			
		||||
        delete[] errorMessage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Привязка скомпилированного шейдера
 | 
			
		||||
    glAttachShader(program, handler);
 | 
			
		||||
    
 | 
			
		||||
    // Освобождение дескриптора шейдера
 | 
			
		||||
    glDeleteShader(handler);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Формирование программы из загруженных шейдеров
 | 
			
		||||
void ShaderProgram::link()
 | 
			
		||||
{
 | 
			
		||||
    // Переменные под результат компиляции
 | 
			
		||||
    GLint result = GL_FALSE;
 | 
			
		||||
    int infoLogLength;
 | 
			
		||||
 | 
			
		||||
    // Формирование программы из привязанных шейдеров
 | 
			
		||||
    glLinkProgram(program);
 | 
			
		||||
 | 
			
		||||
    // Проверка программы
 | 
			
		||||
    glGetProgramiv(program, GL_LINK_STATUS, &result);
 | 
			
		||||
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
 | 
			
		||||
    if (infoLogLength > 0)
 | 
			
		||||
    {
 | 
			
		||||
        char* errorMessage = new char[infoLogLength + 1];
 | 
			
		||||
        glGetProgramInfoLog(program, infoLogLength, NULL, errorMessage);
 | 
			
		||||
        std::cout << errorMessage;
 | 
			
		||||
        delete[] errorMessage;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Используем шейдерную программу объекта из которого вызван метод
 | 
			
		||||
    this->use(); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает местоположение uniform-переменной
 | 
			
		||||
GLuint ShaderProgram::getUniformLoc(const char* name) 
 | 
			
		||||
{
 | 
			
		||||
    GLuint result; // Результат
 | 
			
		||||
    // Если такую переменную ещё не искали - найдем, иначе вернем уже известный дескриптор
 | 
			
		||||
    if (!uniformLocations.count(name))
 | 
			
		||||
        uniformLocations[name] = result = glGetUniformLocation(program, name);
 | 
			
		||||
    else
 | 
			
		||||
        result = uniformLocations[name];
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Привязка uniform-блока
 | 
			
		||||
void ShaderProgram::bindUniformBlock(const char* name, int binding) 
 | 
			
		||||
{
 | 
			
		||||
    glUniformBlockBinding( program
 | 
			
		||||
                         , glGetUniformBlockIndex(program, name)
 | 
			
		||||
                         , binding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Инициализация текстур на шейдере
 | 
			
		||||
void ShaderProgram::bindTextures(const char* textures_base_shader_names[], int count)
 | 
			
		||||
{
 | 
			
		||||
    // Цикл по всем доступным текстурам
 | 
			
		||||
    for (int i = 0; i < count; i++)
 | 
			
		||||
        glUniform1i(getUniformLoc(textures_base_shader_names[i]), i);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										119
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,119 @@
 | 
			
		||||
#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++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Привязка текстуры
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										140
									
								
								src/main.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										140
									
								
								src/main.cpp
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,140 @@
 | 
			
		||||
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#include <GLFW/glfw3.h>
 | 
			
		||||
#include <GLM/glm.hpp>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include "Scene.h"
 | 
			
		||||
#include "Shader.h"
 | 
			
		||||
#include "Lights.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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
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::current().rotate(offset);
 | 
			
		||||
}  
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    
 | 
			
		||||
    glfwSwapInterval(1); // Вертикальная синхронизация
 | 
			
		||||
 | 
			
		||||
    // Установка callback-функции для мыши и камеры
 | 
			
		||||
    glfwSetCursorPosCallback(window, mouse_callback);
 | 
			
		||||
 | 
			
		||||
    // Загрузка функций OpenGL с помощью GLAD
 | 
			
		||||
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "GLAD load GL error\n";
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Включаем проверку по буферу глубины
 | 
			
		||||
    glEnable(GL_DEPTH_TEST);
 | 
			
		||||
 | 
			
		||||
    // Базовый шейдер
 | 
			
		||||
    ShaderProgram base;
 | 
			
		||||
    // Загрузка и компиляция шейдеров
 | 
			
		||||
    base.load(GL_VERTEX_SHADER, "shaders/shader.vert");
 | 
			
		||||
    base.load(GL_FRAGMENT_SHADER, "shaders/shader.frag");
 | 
			
		||||
    base.link();
 | 
			
		||||
    // Установим значения текстур
 | 
			
		||||
    const char* textures_base_shader_names[] = {"tex_diffuse", "tex_ambient", "tex_specular"};
 | 
			
		||||
    base.bindTextures(textures_base_shader_names, sizeof(textures_base_shader_names)/sizeof(const char*));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Загрузка сцены из obj файла
 | 
			
		||||
    Scene scene = loadOBJtoScene("../resources/models/blob.obj", "../resources/models/", "../resources/textures/"); 
 | 
			
		||||
    scene.root.e_scale() = glm::vec3(0.01);
 | 
			
		||||
    scene.root.e_position().z = 1;
 | 
			
		||||
    
 | 
			
		||||
    // Установка цвета очистки буфера цвета
 | 
			
		||||
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 | 
			
		||||
 | 
			
		||||
    // Расположение Uniform-переменной
 | 
			
		||||
    GLuint model_uniform = base.getUniformLoc("model");
 | 
			
		||||
 | 
			
		||||
    // Источник света
 | 
			
		||||
    LightData light = { {1.0f, 3.0f, 0.0f} // позиция
 | 
			
		||||
                      , {1.0f, 1.0f, 1.0f} // цвет
 | 
			
		||||
                      };
 | 
			
		||||
 | 
			
		||||
    // Uniform-буферы
 | 
			
		||||
    UBO cameraUB(sizeof(CameraData), 0);
 | 
			
		||||
    UBO material_data(sizeof(Material), 1);
 | 
			
		||||
    UBO light_data(&light, sizeof(LightData), 2);
 | 
			
		||||
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Использование уменьшенных версий mipmap  
 | 
			
		||||
 | 
			
		||||
    // Пока не произойдет событие запроса закрытия окна
 | 
			
		||||
    while(!glfwWindowShouldClose(window))
 | 
			
		||||
    {
 | 
			
		||||
        // Загрузка данных о камере
 | 
			
		||||
        cameraUB.loadSub(&Camera::current().getData(), sizeof(CameraData));
 | 
			
		||||
 | 
			
		||||
        // Очистка буфера цвета
 | 
			
		||||
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
        // Тут производится рендер
 | 
			
		||||
        scene.render(model_uniform, material_data);
 | 
			
		||||
        
 | 
			
		||||
        // Представление содержимого буфера цепочки показа на окно
 | 
			
		||||
        glfwSwapBuffers(window);
 | 
			
		||||
        // Обработка системных событий
 | 
			
		||||
        glfwPollEvents();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user