#include "CScene.hpp" #include "../Entity/CEntity.hpp" #include "../Component/Graphics/CRenderer.hpp" #include "../Component/Meta/CMetaData.hpp" #include "../Component/Geometry/CTransform.hpp" #include "../Component/Camera/CCamera.hpp" #include "../Systems/Graphics/API/GraphicsAPI.hpp" #include "../../Utils/JsonParser/Identifier.hpp" #include "../../Utils/Factory/CEntityFactory.hpp" #include "../../Utils/Factory/ComponentFactory.hpp" #include "Core/Component/Camera/CCamera2D.hpp" #include "Core/Component/Collider/CCollider2D.hpp" #include "Core/Component/Geometry/CTransform2D.hpp" #include "Core/Component/Graphics/CRenderer2D.hpp" #include "Core/Component/Graphics/CTextRenderer.hpp" #include "Core/Component/Light/CLight.hpp" #include "Core/Entity/EntityComponentManager.hpp" #include "glm/ext/vector_float3.hpp" #include "glm/gtc/type_ptr.hpp" #include "nlohmann/json_fwd.hpp" #include #include #include #include #include #include "../Systems/Graphics/Data/Light/CLightsBuffer.hpp" namespace CosmicCore { CScene::CScene(std::string name) : CSerializable(), m_name(std::move(name)), m_tangibleWorld(this), m_audioWorld(this), m_scriptWorld(this) { m_tangibleWorld.initWorld(); m_audioWorld.initWorld(); m_scriptWorld.initWorld(); m_lightsBuffer.init(); //m_uiWorld.init(); m_ecManager.registry.sort([](const CTransform2D& lhs, const CTransform2D& rhs) { return lhs.getZOrder() > rhs.getZOrder(); }); } std::string CScene::getName(void) const { return m_name; } CScene::~CScene() { m_tangibleWorld.destroy(); m_audioWorld.destroy(); m_scriptWorld.destroy(); m_lightsBuffer.destroy(); //m_uiWorld.destroy(); } CEntity CScene::createEntity(){ auto handle = m_ecManager.registry.create(); CEntity handler(m_ecManager, handle, this); return handler; } unsigned int CScene::getNumEntity(void) const { return m_ecManager().view()->size(); } void CScene::removeEntity(unsigned int index, bool destroy) { } void CScene::collectLights(vk::raii::CommandBuffer& cmd, uint32_t frameIndex) { auto& registry = m_ecManager.registry; auto view = registry.view(); SLightsUBOData lightsData{}; for (auto entity : view) { if (lightsData.lightCount >= MAX_LIGHTS) break; auto& light = registry.get(entity); auto& transform = registry.get(entity); SLightData data{}; glm::vec3 pos = transform.getCenter(); glm::vec3 dir = transform.getOrientation() * glm::vec3(0, -1, 0); data.position = {pos.x, pos.y, pos.z, (float)light.getType()}; data.direction = {dir.x, dir.y, dir.z, light.getRange()}; data.color = {light.getColor().x, light.getColor().y, light.getColor().z, light.getIntensity()}; data.innerCosAngle = glm::cos(glm::radians(light.getInnerAngle())); data.outerCosAngle = glm::cos(glm::radians(light.getOuterAngle())); data.attenuation = light.getAttenuation(); lightsData.lights[lightsData.lightCount++] = data; } // upload dans le SSBO m_lightsBuffer.update(frameIndex, lightsData); } void CScene::render3D(vk::raii::CommandBuffer& cmd, uint32_t frameIndex){ auto entities = m_ecManager.registry.view(); if(entities.begin() != entities.end()) { VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); auto cam = m_ecManager.registry.view(); auto& camera = m_ecManager.registry.get(cam.front()); auto& transform = m_ecManager.registry.get(cam.front()); collectLights(cmd, frameIndex); camera.updateUniformBuffer(frameIndex, transform); cmd.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, api->getDefaultPipelineLayout(), // layout du pipeline 0, *camera.getDescriptorSet(frameIndex), {} ); //bind lumières (set 3) cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, api->getDefaultPipelineLayout(), 3, *m_lightsBuffer.getDescriptorSet(frameIndex), {}); for (auto& entity : entities) { auto model = m_ecManager.registry.get(entity).getModel(); auto& transform = m_ecManager.registry.get(entity); transform.updateUniformBuffer(frameIndex); //trier meshes par matérial ? // bind transform UBO (set = 1) cmd.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, api->getDefaultPipelineLayout(), // layout du pipeline 1, // set = 1 *transform.getDescriptorSet(frameIndex), {} ); for (auto& mm : model->getMeshMaterials()) { // ne rebind le pipeline que si le material change //if (mesh.getMaterial() != boundMaterial) { //boundMaterial = mesh.getMaterial(); cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, *mm.material->getPipeline()); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *mm.material->getPipelineLayout(), 2, *mm.material->getDescriptorSet(frameIndex), {}); //} cmd.bindVertexBuffers(0, vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getVertexOffset()); cmd.bindIndexBuffer(vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getIndexOffset(), vk::IndexType::eUint32); cmd.drawIndexed(mm.mesh->getIndexCount(), 1, 0, 0, 0); } } } } void CScene::render2D(vk::raii::CommandBuffer& cmd, uint32_t frameIndex){ auto entities = m_ecManager.registry.view(); auto textEntities = m_ecManager.registry.view(); if(entities.begin() != entities.end()) { VulkanImpl* api = dynamic_cast(GraphicsAPI::getAPI().get()); auto cam = m_ecManager.registry.view(); auto& camera = m_ecManager.registry.get(cam.front()); auto& trCam = m_ecManager.registry.get(cam.front()); camera.updateUniformBuffer(frameIndex, trCam); // cmd.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, api->getDefault2DPipelineLayout(), // layout du pipeline 2, *camera.getDescriptorSet(frameIndex), {} ); for (auto& entity : entities) { auto model = m_ecManager.registry.get(entity).getModel(); auto& transform = m_ecManager.registry.get(entity); transform.updateUniformBuffer(frameIndex); // bind transform UBO (set = 1) cmd.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, api->getDefault2DPipelineLayout(), // layout du pipeline 0, // set = 1 *transform.getDescriptorSet(frameIndex), {} ); for (auto& mm : model->getMeshMaterials()) { // ne rebind le pipeline que si le material change //if (mesh.getMaterial() != boundMaterial) { //boundMaterial = mesh.getMaterial(); cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, *mm.material->getPipeline()); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *mm.material->getPipelineLayout(), 1, *mm.material->getDescriptorSet(frameIndex), {}); //} cmd.bindVertexBuffers(0, vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getVertexOffset()); cmd.bindIndexBuffer(vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getIndexOffset(), vk::IndexType::eUint32); cmd.drawIndexed(mm.mesh->getIndexCount(), 1, 0, 0, 0); } } for (auto& entity : textEntities) { auto& textRenderer = m_ecManager.registry.get(entity); auto& transform = m_ecManager.registry.get(entity); auto model = textRenderer.getModel(); transform.updateUniformBuffer(frameIndex); // bind transform UBO (set = 1) cmd.bindDescriptorSets( vk::PipelineBindPoint::eGraphics, api->getDefault2DPipelineLayout(), // layout du pipeline 0, // set = 1 *transform.getDescriptorSet(frameIndex), {} ); for (auto& mm : model->getMeshMaterials()) { // ne rebind le pipeline que si le material change //if (mesh.getMaterial() != boundMaterial) { //boundMaterial = mesh.getMaterial(); cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, *mm.material->getPipeline()); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *mm.material->getPipelineLayout(), 1, *mm.material->getDescriptorSet(frameIndex), {}); //} cmd.bindVertexBuffers(0, vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getVertexOffset()); cmd.bindIndexBuffer(vk::Buffer(mm.mesh->getVertexIndexBuffer().buffer), mm.mesh->getIndexOffset(), vk::IndexType::eUint32); cmd.drawIndexed(mm.mesh->getIndexCount(), 1, 0, 0, 0); } } } } void CScene::render(vk::raii::CommandBuffer& cmd, uint32_t frameIndex){ render3D(cmd, frameIndex); render2D(cmd, frameIndex); } nlohmann::json CScene::to_json() { return nlohmann::json(); } std::unique_ptr CScene::load(const std::string &path) { std::ifstream file(path); nlohmann::json sceneJson = nlohmann::json::parse(file); if(CosmicUtils::JsonValidator::validate(sceneJson)) { std::string sceneName = sceneJson[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Scene_Name)]; std::unordered_map idToHandle; std::unordered_map idToParent; std::unordered_map> idToChildren; //TODO add descritpion to members std::string sceneDescription = sceneJson[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Scene_Description)]; auto scene = std::make_unique(sceneName); nlohmann::json& entities = sceneJson[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Scene_Entities)]; for(auto& entity : entities.items()) { nlohmann::json& entityObj = entity.value(); auto ref = entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity_Ref)].get(); std::optional parent = !entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity_Parent)].is_null() ? std::optional(entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity_Parent)].get()) : std::nullopt; auto children = entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity_Children)].get>(); nlohmann::json& components = entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity_Components)]; nlohmann::json& transform = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Transform)]; nlohmann::json& camera = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Camera)]; nlohmann::json& collider = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Collider)]; nlohmann::json& rigidbody = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Rigidbody)]; nlohmann::json& renderer = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Renderer)]; nlohmann::json& speaker = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Speaker)]; nlohmann::json& script = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Script)]; nlohmann::json& light = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Light)]; auto trConfig(!transform.is_null() ? std::optional({ glm::make_vec3(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Position)].get>().data()), glm::make_vec3(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Rotation)].get>().data()), glm::make_vec3(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Scale)].get>().data()) }) : std::nullopt); auto camConfig(!camera.is_null() ? std::optional({ camera[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Camera_Fov)].get(), camera[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Camera_Near)].get(), camera[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Camera_Far)].get() }) : std::nullopt); auto colliderConfig(!collider.is_null() ? std::optional({ static_cast(collider[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Collider_Type)].get()), glm::vec3(), 0, 0, }) : std::nullopt); auto rigidbodyConfig(!rigidbody.is_null() ? std::optional({ static_cast(rigidbody[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::RigidBody_Type)].get()), rigidbody[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::RigidBody_Mass)].get(), rigidbody[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::RigidBody_Friction)].get(), rigidbody[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::RigidBody_Restitution)].get() }) : std::nullopt); auto rendererConfig(!renderer.is_null() ? std::optional({ renderer[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Renderer_Model)].get(), renderer[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Renderer_Shader)].get(), !renderer[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Renderer_Albedo)].is_null() ? std::optional(renderer[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Renderer_Albedo)].get()) : std::nullopt, }) : std::nullopt); auto scriptConfig(!script.is_null() ? std::optional({ script.get>() }): std::nullopt); std::optional speakerConfig = std::nullopt; if(!speaker.is_null()) { if(!speaker[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Speaker_Clips)].empty()) { speakerConfig = std::optional(CosmicUtils::ComponentFactory::SpeakerConfig()); for(auto clipConf : speaker[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Speaker_Clips)]) { CosmicUtils::ComponentFactory::SpeakerConfig::SoundClipConfig conf { clipConf[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Speaker_Path)].get(), clipConf[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Speaker_Gain)].get(), clipConf[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Speaker_Pitch)].get(), clipConf[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Speaker_Loop)].get(), clipConf[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Speaker_Spatial)].get() }; speakerConfig->clips.push_back(conf); } } } auto lightConfig(!light.is_null() ? std::optional( { static_cast(light[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Light_Type)].get()), glm::make_vec3(light[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Light_Color)].get>().data()), light[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Light_Intensity)].get(), light[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Light_Range)].get(), light[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Light_Attenuation)].get(), light[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Light_InnerAngle)].get(), light[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Light_OuterAngle)].get(), light[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Light_CastShadow)].get() }) : std::nullopt); CosmicUtils::CEntityFactory::EntityConfig config = { entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity_Name)], entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity_Description)], trConfig, camConfig, rendererConfig, colliderConfig, rigidbodyConfig, speakerConfig, scriptConfig, lightConfig }; auto entityHandle = CosmicUtils::CEntityFactory::create(scene.get(), config); idToHandle.emplace(std::make_pair(ref, entityHandle)); if(parent.has_value()) idToParent[ref] = parent.value(); for(auto i : children) { idToChildren[ref].push_back(i); } } nlohmann::json& entities2D = sceneJson[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Scene_Entities2D)]; for(auto& entity : entities2D.items()) { nlohmann::json& entityObj = entity.value(); auto ref = entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity2D_Ref)].get(); nlohmann::json& components = entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity2D_Components)]; nlohmann::json& transform = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Transform2D)]; nlohmann::json& camera = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Camera2D)]; nlohmann::json& collider = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Collider2D)]; nlohmann::json& renderer = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Renderer2D)]; nlohmann::json& script = components[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Component_Script)]; auto trConfig(!transform.is_null() ? std::optional({ glm::make_vec2(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Position2D)].get>().data()), glm::make_vec2(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Size2D)].get>().data()), glm::make_vec2(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Scale2D)].get>().data()), glm::make_vec2(transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Pivot2D)].get>().data()), transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Rotation2D)].get(), transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_zOrder2D)].get(), transform[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Transform_Visible2D)].get() }) : std::nullopt); auto camConfig(!camera.is_null() ? std::optional({ camera[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Camera_Zoom2D)].get() }) : std::nullopt); auto colliderConfig(!collider.is_null() ? std::optional({ static_cast(collider[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Collider_Shape2D)].get()) }) : std::nullopt); auto rendererConfig(!renderer.is_null() ? std::optional({ renderer[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Renderer_Model2D)].get(), renderer[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Renderer_Shader2D)].get(), }) : std::nullopt); auto scriptConfig(!script.is_null() ? std::optional({ script.get>() }): std::nullopt); CosmicUtils::CEntityFactory::Entity2DConfig config = { entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity2D_Name)], entityObj[CosmicUtils::JsonKeyRegistry::key(CosmicUtils::EJsonKeys::Entity2D_Description)], trConfig, camConfig, rendererConfig, colliderConfig, scriptConfig }; auto entityHandle = CosmicUtils::CEntityFactory::create(scene.get(), config); } //Connect entities to relationships for(auto& [entityNb, handle]: idToHandle) { CosmicUtils::ComponentFactory::RelationshipConfig cnf; if(idToParent.find(entityNb) != idToParent.end()) { cnf.parent = std::optional(idToHandle.at(idToParent.at(entityNb)).getHandle()); } else { cnf.parent = std::nullopt; } for(auto& child : idToChildren[entityNb]) { cnf.children.push_back(idToHandle.at(child).getHandle()); } CosmicUtils::ComponentFactory::addRelationship(handle, cnf); } return scene; } return nullptr; } void CScene::save(CScene *scene, const std::string &path) { } void CScene::save(const std::string& path) { save(this, path); } }