<commit_before>#include "scene.hpp"

#include <iostream>

#include <Core/camera.hpp>
#include <Models/dynamicmodel.hpp>
#include <Utilities/exceptions.hpp>
#include <Utilities/log.hpp>
#include <Render/renderobject.hpp>
#include <Render/renderchain.hpp>
#include <Resources/resourcehandler.hpp>

using namespace luabridge;
using json = nlohmann::json;

// TODO Implement scene closing
// TODO Implement some sort of multithreading in lua (coroutines?)

// NOTE How slow is calling lua functions?
// NOTE What should lua be capable of doing?

Scene::Scene(const Display* const display, lua_State* luaState, std::string scenename)
        : m_display(display), m_luaState(luaState) {

    m_renderChain = std::make_unique<RenderChain>();
    m_resourceHandler = std::make_unique<ResourceHandler>();

    std::string script =  "Resources/Scenes/" + scenename + "/main.lua";
    std::string filename = "Resources/Scenes/" + scenename + "/scene.json";

    buildLuaNamespace();

    luaL_dofile(m_luaState, script.c_str());

    registerLuaFunctions();

    std::string contents;
    std::ifstream in(filename, std::ios::in | std::ios::binary);
    if (in) {
        in.seekg(0, std::ios::end);
        contents.resize(in.tellg());
        in.seekg(0, std::ios::beg);
        in.read(&contents[0], contents.size());
        in.close();
    } else {
        throw GenericException(filename + " doesn't exist");
    }

    try {
        const json scene = json::parse(contents);
        m_resourceHandler->loadResources(scene);

        if(scene.find("staticObjects") != scene.end()) {
            std::vector<json> objects = scene["staticObjects"];
            for(const json& object : objects) {
                try {
                    std::string type = object["type"];
                    IRenderObject* rObject = nullptr;

                    // NOTE Are there other types of render obects i might want to load?
                    if(type == "line") {
                        rObject = m_resourceHandler->generateLine(object);
                    } else if(type == "staticmodel") {
                        rObject = m_resourceHandler->generateModel(object, m_resourceHandler->getResource<Model3D>(object["resource"]));
                    } else if(type == "rawstaticmodel") {
                        rObject = m_resourceHandler->generateModel(object);
                    }

                    if(rObject != nullptr) {
                        m_renderObjects.push_back(std::unique_ptr<IRenderObject>(rObject));
                    }
                } catch (BadResource& error) {
                    error.printError();
                } catch (std::domain_error& error) {
                    Log::getErrorLog() << error.what() << '\n';
                }
            }
        }

        // TODO Implement actual dynamic model loading
        // NOTE What is "actual dynamic loading"?
        if(scene.find("dynamicObjects") != scene.end()) {
            std::vector<json> objects = scene["dynamicObjects"];
            for(const json& object : objects) {
                try {
                    auto name = object["name"];
                    //m_dynamicModels[name] = std::make_unique<DynamicModel>(m_resourceHandler->GetResource<Model3D>(object["resource"]));
                } catch (BadResource& error) {
                    error.printError();
                } catch (std::domain_error& error) {
                    Log::getErrorLog() << error.what() << '\n';
                }
            }
        }
    } catch(std::exception& error) {
        Log::getErrorLog() << "Parsing of " << filename << " failed: " << error.what() << '\n';
    }

    for(const auto& shader : m_resourceHandler->getShaders()) {
        m_renderChain->attachShader(shader.second.get());
    }
}

// NOTE Make sure scene is 100% closed when *this* is deleted
Scene::~Scene() {
}

