2022-10-11 17:27:22 +02:00

272 lines
7.9 KiB
C++

#include "engine.h"
#include <iostream>
#include <cstring>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/gtc/type_ptr.hpp>
#include <chrono>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <stb/stb_image.h>
#include <stb/stb_image_write.h>
#include "internal.h"
#include "errordialog.h"
#include "objparser.h"
#include "resource.h"
#include "camera.h"
#include "constants.h"
#include "gameobject.h"
#include "scene.h"
kek::KekData kek::kekData;
namespace kek::Engine {
static void framebufferSizeCallback(GLFWwindow *window, int w, int h) {
glViewport(0, 0, w, h);
kekData.screenWidth = w;
kekData.screenHeight = h;
}
static void glDebugOutput(GLenum source, GLenum type, unsigned int id, GLenum severity, GLsizei length, const char *message, const void *userParam) {
//if(id == 0x20071) return;
if(severity == GL_DEBUG_SEVERITY_NOTIFICATION) return;
std::cout << "OpenGL Debug (" << id << "): " << message << std::endl;
}
void onCursorPosCallback(GLFWwindow *window, double x, double y) {
static bool firstMouse = true;
static double lastX = 0, lastY = 0;
if(firstMouse) {
lastX = x;
lastY = y;
firstMouse = false;
}
float xoff = lastX - x;
float yoff = lastY - y;
lastX = x;
lastY = y;
xoff *= 0.1f;
yoff *= 0.1f;
kekData.activeCamera->rotateYaw(xoff);
kekData.activeCamera->rotatePitch(yoff);
for(std::pair<InputListener, MouseCallback> cb : kekData.mouseCallbacks) {
cb.second(window, x, y);
}
}
void onKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) {
for(std::pair<InputListener, KeyCallback> cb : kekData.keyCallbacks) {
cb.second(window, key, scancode, action, mods);
}
}
int init() {
// Init GLFW
if (glfwInit() != GL_TRUE) {
const char *errorMsg;
int code = glfwGetError(&errorMsg);
if(code != GLFW_NO_ERROR) {
ErrorDialog::showError("Failed to initialize GLFW: " + std::string(errorMsg) + std::string(" (") + std::to_string(code) + std::string(")"));
}else {
ErrorDialog::showError("Failed to initialize GLFW: Unknown error");
}
return KEK_ERROR;
}
std::cout << "Initialized GLFW" << std::endl;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_MAXIMIZED, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);
kekData.screenWidth = 800.0f;
kekData.screenHeight = 600.0f;
kekData.window = glfwCreateWindow(kekData.screenWidth, kekData.screenHeight, "KekEngine", NULL, NULL);
if(!kekData.window) {
const char *errorMsg;
int code = glfwGetError(&errorMsg);
if(code != GLFW_NO_ERROR) {
ErrorDialog::showError("Failed to create window: " + std::string(errorMsg) + " (" + std::to_string(code) + ")");
}else {
ErrorDialog::showError("Failed to create window: Unknown error");
}
glfwTerminate();
return KEK_ERROR;
}
glfwMakeContextCurrent(kekData.window);
std::cout << "Initialized window" << std::endl;
// Init GLEW
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
ErrorDialog::showError("Failed to initialize GLEW");
glfwTerminate();
return KEK_ERROR;
}
std::cout << "Initialized GLEW" << std::endl;
std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
int flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) {
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(glDebugOutput, NULL);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
}
glViewport(0, 0, kekData.screenWidth, kekData.screenHeight);
glfwSetFramebufferSizeCallback(kekData.window, framebufferSizeCallback);
glEnable(GL_DEPTH_TEST);
glEnable(GL_MULTISAMPLE);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
if(Resource::init() != KEK_SUCCESS) {
glfwTerminate();
return KEK_ERROR;
}
glfwSetCursorPosCallback(kekData.window, onCursorPosCallback);
glfwSetInputMode(kekData.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glClearColor(0.1f, 0.3f, 0.1f, 0.0f);
// glfwSwapInterval(0);
stbi_set_flip_vertically_on_load(true);
kekData.activeCamera = new Camera();
kekData.shader = new Shader("shader/mesh/vertex.glsl", "shader/mesh/fragment.glsl");
return KEK_SUCCESS;
}
int start() {
while(!glfwWindowShouldClose(kekData.window)) {
auto start = std::chrono::high_resolution_clock::now();
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, kekData.screenWidth, kekData.screenHeight);
for(std::pair<InputListener, PeriodicCallback> cb : kekData.periodicCallbacks) {
cb.second(kekData.window);
}
if(glfwGetKey(kekData.window, GLFW_KEY_W) == GLFW_PRESS) {
kekData.activeCamera->translate(kekData.activeCamera->direction * 0.1f);
}
if(glfwGetKey(kekData.window, GLFW_KEY_S) == GLFW_PRESS) {
kekData.activeCamera->translate(kekData.activeCamera->direction * -0.1f);
}
if(glfwGetKey(kekData.window, GLFW_KEY_A) == GLFW_PRESS) {
glm::vec3 camRight = glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
kekData.activeCamera->translate(-camRight * 0.1f);
}
if(glfwGetKey(kekData.window, GLFW_KEY_D) == GLFW_PRESS) {
glm::vec3 camRight = glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
kekData.activeCamera->translate(camRight * 0.1f);
}
if(glfwGetKey(kekData.window, GLFW_KEY_SPACE) == GLFW_PRESS) {
kekData.activeCamera->translateY(0.1f);
}
if(glfwGetKey(kekData.window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) {
kekData.activeCamera->translateY(-0.1f);
}
if(glfwGetKey(kekData.window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
break;
}
kekData.shader->use();
glm::mat4 view = kekData.activeCamera->transformationMatrix();
glm::mat4 projection;
projection = glm::perspective(glm::radians(90.0f), kekData.screenWidth / (float) kekData.screenHeight, KEK_CAMERA_NEAR, KEK_CAMERA_FAR);
glm::vec3 position = kekData.activeCamera->getPosition();
glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniform3fv(glGetUniformLocation(kekData.shader->id, "cameraPos"), 1, glm::value_ptr(position));
LightList *lights = kekData.activeScene->lights;
std::vector<Light *> shaderLights;
for(PointLight *light : lights->point) {
if(glm::abs(light->getPosition() - kekData.activeCamera->getPosition()).length() < 10) {
shaderLights.push_back(light);
}
}
glUniform1i(glGetUniformLocation(kekData.shader->id, "numPointLights"), 1);
unsigned int i = 0;
for(Light *light : shaderLights) {
std::string prefix = "lights[" + std::to_string(i) + "].";
switch(light->getType()) {
case LightType::POINT:
{
PointLight *l = (PointLight *) light;
glUniform3fv(glGetUniformLocation(kekData.shader->id, (prefix + "position").c_str()), 1, glm::value_ptr(l->getPosition()));
glUniform3fv(glGetUniformLocation(kekData.shader->id, (prefix + "color").c_str()), 1, glm::value_ptr(l->color));
glUniform3fv(glGetUniformLocation(kekData.shader->id, (prefix + "attenuation").c_str()), 1, glm::value_ptr(glm::vec3(l->constant, l->linear, l->quadratic)));
}
case LightType::DIRECTIONAL:
case LightType::SPOT:
break;
}
i++;
}
if(kekData.activeScene) kekData.activeScene->draw(kekData.shader);
// Swap buffers and poll window events
glfwSwapBuffers(kekData.window);
glfwPollEvents();
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<float> secsTaken = end - start;
// std::cout << "FT: " << secsTaken.count() * 1000 << std::endl;
// std::cout << "FR: " << (1.0f / secsTaken.count()) << std::endl;
}
return KEK_SUCCESS;
}
void setActiveScene(Scene *scene) {
kekData.activeScene = scene;
}
}