tes-tiger/utilities.cpp
2018-06-15 18:48:45 +05:00

305 lines
8.6 KiB
C++

#include <string>
using std::string;
#include <fstream>
using std::ifstream;
using std::istreambuf_iterator;
#include <iostream>
using std::cerr;
using std::endl;
#include <exception>
using std::exception;
#include <initializer_list>
using std::initializer_list;
#include <utility>
using std::pair;
#include <functional>
using std::function;
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <SOIL/SOIL.h>
#include <glm/glm.hpp>
using glm::vec3;
using glm::cross;
using glm::dot;
using glm::normalize;
using glm::radians;
using glm::mat4;
#include <glm/gtc/matrix_transform.hpp>
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<float>(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<float>(x);
auto yf = static_cast<float>(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<void ()>& 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<size_t>(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<float>(frameBufferWidth) / static_cast<float>(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<char>(file),
istreambuf_iterator<char>()
);
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<pair<const GLenum, const string>>& 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<const vec3, const vec3> findPlaneBasis(const vec3& normal) noexcept {
pair<vec3, vec3> 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;
}