#include #include #include #include #include "Scene.h" #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 #define WINDOW_CAPTION "OPENGL notes on rekovalev.site" // Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна void framebuffer_size_callback(GLFWwindow* window, int width, int height) { glViewport(0, 0, width, height); } #include #include // Функция чтения шейдера из файла std::string readFile(const char* filename) { std::string text; std::ifstream file(filename, std::ios::in); // Открываем файл на чтение // Если файл доступен и успешно открыт if (file.is_open()) { std::stringstream sstr; // Буфер для чтения sstr << file.rdbuf(); // Считываем файл text = sstr.str(); // Преобразуем буфер к строке file.close(); // Закрываем файл } return text; } // Функция для загрузки шейдеров // Принимает два адреса вершинного и фрагментного шейдеров // Возвращает дескриптор шейдерной программы GLuint LoadShaders(const char *vertex_file, const char *fragment_file) { // Создание дескрипторов вершинного и фрагментного шейдеров GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER); GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); // Переменные под результат компиляции GLint result = GL_FALSE; int infoLogLength; // Считываем текст вершинного шейдера std::string code = readFile(vertex_file); const char* pointer = code.c_str(); // Преобразование к указателю на const char, так как функция принимает массив си-строк // Компиляция кода вершинного шейдера glShaderSource(vertexShaderID, 1, &pointer, NULL); glCompileShader(vertexShaderID); // Проверка результата компиляции glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &result); glGetShaderiv(vertexShaderID, GL_INFO_LOG_LENGTH, &infoLogLength); if (infoLogLength > 0) { char* errorMessage = new char[infoLogLength + 1]; glGetShaderInfoLog(vertexShaderID, infoLogLength, NULL, errorMessage); std::cout << errorMessage; delete[] errorMessage; } // Считываем текст вершинного шейдера code = readFile(fragment_file); pointer = code.c_str(); // Преобразование к указателю на const char, так как функция принимает массив си-строк // Компиляция кода фрагментного шейдера glShaderSource(fragmentShaderID, 1, &pointer, NULL); glCompileShader(fragmentShaderID); // Проверка результата компиляции glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &result); glGetShaderiv(fragmentShaderID, GL_INFO_LOG_LENGTH, &infoLogLength); if (infoLogLength > 0) { char* errorMessage = new char[infoLogLength + 1]; glGetShaderInfoLog(fragmentShaderID, infoLogLength, NULL, errorMessage); std::cout << errorMessage; delete[] errorMessage; } // Привязка скомпилированных шейдеров GLuint programID = glCreateProgram(); glAttachShader(programID, vertexShaderID); glAttachShader(programID, fragmentShaderID); glLinkProgram(programID); // Проверка программы glGetProgramiv(programID, GL_LINK_STATUS, &result); glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength); if (infoLogLength > 0) { char* errorMessage = new char[infoLogLength + 1]; glGetProgramInfoLog(programID, infoLogLength, NULL, errorMessage); std::cout << errorMessage; delete[] errorMessage; } // Освобождение дескрипторов шейдеров glDeleteShader(vertexShaderID); glDeleteShader(fragmentShaderID); return programID; } 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); // Компиляция шейдеров GLuint shaderProgram = LoadShaders("shaders/shader.vert", "shaders/shader.frag"); // Активация шейдера glUseProgram(shaderProgram); // Установим значения текстур Texture::init_textures(shaderProgram); // Загрузка сцены из obj файла Scene scene = loadOBJtoScene("../resources/models/cubes.obj", "../resources/models/", "../resources/textures/"); // Установка цвета очистки буфера цвета glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Расположение Uniform-переменной GLuint vp_uniform = glGetUniformLocation(shaderProgram, "vp"); GLuint model_uniform = glGetUniformLocation(shaderProgram, "model"); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Использование уменьшенных версий mipmap // Пока не произойдет событие запроса закрытия окна while(!glfwWindowShouldClose(window)) { // Загрузим матрицу проекции*вида glUniformMatrix4fv(vp_uniform, 1, GL_FALSE, &Camera::current().getVP()[0][0]); // Очистка буфера цвета glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Тут производится рендер scene.render(model_uniform); // Представление содержимого буфера цепочки показа на окно glfwSwapBuffers(window); // Обработка системных событий glfwPollEvents(); } // Удаление шейдерной программы glDeleteProgram(shaderProgram); return 0; }