<commit_before>/*
 * Copyright (c) 2013 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <Engine.h>
#include <Logger.h>
#include <ObjectManager.h>
#include <RenderManager.h>
#include <EngineConfig.h>
#if defined(_WIN32)
#include <Win32Window.h>
#elif defined(__linux__)
#include <LinuxWindow.h>
#endif
#include <chrono>
#include <thread>
#include <sstream>
#include <unordered_map>

namespace Graphene {

std::unordered_map<GLenum, std::string> sourceMap = {
    { GL_DEBUG_SOURCE_API_ARB,             "OpenGL" },
    { GL_DEBUG_SOURCE_SHADER_COMPILER_ARB, "GLSL" },
    { GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB,   "Window system" },
    { GL_DEBUG_SOURCE_THIRD_PARTY_ARB,     "3rd party" },
    { GL_DEBUG_SOURCE_APPLICATION_ARB,     "Application" },
    { GL_DEBUG_SOURCE_OTHER_ARB,           "Other" }
};

std::unordered_map<GLenum, std::string> typeMap = {
    { GL_DEBUG_TYPE_ERROR_ARB,               "Error" },
    { GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, "Deprecated" },
    { GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB,  "Undefined" },
    { GL_DEBUG_TYPE_PERFORMANCE_ARB,         "Performance" },
    { GL_DEBUG_TYPE_PORTABILITY_ARB,         "Portability" },
    { GL_DEBUG_TYPE_OTHER_ARB,               "Other" }
};

void debugHandler(GLenum source, GLenum type, GLuint /*id*/, GLenum /*severity*/,
        GLsizei /*length*/, const GLchar* message, const GLvoid* /*userParam*/) {
    LogDebug("%s [%s]: %s", sourceMap[source].c_str(), typeMap[type].c_str(), message);
}

Engine::Engine() {
    if (GetEngineConfig().isDebug()) {
        GetLogger().setLogLevel(LogLevel::LOG_DEBUG);
    }
}

const std::unordered_set<std::shared_ptr<FrameBuffer>>& Engine::getFrameBuffers() const {
    return this->frameBuffers;
}

const std::shared_ptr<FrameBuffer>& Engine::createFrameBuffer(int width, int height, GLenum format) {
    auto frameBuffer = std::make_shared<FrameBuffer>(width, height, format);
    return *this->frameBuffers.insert(frameBuffer).first;
}

const std::unordered_set<std::shared_ptr<Scene>>& Engine::getScenes() const {
    return this->scenes;
}

const std::shared_ptr<Scene>& Engine::createScene(const std::string& name) {
    auto scene = GetObjectManager().createScene(name);
    return *this->scenes.insert(scene).first;
}

const std::shared_ptr<Scene>& Engine::createScene() {
    auto scene = std::make_shared<Scene>();
    return *this->scenes.insert(scene).first;
}

const std::shared_ptr<Window>& Engine::getWindow() const {
    return this->window;
}

float Engine::getFrameTime() const {
    return this->frameTime;
}

void Engine::exit(int result) {
    this->result = result;
    this->running = false;
}

int Engine::exec() {
    std::chrono::time_point<std::chrono::steady_clock> timestamp;

    auto& config = GetEngineConfig();
    LogInfo("Engine configuration:\n%s", config.toString().c_str());

    this->setupWindow();
    this->setupOpenGL();
    this->setupEngine();
    this->onSetupSignal();

    while (this->running) {
        timestamp = std::chrono::steady_clock::now();

        if (this->window->dispatchEvents()) {
            this->onQuitSignal();
            this->exit(0);
        } else {
            this->onIdleSignal();
            this->update();
        }

        std::chrono::duration<float> duration = std::chrono::steady_clock::now() - timestamp;
        this->frameTime = duration.count();
        float maxFps = config.getMaxFps();

        if (!config.isVsync() && maxFps > 0.0f) {
            float maxFrameTime = 1.0f / maxFps;

            if (this->frameTime < maxFrameTime) {
                std::this_thread::sleep_for(std::chrono::duration<float>(maxFrameTime - this->frameTime));
                this->frameTime = maxFrameTime;
            }
        }

        this->renderTime += this->getFrameTime();
        this->frames++;

        if (this->renderTime >= 1.0f) {
            float fps = this->frames / this->renderTime;
            LogInfo("%d frames in %.1f seconds = %.3f fps", this->frames, this->renderTime, fps);

            this->renderTime = 0.0f;
            this->frames = 0;
        }
    }

    this->onTeardownSignal();
    this->teardownEngine();

    return this->result;
}

