#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; }