diff --git a/CMakeLists.txt b/CMakeLists.txt index 95da797..1b995e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,11 @@ cmake_minimum_required(VERSION 3.10) project(tes-tiger) -include_directories(includes) -link_directories(libraries) set(CMAKE_CXX_STANDARD 17) +include_directories(includes) +link_directories(libraries) + add_executable(tes-tiger includes/boost/property_tree/ptree.hpp includes/boost/property_tree/json_parser.hpp @@ -14,7 +15,9 @@ add_executable(tes-tiger includes/SOIL/SOIL.h includes/GL/glew.h includes/GLFW/glfw3.h + utilities.h glew.c + utilities.cpp main.cpp) target_link_libraries(tes-tiger diff --git a/main.cpp b/main.cpp index eca312f..4e487b8 100644 --- a/main.cpp +++ b/main.cpp @@ -1,189 +1,18 @@ -#include #include -#include #include -#include #include #define GLEW_STATIC -#include "GL/glew.h" -#include "GLFW/glfw3.h" -#include "SOIL/SOIL.h" -#include "glm/glm.hpp" -#include "glm/gtc/matrix_transform.hpp" -#include "glm/gtc/type_ptr.hpp" -#include "boost/property_tree/ptree.hpp" -#include "boost/property_tree/json_parser.hpp" +#include +#include +#include +#include +#include +#include -const int windowWidth = 800; -const int windowHeight = 600; +#include "utilities.h" const float pi = 3.14159f; - -std::string readFile(const std::string& filePath) { - std::ifstream file(filePath); - auto result = std::string( - std::istreambuf_iterator(file), - std::istreambuf_iterator() - ); - file.close(); - return result; -} -const GLuint loadShader(const GLenum& shaderType, const std::string& shaderFilePath) { - const GLuint shader = glCreateShader(shaderType); - auto shaderSource = readFile(shaderFilePath); - auto shaderSourceC = shaderSource.c_str(); - glShaderSource(shader, 1, &shaderSourceC, nullptr); - glCompileShader(shader); - GLint success; - GLchar infoLog[512]; - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if(!success) { - glGetShaderInfoLog(shader, 512, nullptr, infoLog); - std::cout << "Failed to compile shader: " << infoLog << std::endl; - } - - return shader; -} -const GLuint linkShaderProgram(const std::initializer_list>& shadersInfo) { - const GLuint shaderProgram = glCreateProgram(); - for(const auto& shaderInfo: shadersInfo) { - auto shader = loadShader(shaderInfo.first, shaderInfo.second); - glAttachShader(shaderProgram, shader); - glDeleteShader(shader); - } - glLinkProgram(shaderProgram); - { - GLint success; - GLchar infoLog[512]; - glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); - if(!success) { - glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); - std::cout << "Failed to link shader program: " << infoLog << std::endl; - } - } - - return shaderProgram; -} -GLuint loadTexture(const std::string& textureFilePath) { - int imageWidth, imageHeight; - unsigned char *imageData = SOIL_load_image( - textureFilePath.c_str(), - &imageWidth, &imageHeight, - nullptr, SOIL_LOAD_RGB - ); - GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imageWidth, imageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - SOIL_free_image_data(imageData); - - return texture; -} - -auto cameraPosition = glm::vec3(0.0f, 0.0f, 512.0f); -auto cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); -auto cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); - -bool keyPressed[1024]; -void keyCallback(GLFWwindow* /* window */, int key, int /* scanCode */, int action, int /* mode */) { - if(key == GLFW_KEY_W) { - if(action == GLFW_PRESS) { - keyPressed[GLFW_KEY_W] = true; - } else if(action == GLFW_RELEASE) { - keyPressed[GLFW_KEY_W] = false; - } - } else if(key == GLFW_KEY_S) { - if(action == GLFW_PRESS) { - keyPressed[GLFW_KEY_S] = true; - } else if(action == GLFW_RELEASE) { - keyPressed[GLFW_KEY_S] = false; - } - } else if(key == GLFW_KEY_A) { - if(action == GLFW_PRESS) { - keyPressed[GLFW_KEY_A] = true; - } else if(action == GLFW_RELEASE) { - keyPressed[GLFW_KEY_A] = false; - } - } else if(key == GLFW_KEY_D) { - if(action == GLFW_PRESS) { - keyPressed[GLFW_KEY_D] = true; - } else if(action == GLFW_RELEASE) { - keyPressed[GLFW_KEY_D] = false; - } - } -} -void moveCamera(double deltaTime) { - float cameraSpeed = 1024.0f * static_cast(deltaTime); - if(keyPressed[GLFW_KEY_W]) { - cameraPosition = cameraPosition + cameraSpeed * cameraFront; - } else if(keyPressed[GLFW_KEY_S]) { - cameraPosition = cameraPosition - cameraSpeed * cameraFront; - } else if(keyPressed[GLFW_KEY_A]) { - cameraPosition = cameraPosition - cameraSpeed * glm::normalize(glm::cross(cameraFront, cameraUp)); - } else if(keyPressed[GLFW_KEY_D]) { - cameraPosition = cameraPosition + cameraSpeed * glm::normalize(glm::cross(cameraFront, cameraUp)); - } -} - -float lastX = windowWidth / 2.0f, lastY = windowHeight / 2.0f; -float yaw = -90.0f, pitch = 0.0f; -bool firstMouse = false; -void mouseCallback(GLFWwindow* /* window */, double x, double y) { - auto xf = static_cast(x); - auto yf = static_cast(y); - - if(!firstMouse) { - lastX = xf; lastY = yf; - firstMouse = true; - } - - auto offsetX = xf - lastX, offsetY = lastY - yf; - lastX = xf; lastY = yf; - - float sensivity = 0.05f; - offsetX *= sensivity; - offsetY *= sensivity; - - yaw += offsetX; - pitch += offsetY; - - if(pitch > 89.0f) { - pitch = 89.0f; - } else if(pitch < -89.0f) { - pitch = -89.0f; - } - - glm::vec3 newCameraFront; - newCameraFront.x = cosf(glm::radians(pitch)) * cosf(glm::radians(yaw)); - newCameraFront.y = sinf(glm::radians(pitch)); - newCameraFront.z = cosf(glm::radians(pitch)) * sinf(glm::radians(yaw)); - cameraFront = glm::normalize(newCameraFront); -} - -const std::pair findPlaneBasis(const glm::vec3& normal) { - std::pair result; - glm::vec3 e0, e1; - if(normal.z != 0.0f) { - e0 = glm::normalize(glm::vec3(1.0f, 0.0f, -normal.x / normal.z)); - e1 = glm::vec3(0.0f, 1.0f, -normal.y / normal.z); - } else if(normal.y != 0.0f) { - e0 = glm::normalize(glm::vec3(1.0f, -normal.x / normal.y, 0.0f)); - e1 = glm::vec3(0.0f, -normal.z / normal.y, 1.0f); - } else { - e0 = glm::normalize(glm::vec3(-normal.y / normal.x, 1.0f, 0.0f)); - e1 = glm::vec3(-normal.z / normal.x, 0.0f, 1.0f); - } - e1 = glm::normalize(e1 - (glm::dot(e1, e0) / glm::dot(e0, e0)) * e0); - - result.first = e0; - result.second = e1; - - return result; -} - const float radius = 8.0f; const float step = 100.0f; const float angle = pi / 6.0f; @@ -269,37 +98,7 @@ void bufferVertices( }; int main() { - if(glfwInit() != GLFW_TRUE) { - std::cout << "Failed to initialize glfw." << std::endl; - return -1; - } - - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); - - GLFWwindow* window = glfwCreateWindow(windowWidth, windowHeight, "gl", nullptr, nullptr); - if(window == nullptr) { - std::cout << "Failed to create window." << std::endl; - glfwTerminate(); - return -1; - } - glfwMakeContextCurrent(window); - glfwSetKeyCallback(window, keyCallback); - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - glfwSetCursorPosCallback(window, mouseCallback); - - glewExperimental = GL_TRUE; - if(glewInit() != GLEW_OK) { - std::cout << "Failed to initialize glew." << std::endl; - glfwTerminate(); - return -1; - } - - int frameBufferWidth, frameBufferHeight; - glfwGetFramebufferSize(window, &frameBufferWidth, &frameBufferHeight); - glViewport(0, 0, frameBufferWidth, frameBufferHeight); + setUp(); auto shaderProgram = linkShaderProgram({ {GL_VERTEX_SHADER, "../resources/shader.vertex"}, @@ -339,9 +138,9 @@ int main() { }); auto threadTexture = loadTexture("../resources/fabric.jpg"); + setWindowTitle("parsing lines.json"); boost::property_tree::ptree root; - glfwSetWindowTitle(window, "parsing lines.json..."); - boost::property_tree::read_json("../resources/lines100500.json", root); + boost::property_tree::read_json("../resources/line.json", root); size_t linesCount = 0; for(const auto& line: root.get_child("lines")) { @@ -385,7 +184,7 @@ int main() { lineIndex++; std::stringstream progressString; progressString << "loading " << lineIndex << "/" << linesCount; - glfwSetWindowTitle(window, progressString.str().c_str()); + setWindowTitle(progressString.str().c_str()); } GLuint threadVAO; @@ -406,31 +205,21 @@ int main() { glEnableVertexAttribArray(3); glBindVertexArray(0); - auto threadModelTransform = glm::mat4(1.0f); - threadModelTransform = glm::translate(threadModelTransform, glm::vec3(0.0f, 0.0f, 100.0f)); - auto projectionTransform = glm::infinitePerspective( - glm::radians(45.0f), - static_cast(frameBufferWidth) / static_cast(frameBufferHeight), - 0.1f - ); - double lastTime = 0.0f; + auto threadModelTransform = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 100.0f)); + glEnable(GL_DEPTH_TEST); // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - while(!glfwWindowShouldClose(window)) { - glfwPollEvents(); - - double currentTime = glfwGetTime(); - double deltaTime = currentTime - lastTime; - lastTime = currentTime; - moveCamera(deltaTime); - auto viewTransform = glm::lookAt( - cameraPosition, - cameraPosition + cameraFront, - cameraUp - ); - - glfwSetWindowTitle(window, std::to_string(static_cast(1.0 / deltaTime)).c_str()); + renderCycle([ + shaderProgram, + texture, + vertexArrayObject, + threadShaderProgram, + threadTexture, + threadModelTransform, + threadVAO, + verticesBuffer + ] () { glClearColor(0.5f, 0.5f, 1.0f, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); @@ -448,13 +237,13 @@ int main() { glGetUniformLocation(shaderProgram, "viewTransform"), 1, GL_FALSE, - glm::value_ptr(viewTransform) + glm::value_ptr(getViewTransform()) ); glUniformMatrix4fv( glGetUniformLocation(shaderProgram, "projectionTransform"), 1, GL_FALSE, - glm::value_ptr(projectionTransform) + glm::value_ptr(getProjectionTransform()) ); glBindVertexArray(vertexArrayObject); glDrawArrays(GL_TRIANGLES, 0, 6); @@ -474,21 +263,19 @@ int main() { glGetUniformLocation(threadShaderProgram, "viewTransform"), 1, GL_FALSE, - glm::value_ptr(viewTransform) + glm::value_ptr(getViewTransform()) ); glUniformMatrix4fv( glGetUniformLocation(threadShaderProgram, "projectionTransform"), 1, GL_FALSE, - glm::value_ptr(projectionTransform) + glm::value_ptr(getProjectionTransform()) ); glBindVertexArray(threadVAO); glDrawArrays(GL_TRIANGLES, 0, verticesBuffer.size()); glBindVertexArray(0); + }); - glfwSwapBuffers(window); - } - - glfwTerminate(); + tearDown(); return 0; } diff --git a/utilities.cpp b/utilities.cpp new file mode 100644 index 0000000..28f826b --- /dev/null +++ b/utilities.cpp @@ -0,0 +1,305 @@ +#include +using std::string; + +#include +using std::ifstream; +using std::istreambuf_iterator; + +#include +using std::cerr; +using std::endl; + +#include +using std::exception; + +#include +using std::initializer_list; + +#include +using std::pair; + +#include +using std::function; + +#define GLEW_STATIC +#include + +#include + +#include + +#include +using glm::vec3; +using glm::cross; +using glm::dot; +using glm::normalize; +using glm::radians; +using glm::mat4; + +#include +using glm::lookAt; +using glm::infinitePerspective; + +#include "utilities.h" + +const int windowWidth = 1600; +const int windowHeight = 900; +vec3 cameraPosition, cameraFront, cameraUp; +bool keyPressed[1024]; + +void keyCallback(GLFWwindow* /* window */, int key, int /* scanCode */, int action, int /* mode */) { + if(key == GLFW_KEY_W) { + if(action == GLFW_PRESS) { + keyPressed[GLFW_KEY_W] = true; + } else if(action == GLFW_RELEASE) { + keyPressed[GLFW_KEY_W] = false; + } + } else if(key == GLFW_KEY_S) { + if(action == GLFW_PRESS) { + keyPressed[GLFW_KEY_S] = true; + } else if(action == GLFW_RELEASE) { + keyPressed[GLFW_KEY_S] = false; + } + } else if(key == GLFW_KEY_A) { + if(action == GLFW_PRESS) { + keyPressed[GLFW_KEY_A] = true; + } else if(action == GLFW_RELEASE) { + keyPressed[GLFW_KEY_A] = false; + } + } else if(key == GLFW_KEY_D) { + if(action == GLFW_PRESS) { + keyPressed[GLFW_KEY_D] = true; + } else if(action == GLFW_RELEASE) { + keyPressed[GLFW_KEY_D] = false; + } + } +} + +void moveCamera(double deltaTime) { + float cameraSpeed = 1024.0f * static_cast(deltaTime); + if(keyPressed[GLFW_KEY_W]) { + cameraPosition = cameraPosition + cameraSpeed * cameraFront; + } else if(keyPressed[GLFW_KEY_S]) { + cameraPosition = cameraPosition - cameraSpeed * cameraFront; + } else if(keyPressed[GLFW_KEY_A]) { + cameraPosition = cameraPosition - cameraSpeed * normalize(cross(cameraFront, cameraUp)); + } else if(keyPressed[GLFW_KEY_D]) { + cameraPosition = cameraPosition + cameraSpeed * normalize(cross(cameraFront, cameraUp)); + } +} + +float lastX = windowWidth / 2.0f, lastY = windowHeight / 2.0f; +float yaw = -90.0f, pitch = 0.0f; +bool firstMouse = false; +void mouseCallback(GLFWwindow* /* window */, double x, double y) { + auto xf = static_cast(x); + auto yf = static_cast(y); + + if(!firstMouse) { + lastX = xf; lastY = yf; + firstMouse = true; + } + + auto offsetX = xf - lastX, offsetY = lastY - yf; + lastX = xf; lastY = yf; + + float sensivity = 0.05f; + offsetX *= sensivity; + offsetY *= sensivity; + + yaw += offsetX; + pitch += offsetY; + + if(pitch > 89.0f) { + pitch = 89.0f; + } else if(pitch < -89.0f) { + pitch = -89.0f; + } + + vec3 newCameraFront; + newCameraFront.x = cosf(radians(pitch)) * cosf(radians(yaw)); + newCameraFront.y = sinf(radians(pitch)); + newCameraFront.z = cosf(radians(pitch)) * sinf(radians(yaw)); + cameraFront = normalize(newCameraFront); +} + +GLFWwindow* window = nullptr; +void setUp() noexcept(false) { + if(glfwInit() != GLFW_TRUE) { + cerr << "Failed to initialize glfw." << endl; + throw exception(); + } + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + + window = glfwCreateWindow(windowWidth, windowHeight, "tes-tiger", nullptr, nullptr); + if(window == nullptr) { + cerr << "Failed to create window." << endl; + glfwTerminate(); + throw exception(); + } + + glfwMakeContextCurrent(window); + + cameraPosition = vec3(0.0f, 0.0f, 512.0f); + cameraFront = vec3(0.0f, 0.0f, -1.0f); + cameraUp = vec3(0.0f, 1.0f, 0.0f); + + glfwSetKeyCallback(window, keyCallback); + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwSetCursorPosCallback(window, mouseCallback); + + glewExperimental = GL_TRUE; + if(glewInit() != GLEW_OK) { + cerr << "Failed to initialize glew." << endl; + glfwTerminate(); + throw exception(); + } + + int frameBufferWidth, frameBufferHeight; + glfwGetFramebufferSize(window, &frameBufferWidth, &frameBufferHeight); + glViewport(0, 0, frameBufferWidth, frameBufferHeight); +} + +void tearDown() noexcept { + glfwTerminate(); + window = nullptr; +} + +void setWindowTitle(const char* title) noexcept { + glfwSetWindowTitle(window, title); +} + +void renderCycle(const function& renderRoutine) noexcept { + double lastTime = 0.0f; + + while(!glfwWindowShouldClose(window)) { + glfwPollEvents(); + + double currentTime = glfwGetTime(); + double deltaTime = currentTime - lastTime; + lastTime = currentTime; + moveCamera(deltaTime); + setWindowTitle(std::to_string(static_cast(1.0 / deltaTime)).c_str()); + + renderRoutine(); + + glfwSwapBuffers(window); + } +} + +mat4 getViewTransform() noexcept { + return lookAt( + cameraPosition, + cameraPosition + cameraFront, + cameraUp + ); +} + +mat4 getProjectionTransform() noexcept { + int frameBufferWidth, frameBufferHeight; + glfwGetFramebufferSize(window, &frameBufferWidth, &frameBufferHeight); + auto ratio = static_cast(frameBufferWidth) / static_cast(frameBufferHeight); + + return infinitePerspective(radians(45.0f), ratio, 0.1f); +} + +string readFile(const string& filePath) noexcept(false) { + ifstream file(filePath); + if(!file.good()) { + cerr << "Failed to open file '" << filePath << "'." << endl; + throw exception(); + } + + auto result = string( + istreambuf_iterator(file), + istreambuf_iterator() + ); + file.close(); + + return result; +} + +const GLuint loadShader(const GLenum& shaderType, const string& shaderFilePath) noexcept(false) { + const GLuint shader = glCreateShader(shaderType); + auto shaderSource = readFile(shaderFilePath); + auto shaderSourceC = shaderSource.c_str(); + glShaderSource(shader, 1, &shaderSourceC, nullptr); + glCompileShader(shader); + + GLint success; + GLchar infoLog[512]; + glGetShaderiv(shader, GL_COMPILE_STATUS, &success); + if(!success) { + glGetShaderInfoLog(shader, 512, nullptr, infoLog); + cerr << "Failed to compile shader '" << shaderFilePath << "': " << infoLog << endl; + throw exception(); + } + + return shader; +} + +const GLuint linkShaderProgram(const initializer_list>& shadersInfo) noexcept(false) { + const GLuint shaderProgram = glCreateProgram(); + for(const auto& shaderInfo: shadersInfo) { + auto shader = loadShader(shaderInfo.first, shaderInfo.second); + glAttachShader(shaderProgram, shader); + glDeleteShader(shader); + } + glLinkProgram(shaderProgram); + { + GLint success; + GLchar infoLog[512]; + glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); + if(!success) { + glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); + cerr << "Failed to link shader program: " << infoLog << endl; + throw exception(); + } + } + + return shaderProgram; +} + +GLuint loadTexture(const string& textureFilePath) noexcept { + int imageWidth, imageHeight; + unsigned char *imageData = SOIL_load_image( + textureFilePath.c_str(), + &imageWidth, &imageHeight, + nullptr, SOIL_LOAD_RGB + ); + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imageWidth, imageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + SOIL_free_image_data(imageData); + + + return texture; +} + +const pair findPlaneBasis(const vec3& normal) noexcept { + pair result; + vec3 e0, e1; + if(normal.z != 0.0f) { + e0 = normalize(vec3(1.0f, 0.0f, -normal.x / normal.z)); + e1 = vec3(0.0f, 1.0f, -normal.y / normal.z); + } else if(normal.y != 0.0f) { + e0 = normalize(vec3(1.0f, -normal.x / normal.y, 0.0f)); + e1 = vec3(0.0f, -normal.z / normal.y, 1.0f); + } else { + e0 = normalize(vec3(-normal.y / normal.x, 1.0f, 0.0f)); + e1 = vec3(-normal.z / normal.x, 0.0f, 1.0f); + } + e1 = normalize(e1 - (dot(e1, e0) / dot(e0, e0)) * e0); + + result.first = e0; + result.second = e1; + + return result; +} diff --git a/utilities.h b/utilities.h new file mode 100644 index 0000000..fc9245a --- /dev/null +++ b/utilities.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include + +#define GLEW_STATIC +#include "GL/glew.h" +#include "glm/glm.hpp" + +void moveCamera(double); +void setUp() noexcept(false); +void tearDown() noexcept; +void setWindowTitle(const char*) noexcept; +void renderCycle(const std::function&) noexcept; +glm::mat4 getViewTransform() noexcept; +glm::mat4 getProjectionTransform() noexcept; +std::string readFile(const std::string&) noexcept(false); +const GLuint loadShader(const GLenum&, const std::string&) noexcept(false); +const GLuint linkShaderProgram(const std::initializer_list>&) noexcept(false); +GLuint loadTexture(const std::string&) noexcept; +const std::pair findPlaneBasis(const glm::vec3& normal) noexcept;