// NOTE What other functions are necessary to expose to lua?
void Scene::buildLuaNamespace() {
    getGlobalNamespace(m_luaState)
        .beginClass<glm::vec2>("vec2")
            .addConstructor<void(*)(float, float)>()
            .addData("x", &glm::vec2::x)
            .addData("y", &glm::vec2::y)
        .endClass()
        .beginClass<glm::vec3>("vec3")
            .addConstructor<void(*)(float, float, float)>()
            .addData("x", &glm::vec3::x)
            .addData("y", &glm::vec3::y)
            .addData("z", &glm::vec3::z)
        .endClass()
        .beginClass<glm::vec4>("vec4")
            .addConstructor<void(*)(float, float, float, float)>()
            .addData("x", &glm::vec4::x)
            .addData("y", &glm::vec4::y)
            .addData("z", &glm::vec4::z)
            .addData("w", &glm::vec4::w)
        .endClass()
        .beginNamespace("Game")
            .beginClass<Camera>("Camera")
                .addFunction("MoveCamera", &Camera::moveCamera)
                .addFunction("SetCamera", &Camera::setPosition)
                .addFunction("GetPosition", &Camera::getPosition)
                .addFunction("GetDirection", &Camera::getDirection)
            .endClass()
            .beginClass<Entity>("Entity")
                .addConstructor<void(*)(void)>()
                .addProperty("visible", &Entity::isVisible, &Entity::setVisible)
                .addProperty("name", &Entity::getName, &Entity::setName)
                .addFunction("Scale", &Entity::scale)
                .addFunction("Translate", &Entity::translate)
                .addFunction("Rotate", &Entity::rotate)
            .endClass()
            .beginClass<Scene>("Scene")
                .addFunction("SetAmbientIntensity", &Scene::setAmbientIntensity)
                .addFunction("SetAmbientColor", &Scene::setAmbientColor)
                .addFunction("BindFunctionToKey", &Scene::bindFunctionToKey)
                .addFunction("GetCamera", &Scene::getCamera)
                .addFunction("AddEntity", &Scene::addEntity)
                .addFunction("GetEntity", &Scene::getEntity)
                .addFunction("GetEntityCount", &Scene::getEntityCount)
                .addFunction("Spawn", &Scene::spawn)
            .endClass()
        .endNamespace();

    push(m_luaState, this);
    lua_setglobal(m_luaState, "Level");
}

// NOTE Are there other necessary function the engine might want to call?
void Scene::registerLuaFunctions() {
    m_startFunc = std::make_unique<LuaRef>(getGlobal(m_luaState, "Start"));
    if(!m_startFunc->isFunction()) {
        throw GenericException("Start function wasn't found");
    }

    m_renderFunc = std::make_unique<LuaRef>(getGlobal(m_luaState, "GameLoop"));
    if(!m_renderFunc->isFunction()) {
        throw GenericException("Render function wasn't found");
    }
}

