#include "engine.h" #include #include #include #include #include #include #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION #include #include #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 cb : kekData.mouseCallbacks) { cb.second(window, x, y); } } void onKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { for(std::pair 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 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 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 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; } }