#include #include #include #include #include #ifdef _DEBUG #include #include #include #endif #include "Controller.h" #include "Entity.h" #include "Helper.h" #include "JsonParser.h" #include "Model.h" #include "Screen.h" #include "Texture.h" #include "VertexArray.h" #include "Widget.h" #include "World.h" Controller::Controller() { gameWindow = new Window(); gameEventHandler = new EventHandler(gameWindow->getGLFWwindow()); camera = new Camera(90.0f, gameWindow->getWindowAspectRatio()); JsonParser shaderParser("data/shaderPrograms.json"); shaderPrograms = shaderParser.getShaderPrograms(); pp_framebuffer = new Framebuffer(gameWindow->getWindowWidth(), gameWindow->getWindowHeight(), getShaderProgramByName("postProcessingProgram")); menu = new Menu(pp_framebuffer, getShaderProgramByName("menuProgram")); // Show loading screen... glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); menu->showScreenByName("loadingScreen"); glfwSwapBuffers(gameWindow->getGLFWwindow()); // Show main menu when loading is finished... menu->showScreenByName("mainMenuScreen"); world = new World(shaderPrograms); #ifdef _DEBUG // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO &io = ImGui::GetIO(); (void)io; // Setup Platform/Renderer bindings ImGui_ImplGlfw_InitForOpenGL(gameWindow->getGLFWwindow(), true); ImGui_ImplOpenGL3_Init("#version 150"); // Setup Dear ImGui style ImGui::StyleColorsDark(); #endif } Controller::~Controller() { #ifdef _DEBUG ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); #endif for (auto it = shaderPrograms.begin(); it != shaderPrograms.end(); it++) { delete *it; } delete world; delete camera; delete menu; delete pp_framebuffer; delete gameEventHandler; delete gameWindow; } void Controller::run() { updateExposure(getShaderProgramByName("postProcessingProgram")); Entity *lightSource = world->getEntityByName("light"); lightSource->setScale(0.1f); lightSource->setRotation(glm::vec3(0.f)); lightSource->setPosition(glm::vec3(-2.f, 1.5f, 2.f)); lightSource->setIsLightSource(true); camera->translate(glm::vec3(0.0f, 1.5f, 5.0f)); // This is the game loop while (!glfwWindowShouldClose(gameWindow->getGLFWwindow())) { // --- Timing --- limit_framerate(); // --- Update game --- static bool rotateLightSource = false, rotateEntity = false; if (rotateLightSource) { float radius = 4.0; glm::vec3 newPos = glm::vec3(-cos(glfwGetTime() * 0.5), 0.5f, sin(glfwGetTime() * 0.5)) * radius; world->getEntityByName("light")->setPosition(newPos); } if (rotateEntity) { world->getEntityById(0)->rotate(glm::vec3(0.0f, 1.0f, 0.0f), -0.2f * deltaTime); } static glm::vec3 lightColor = glm::vec3(1.f); static float intensity = 7.5f; world->updatePointLight(0, true, world->getEntityByName("light")->getPosition(), lightColor, intensity); world->updateDirectionalLight(true, world->getDirectionalLight()->getDirection(), lightColor); getShaderProgramByName("lightProgram")->bind(); getShaderProgramByName("lightProgram")->setUniform("v_lightColor", lightColor * 100.0f); getShaderProgramByName("lightProgram")->unbind(); // --- Render and buffer swap --- // Calc shadows static bool drawShadows = false; static bool firstRun = true; getShaderProgramByName("defaultProgram")->bind(); getShaderProgramByName("defaultProgram")->setUniform("b_drawShadows", (int)drawShadows); getShaderProgramByName("defaultProgram")->unbind(); if (drawShadows || firstRun) { firstRun = false; world->calculateShadows(getShaderProgramByName("directionalShadowDepthProgram"), getShaderProgramByName("pointShadowDepthProgram")); } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); auto activeScreen = menu->getActiveScreen(); if (activeScreen) { activeScreen->draw(); } else { pp_framebuffer->bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->lookForward(); camera->updateVPM(); world->getSkybox()->draw(camera->getView(), camera->getProj()); world->draw(camera->getViewProj(), camera->getPosition()); pp_framebuffer->unbind(); pp_framebuffer->render(); #ifdef _DEBUG renderImGui(world, &lightColor, &rotateEntity, &rotateLightSource, getShaderProgramByName("postProcessingProgram"), &intensity, &drawShadows); #endif } glfwSwapBuffers(gameWindow->getGLFWwindow()); // Update window size if (gameWindow->isWindowResized()) { gameWindow->updateWindowDimensions(); updateWindowDimensions(); } // --- Check events, handle input --- gameEventHandler->handleEvents(); camera->updatePositionFromKeyboardInput(gameEventHandler->getCameraActionRegister(), deltaTime); if (gameWindow->getMouseIsCatched()) { camera->updateDirectionFromMouseInput(gameEventHandler->getCursorDelta()); } menu->writeWindowActions(gameEventHandler->getWindowActionRegister()); gameWindow->handleWindowActionRegister(gameEventHandler->getWindowActionRegister()); // Handle widget pressed event only when a screen is currently active if (menu->getActiveScreen()) menu->handleMouseButtonActionRegister(gameEventHandler->getMouseButtonActionRegister(), gameWindow); } } void Controller::limit_framerate() { static double startingTime = 0.0; static double lastTime = 0.0; lastTime = glfwGetTime() - startingTime; double frameTime = 1 / (double)MAX_FPS; if (frameTime > lastTime) { Helper::sleep((frameTime - lastTime) * 1000000); } deltaTime = glfwGetTime() - startingTime; startingTime = glfwGetTime(); } void Controller::updateWindowDimensions() { camera->updateAspectRatio(gameWindow->getWindowAspectRatio()); gameEventHandler->setFirstMouseInput(1); pp_framebuffer->changeDimensions(gameWindow->getWindowWidth(), gameWindow->getWindowHeight()); } void Controller::updateExposure(ShaderProgram *shaderProgram) { shaderProgram->bind(); shaderProgram->setUniform("u_exposure", exposure); shaderProgram->unbind(); } ShaderProgram *Controller::getShaderProgramByName(const std::string &name) { for (auto it = shaderPrograms.begin(); it != shaderPrograms.end(); it++) { if ((*it)->getUniqueName() == name) { return *it; } } std::cout << "[Warning] ShaderProgram could not be found by name \"" << name << "\"" << std::endl; return nullptr; } ShaderProgram *Controller::getShaderProgramByName(std::vector shaderPrograms, const std::string &name) { for (auto it = shaderPrograms.begin(); it != shaderPrograms.end(); it++) { if ((*it)->getUniqueName() == name) { return *it; } } std::cout << "[Warning] ShaderProgram could not be found by name \"" << name << "\"" << std::endl; return nullptr; } void Controller::setMaxFps(uint16_t fps) { MAX_FPS = fps; } #ifdef _DEBUG void Controller::renderImGui(World *world, glm::vec3 *lightColor, bool *rotateEntity, bool *rotateLightSource, ShaderProgram *postProcessingProgram, float *intensity, bool *drawShadows) { ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); // render your GUI ImGui::Begin("Debug Utils"); ImGui::Text("Object"); static float rotation = 0.0; ImGui::SliderFloat("Rotation", &rotation, 0, 2 * M_PI); static float translation[] = {0.0f, 1.0f, 0.0f}; ImGui::SliderFloat3("Position", translation, -4.0, 4.0); static float scale = 0.6f; ImGui::SliderFloat("Scale", &scale, 0.02, 2.0); ImGui::Checkbox("Rotate Object", rotateEntity); Entity *mainObject = world->getEntityById(0); mainObject->setPosition(glm::vec3(translation[0], translation[1], translation[2])); if (!*rotateEntity) { mainObject->setRotation(glm::vec3(0.f, 1.0f, 0.f), rotation); } mainObject->setScale(scale); // color picker ImGui::Text("\nLight Source"); updateExposure(postProcessingProgram); static float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; ImGui::SliderFloat("Intensity", intensity, 0, 250.f); ImGui::ColorEdit3("Color", color); lightColor->x = color[0]; lightColor->y = color[1]; lightColor->z = color[2]; ImGui::Text("\nMiscellaneous"); ImGui::SliderFloat("Exposure", &exposure, 0, 5.0f); ImGui::Checkbox("Draw Shadows", drawShadows); ImGui::Checkbox("Rotate Lightsource", rotateLightSource); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0 / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGui::End(); ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } #endif