Files
fall-fever/src/Scene.cpp

203 lines
7.1 KiB
C++

#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 <future>
#include <memory>
#include <thread>
Scene::Scene(std::vector<std::shared_ptr<ShaderProgram>> 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<std::future<void>> futures;
std::mutex mutex;
for (const auto &descriptor : modelDescriptors) {
auto loadModel = [=, this, &mutex]() {
ResourceId model = ResourceHandler::instance().registerResource<Model>(descriptor);
Log::logger().info("Loaded model \"{}\": {}", descriptor.name, descriptor.path);
std::lock_guard<std::mutex> 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<Skybox>(
skyboxPrototype, std::static_pointer_cast<Model>(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<Model>(ResourceHandler::instance().resource(prototype.modelName)).get();
if (!currentModel) {
// Apply fallback model (first model in vector)
currentModel = std::static_pointer_cast<Model>(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<ModelEntity>(prototype, currentModel, currentProgram.get()));
Log::logger().info("Loaded entity \"{}\" with model \"{}\"", prototype.name, prototype.modelName);
}
}
// Order important
std::array<std::unique_ptr<Light::Prototype>, 2> lightPrototypes{
std::unique_ptr<DirectionalLight::Prototype>(
new DirectionalLight::Prototype{"directionalLight", {-0.2, -1.0, -0.3}, {1., 1., 1.}, 0.25}),
std::unique_ptr<PointLight::Prototype>(
new PointLight::Prototype{"pointLight0", "light", {0., 1., 0.}, {1., 1., 1.}, 7.5}),
};
std::vector<std::shared_ptr<Light>> lights;
{
for (auto &prototype : lightPrototypes) {
std::shared_ptr<Light> currentLight;
auto directionalPrototype = dynamic_cast<DirectionalLight::Prototype *>(prototype.get());
if (directionalPrototype) {
currentLight = std::make_shared<DirectionalLight>(*directionalPrototype, &m_shaderProgram);
}
auto pointPrototype = dynamic_cast<PointLight::Prototype *>(prototype.get());
if (pointPrototype) {
currentLight = std::make_shared<PointLight>(*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<ModelEntity> 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<ModelEntity> 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<std::shared_ptr<PointLight>> Scene::getPointLights()
{
std::vector<std::shared_ptr<PointLight>> temp_pointLights;
for (auto it = m_lights.begin(); it != m_lights.end(); it++) {
auto temp_pointLight = std::dynamic_pointer_cast<PointLight>(*it);
if (temp_pointLight) {
temp_pointLights.push_back(temp_pointLight);
}
}
return temp_pointLights;
}
std::shared_ptr<DirectionalLight> Scene::getDirectionalLight()
{
std::shared_ptr<DirectionalLight> temp_directionalLight;
for (auto it = m_lights.begin(); it != m_lights.end(); it++) {
temp_directionalLight = std::dynamic_pointer_cast<DirectionalLight>(*it);
if (temp_directionalLight)
break;
}
return temp_directionalLight;
}
std::vector<std::shared_ptr<ModelEntity>> Scene::getEntities()
{
return m_entities;
}
std::shared_ptr<Skybox> Scene::getSkybox()
{
return m_skybox;
}