#include "Scene.h" #include "Controller.h" #include "Entity.h" #include "Light.h" #include "ShaderProgram.h" #include "resources/Model.h" #include "resources/ResourceHandler.h" #include "util/Log.h" #include #include #include Scene::Scene(std::vector> shaderPrograms) : m_shaderProgram(*Controller::getShaderProgramByName("defaultProgram", shaderPrograms)) { // This will be removed in future when gloss maps are implemented m_shaderProgram.bind(); m_shaderProgram.setUniform("u_material.shininess", 100.0f); m_shaderProgram.unbind(); std::array modelDescriptors{ ModelDescriptor{"fallback", "data/res/models/fallback.ffo"}, ModelDescriptor{"backpack", "data/res/models/backpack.ffo"}, ModelDescriptor{"ground", "data/res/models/wood_floor.ffo"}, ModelDescriptor{"cube", "data/res/models/cube.ffo"}, ModelDescriptor{"container", "data/res/models/container.ffo"}, }; { std::vector> futures; std::mutex mutex; for (const auto &descriptor : modelDescriptors) { auto loadModel = [=, this, &mutex]() { ResourceId model = ResourceHandler::instance().registerResource(descriptor); Log::logger().info("Loaded model \"{}\": {}", descriptor.name, descriptor.path); std::lock_guard lock(mutex); m_models.push_back(model); }; futures.push_back(std::async(std::launch::async, loadModel)); } } // TODO: use geometry shader instead of model and load skybox before models. Skybox::Prototype skyboxPrototype{"data/res/textures/skybox/"}; m_skybox = std::make_shared( skyboxPrototype, std::static_pointer_cast(ResourceHandler::instance().resource("cube")).get(), Controller::getShaderProgramByName("skyboxProgram", shaderPrograms).get()); Log::logger().info("Loaded skybox: {}", skyboxPrototype.texturePath); m_skybox->initializeOnGPU(); std::array entityPrototypes{ ModelEntity::Prototype{"backpack", {0., 1., 0.}, {}, 0.6F, "backpack", "defaultProgram"}, ModelEntity::Prototype{"container", {10., 1., 0.}, {45., 45., 45.}, 1., "container", "defaultProgram"}, ModelEntity::Prototype{"ground", {}, {}, 1., "ground", "defaultProgram"}, ModelEntity::Prototype{"light", {}, {}, 1., "cube", "lightProgram"}, }; { for (auto &prototype : entityPrototypes) { // Get model const Model *currentModel = std::static_pointer_cast(ResourceHandler::instance().resource(prototype.modelName)).get(); if (!currentModel) { // Apply fallback model (first model in vector) currentModel = std::static_pointer_cast(ResourceHandler::instance().resource("fallback")) .get(); // TODO rename fallbackModel Log::logger().warn("Model could not be found by name \"{}\"", prototype.modelName); } // Get shaderprogram auto currentProgram = Controller::getShaderProgramByName(prototype.shaderProgramName, shaderPrograms); if (!currentProgram) { currentProgram = Controller::getShaderProgramByName("basic", shaderPrograms); } m_entities.push_back(std::make_shared(prototype, currentModel, currentProgram.get())); Log::logger().info("Loaded entity \"{}\" with model \"{}\"", prototype.name, prototype.modelName); } } // Order important std::array, 2> lightPrototypes{ std::unique_ptr( new DirectionalLight::Prototype{"directionalLight", {-0.2, -1.0, -0.3}, {1., 1., 1.}, 0.25}), std::unique_ptr( new PointLight::Prototype{"pointLight0", "light", {0., 1., 0.}, {1., 1., 1.}, 7.5}), }; std::vector> lights; { for (auto &prototype : lightPrototypes) { std::shared_ptr currentLight; auto directionalPrototype = dynamic_cast(prototype.get()); if (directionalPrototype) { currentLight = std::make_shared(*directionalPrototype, &m_shaderProgram); } auto pointPrototype = dynamic_cast(prototype.get()); if (pointPrototype) { currentLight = std::make_shared(*pointPrototype, &m_shaderProgram); } lights.push_back(currentLight); Log::logger().info("Loaded light \"{}\"", prototype->name); } } m_lights = lights; } void Scene::updatePointLight(unsigned int lightId, bool active, glm::vec3 position, glm::vec3 color, float intensity) { auto pointLights = getPointLights(); pointLights[lightId]->setActive(active); pointLights[lightId]->setPosition(position); pointLights[lightId]->setIntensity(intensity); pointLights[lightId]->setColor(color); } void Scene::updateDirectionalLight(bool active, glm::vec3 direction, glm::vec3 color) { auto directionalLight = getDirectionalLight(); directionalLight->setActive(active); directionalLight->setDirection(direction); directionalLight->setColor(color); } void Scene::draw(glm::mat4 viewProjMatrix, glm::vec3 viewPosition) { // Draw all entities for (auto it = m_entities.begin(); it != m_entities.end(); it++) { (*it)->draw(viewProjMatrix, viewPosition); } } std::shared_ptr Scene::getEntityByName(const std::string &name) { for (auto it = m_entities.begin(); it != m_entities.end(); it++) { if ((*it)->getUniqueName() == name) { return *it; } } Log::logger().warn("Entity could not be found by unique name \"{}\"", name); return nullptr; } std::shared_ptr Scene::getEntityById(uint32_t id) { for (auto it = m_entities.begin(); it != m_entities.end(); it++) { if ((*it)->getId() == id) { return *it; } } Log::logger().warn("Entity could not be found by ID \"{}\"", id); return nullptr; } std::vector> Scene::getPointLights() { std::vector> temp_pointLights; for (auto it = m_lights.begin(); it != m_lights.end(); it++) { auto temp_pointLight = std::dynamic_pointer_cast(*it); if (temp_pointLight) { temp_pointLights.push_back(temp_pointLight); } } return temp_pointLights; } std::shared_ptr Scene::getDirectionalLight() { std::shared_ptr temp_directionalLight; for (auto it = m_lights.begin(); it != m_lights.end(); it++) { temp_directionalLight = std::dynamic_pointer_cast(*it); if (temp_directionalLight) break; } return temp_directionalLight; } std::vector> Scene::getEntities() { return m_entities; } std::shared_ptr Scene::getSkybox() { return m_skybox; }