void Engine::setupWindow() {<commit_msg>Recalculate frame duration if std::this_thread::sleep_for() was unreliable<commit_after>/*
 * Copyright (c) 2013 <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include <Engine.h>
#include <Logger.h>
#include <ObjectManager.h>
#include <RenderManager.h>
#include <EngineConfig.h>
#if defined(_WIN32)
#include <Win32Window.h>
#elif defined(__linux__)
#include <LinuxWindow.h>
#endif
#include <chrono>
#include <thread>
#include <sstream>
#include <unordered_map>

namespace Graphene {

std::unordered_map<GLenum, std::string> sourceMap = {
    { GL_DEBUG_SOURCE_API_ARB,             "OpenGL" },
    { GL_DEBUG_SOURCE_SHADER_COMPILER_ARB, "GLSL" },
    { GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB,   "Window system" },
    { GL_DEBUG_SOURCE_THIRD_PARTY_ARB,     "3rd party" },
    { GL_DEBUG_SOURCE_APPLICATION_ARB,     "Application" },
    { GL_DEBUG_SOURCE_OTHER_ARB,           "Other" }
};

std::unordered_map<GLenum, std::string> typeMap = {
    { GL_DEBUG_TYPE_ERROR_ARB,               "Error" },
    { GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, "Deprecated" },
    { GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB,  "Undefined" },
    { GL_DEBUG_TYPE_PERFORMANCE_ARB,         "Performance" },
    { GL_DEBUG_TYPE_PORTABILITY_ARB,         "Portability" },
    { GL_DEBUG_TYPE_OTHER_ARB,               "Other" }
};

void debugHandler(GLenum source, GLenum type, GLuint /*id*/, GLenum /*severity*/,
        GLsizei /*length*/, const GLchar* message, const GLvoid* /*userParam*/) {
    LogDebug("%s [%s]: %s", sourceMap[source].c_str(), typeMap[type].c_str(), message);
}

Engine::Engine() {
    if (GetEngineConfig().isDebug()) {
        GetLogger().setLogLevel(LogLevel::LOG_DEBUG);
    }
}

const std::unordered_set<std::shared_ptr<FrameBuffer>>& Engine::getFrameBuffers() const {
    return this->frameBuffers;
}

const std::shared_ptr<FrameBuffer>& Engine::createFrameBuffer(int width, int height, GLenum format) {
    auto frameBuffer = std::make_shared<FrameBuffer>(width, height, format);
    return *this->frameBuffers.insert(frameBuffer).first;
}

const std::unordered_set<std::shared_ptr<Scene>>& Engine::getScenes() const {
    return this->scenes;
}

const std::shared_ptr<Scene>& Engine::createScene(const std::string& name) {
    auto scene = GetObjectManager().createScene(name);
    return *this->scenes.insert(scene).first;
}

const std::shared_ptr<Scene>& Engine::createScene() {
    auto scene = std::make_shared<Scene>();
    return *this->scenes.insert(scene).first;
}

const std::shared_ptr<Window>& Engine::getWindow() const {
    return this->window;
}

float Engine::getFrameTime() const {
    return this->frameTime;
}

void Engine::exit(int result) {
    this->result = result;
    this->running = false;
}

int Engine::exec() {
    std::chrono::time_point<std::chrono::steady_clock> timestamp;

    auto& config = GetEngineConfig();
    LogInfo("Engine configuration:\n%s", config.toString().c_str());

    this->setupWindow();
    this->setupOpenGL();
    this->setupEngine();
    this->onSetupSignal();

    while (this->running) {
        timestamp = std::chrono::steady_clock::now();

        if (this->window->dispatchEvents()) {
            this->onQuitSignal();
            this->exit(0);
        } else {
            this->onIdleSignal();
            this->update();
        }

        std::chrono::duration<float> frameDuration = std::chrono::steady_clock::now() - timestamp;
        this->frameTime = frameDuration.count();

        float maxFps = config.getMaxFps();
        if (maxFps > 0.0f && !config.isVsync()) {
            float maxFrameTime = 1.0f / maxFps;
            if (this->frameTime < maxFrameTime) {
                std::this_thread::sleep_for(std::chrono::duration<float>(maxFrameTime - this->frameTime));

                // Recalculate duration if std::this_thread::sleep_for() was unreliable
                std::chrono::duration<float> finalDuration = std::chrono::steady_clock::now() - timestamp;
                this->frameTime = finalDuration.count();
            }
        }

        this->renderTime += this->getFrameTime();
        this->frames++;

        if (this->renderTime >= 1.0f) {
            float fps = this->frames / this->renderTime;
            LogInfo("%d frames in %.1f seconds = %.3f fps", this->frames, this->renderTime, fps);

            this->renderTime = 0.0f;
            this->frames = 0;
        }
    }

    this->onTeardownSignal();
    this->teardownEngine();

    return this->result;
}

void Engine::setupWindow() {
{'fraction_non_alphanumeric': 0.13152768759855302, 'fraction_numerical': 0.0038957425099712456, 'mean_word_length': 3.5417017691659645, 'pattern_counts': {'":': 0, '<': 60, '<?xml version=': 0, '>': 136, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6223272', 'n_tokens_mistral': 3352, 'n_tokens_neox': 3267, 'n_words': 810}