272 lines
7.9 KiB
C++
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;
|
|
}
|
|
|
|
}
|