// Is this the best way to do it?
void Scene::start() {
    (*m_startFunc)();<commit_msg>small change<commit_after>#include "scene.hpp"

#include <iostream>

#include <Core/camera.hpp>
#include <Models/dynamicmodel.hpp>
#include <Utilities/exceptions.hpp>
#include <Utilities/log.hpp>
#include <Render/renderobject.hpp>
#include <Render/renderchain.hpp>
#include <Resources/resourcehandler.hpp>

using luabridge::LuaRef;
using json = nlohmann::json;

// TODO Implement scene closing
// TODO Implement some sort of multithreading in lua (coroutines?)

// NOTE How slow is calling lua functions?
// NOTE What should lua be capable of doing?

Scene::Scene(const Display* const display, lua_State* luaState, std::string scenename)
        : m_display(display), m_luaState(luaState) {

    m_renderChain = std::make_unique<RenderChain>();
    m_resourceHandler = std::make_unique<ResourceHandler>();

    std::string script =  "Resources/Scenes/" + scenename + "/main.lua";
    std::string filename = "Resources/Scenes/" + scenename + "/scene.json";

    buildLuaNamespace();

    luaL_dofile(m_luaState, script.c_str());

    registerLuaFunctions();

    std::string contents;
    std::ifstream in(filename, std::ios::in | std::ios::binary);
    if (in) {
        in.seekg(0, std::ios::end);
        contents.resize(in.tellg());
        in.seekg(0, std::ios::beg);
        in.read(&contents[0], contents.size());
        in.close();
    } else {
        throw GenericException(filename + " doesn't exist");
    }

    try {
        const json scene = json::parse(contents);
        m_resourceHandler->loadResources(scene);

        if(scene.find("staticObjects") != scene.end()) {
            std::vector<json> objects = scene["staticObjects"];
            for(const json& object : objects) {
                try {
                    std::string type = object["type"];
                    IRenderObject* rObject = nullptr;

                    // NOTE Are there other types of render obects i might want to load?
                    if(type == "line") {
                        rObject = m_resourceHandler->generateLine(object);
                    } else if(type == "staticmodel") {
                        rObject = m_resourceHandler->generateModel(object, m_resourceHandler->getResource<Model3D>(object["resource"]));
                    } else if(type == "rawstaticmodel") {
                        rObject = m_resourceHandler->generateModel(object);
                    }

                    if(rObject != nullptr) {
                        m_renderObjects.push_back(std::unique_ptr<IRenderObject>(rObject));
                    }
                } catch (BadResource& error) {
                    error.printError();
                } catch (std::domain_error& error) {
                    Log::getErrorLog() << error.what() << '\n';
                }
            }
        }

        // TODO Implement actual dynamic model loading
        // NOTE What is "actual dynamic loading"?
        if(scene.find("dynamicObjects") != scene.end()) {
            std::vector<json> objects = scene["dynamicObjects"];
            for(const json& object : objects) {
                try {
                    auto name = object["name"];
                    //m_dynamicModels[name] = std::make_unique<DynamicModel>(m_resourceHandler->GetResource<Model3D>(object["resource"]));
                } catch (BadResource& error) {
                    error.printError();
                } catch (std::domain_error& error) {
                    Log::getErrorLog() << error.what() << '\n';
                }
            }
        }
    } catch(std::exception& error) {
        Log::getErrorLog() << "Parsing of " << filename << " failed: " << error.what() << '\n';
    }

    for(const auto& shader : m_resourceHandler->getShaders()) {
        m_renderChain->attachShader(shader.second.get());
    }
}

// NOTE Make sure scene is 100% closed when *this* is deleted
Scene::~Scene() {
}

// NOTE What other functions are necessary to expose to lua?
void Scene::buildLuaNamespace() {
    luabridge::getGlobalNamespace(m_luaState)
        .beginClass<glm::vec2>("vec2")
            .addConstructor<void(*)(float, float)>()
            .addData("x", &glm::vec2::x)
            .addData("y", &glm::vec2::y)
        .endClass()
        .beginClass<glm::vec3>("vec3")
            .addConstructor<void(*)(float, float, float)>()
            .addData("x", &glm::vec3::x)
            .addData("y", &glm::vec3::y)
            .addData("z", &glm::vec3::z)
        .endClass()
        .beginClass<glm::vec4>("vec4")
            .addConstructor<void(*)(float, float, float, float)>()
            .addData("x", &glm::vec4::x)
            .addData("y", &glm::vec4::y)
            .addData("z", &glm::vec4::z)
            .addData("w", &glm::vec4::w)
        .endClass()
        .beginNamespace("Game")
            .beginClass<Camera>("Camera")
                .addFunction("MoveCamera", &Camera::moveCamera)
                .addFunction("SetCamera", &Camera::setPosition)
                .addFunction("GetPosition", &Camera::getPosition)
                .addFunction("GetDirection", &Camera::getDirection)
            .endClass()
            .beginClass<Entity>("Entity")
                .addConstructor<void(*)(void)>()
                .addProperty("visible", &Entity::isVisible, &Entity::setVisible)
                .addProperty("name", &Entity::getName, &Entity::setName)
                .addFunction("Scale", &Entity::scale)
                .addFunction("Translate", &Entity::translate)
                .addFunction("Rotate", &Entity::rotate)
            .endClass()
            .beginClass<Scene>("Scene")
                .addFunction("SetAmbientIntensity", &Scene::setAmbientIntensity)
                .addFunction("SetAmbientColor", &Scene::setAmbientColor)
                .addFunction("BindFunctionToKey", &Scene::bindFunctionToKey)
                .addFunction("GetCamera", &Scene::getCamera)
                .addFunction("AddEntity", &Scene::addEntity)
                .addFunction("GetEntity", &Scene::getEntity)
                .addFunction("GetEntityCount", &Scene::getEntityCount)
                .addFunction("Spawn", &Scene::spawn)
            .endClass()
        .endNamespace();

    luabridge::setGlobal(m_luaState, this, "Level");
}

// NOTE Are there other necessary function the engine might want to call?
void Scene::registerLuaFunctions() {
    m_startFunc = std::make_unique<LuaRef>(luabridge::getGlobal(m_luaState, "Start"));
    if(!m_startFunc->isFunction()) {
        throw GenericException("Start function wasn't found");
    }

    m_renderFunc = std::make_unique<LuaRef>(luabridge::getGlobal(m_luaState, "GameLoop"));
    if(!m_renderFunc->isFunction()) {
        throw GenericException("Render function wasn't found");
    }
}

// Is this the best way to do it?
void Scene::start() {
    (*m_startFunc)();
{'fraction_non_alphanumeric': 0.1490706046579972, 'fraction_numerical': 0.0033796194254646977, 'mean_word_length': 2.331375428291728, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 79, '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': '6845042', 'n_tokens_mistral': 3941, 'n_tokens_neox': 3793, 'n_words': 728}