diff --git a/CMakeLists.txt b/CMakeLists.txt index fdfe68a..8ffd1a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,10 @@ project( LANGUAGES C CXX ) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_EXPORT_COMPILE_COMMANDS ON) include(FetchContent) @@ -15,7 +19,7 @@ include(FetchContent) # EnTT FetchContent_Declare( entt - URL https://github.com/skypjack/entt/archive/refs/tags/v3.11.1.tar.gz + URL https://github.com/skypjack/entt/archive/refs/tags/v3.12.0.tar.gz ) FetchContent_MakeAvailable(entt) @@ -27,6 +31,8 @@ FetchContent_Declare( ) option(GLFW_BUILD_DOCS "" OFF) +option(GLFW_BUILD_EXAMPLES "" OFF) +option(GLFW_BUILD_TESTS "" OFF) option(GLFW_INSTALL "" OFF) FetchContent_MakeAvailable(glfw) diff --git a/CMakePresets.json b/CMakePresets.json index f5c887e..4eb2a56 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -28,7 +28,7 @@ }, { "name": "dev", - "generator": "Unix Makefiles", + "generator": "Ninja", "binaryDir": "${sourceDir}/build", "inherits": [ "std" diff --git a/Fall-Fever b/Fall-Fever deleted file mode 120000 index 0a680c7..0000000 --- a/Fall-Fever +++ /dev/null @@ -1 +0,0 @@ -build/src/Fall-Fever \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2fc8a9b..f871741 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,14 +5,15 @@ add_library(fever_engine core/graphics/material.cpp core/graphics/mesh.cpp core/camera.cpp + core/game_loop.cpp core/glad.cpp core/light.cpp core/render.cpp core/shader.cpp core/time.cpp input/input.cpp + scene/gltf.cpp scene/gltf_loader.cpp - scene/scene.cpp util/log.cpp window/window.cpp ) @@ -35,7 +36,7 @@ target_link_libraries( add_executable(Fall-Fever bin/main.cpp - bin/Controller.cpp + bin/controller.cpp ) target_link_libraries(Fall-Fever PRIVATE fever_engine) diff --git a/src/bin/Controller.cpp b/src/bin/Controller.cpp deleted file mode 100644 index 7509e0d..0000000 --- a/src/bin/Controller.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "Controller.h" -#include "core/light.h" -#include "core/render.h" -#include "core/shader.h" -#include "core/time.h" -#include "input/input.h" -#include "scene/scene.h" -#include "window/window.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace entt::literals; - -Controller::Controller() : - m_gameWindow(std::make_shared(event_dispatcher)), - post_processing_framebuffer(m_gameWindow->physical_dimensions()), - m_gltf_loader{.image_cache = m_image_cache, - .material_cache = m_material_cache, - .mesh_cache = m_mesh_cache, - .shader_cache = m_shader_cache, - .scene_cache = m_scene_cache, - .gltf_mesh_cache = m_gltf_mesh_cache, - .gltf_node_cache = m_gltf_node_cache, - .registry = registry}, - m_gltf_cache(m_gltf_loader), - key_listener{.registry = registry}, - cursor_listener{.registry = registry} -{ - std::filesystem::path document_path("WaterBottle/glTF-Binary/WaterBottle.glb"); - entt::hashed_string document_hash(document_path.c_str()); - - entt::resource gltf_document = - m_gltf_cache.load(document_hash, document_path).first->second; - - m_scene = gltf_document->default_scene.value_or(gltf_document->scenes.at(0)).handle(); - - Input::State::init_state(registry); - - event_dispatcher.sink().connect<&Controller::recreate_framebuffer>(this); - event_dispatcher.sink().connect<&Input::KeyListener::key_event>(key_listener); - event_dispatcher.sink().connect<&Input::CursorListener::cursor_event>(cursor_listener); -} - -void Controller::run() -{ - entt::hashed_string shader_hash(Material::SHADER_NAME.data()); - auto standard_material_shader = - m_shader_cache.load(shader_hash, Material::SHADER_NAME).first->second; - - spdlog::info("Startup complete. Enter game loop."); - - // This is the game loop - while (glfwWindowShouldClose(&m_gameWindow->handle()) == GLFW_FALSE) { - // --- Timing --- - Time::update_delta_time(registry); - - // --- Check events, handle input --- - // m_gameWindow->clear_mouse_cursor_input(); - glfwPollEvents(); - - // --- Update game state --- - event_dispatcher.update(); - - m_gameWindow->update_descriptor(registry); - m_gameWindow->mouse_catching(registry); - m_gameWindow->close_on_esc(registry); - - m_scene->update(); - - Input::State::update_state(registry); - Input::reset_mouse_motion(registry); - - // --- Render and buffer swap --- - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - post_processing_framebuffer.bind(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - Light::update_lights(registry, standard_material_shader); - Render::render(registry); - - Framebuffer::unbind(); - post_processing_framebuffer.draw(post_processing_shader); - - glfwSwapBuffers(&m_gameWindow->handle()); - } -} - -void Controller::recreate_framebuffer() -{ - auto dimensions = m_gameWindow->physical_dimensions(); - post_processing_framebuffer = Framebuffer(dimensions); -} diff --git a/src/bin/Controller.h b/src/bin/Controller.h deleted file mode 100644 index c58d808..0000000 --- a/src/bin/Controller.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "core/graphics/framebuffer.h" -#include "core/shader.h" -#include "entt/entity/fwd.hpp" -#include "scene/gltf_loader.h" -#include "input/input.h" - -#include -#include -#include -#include -#include - -class Scene; -class Camera; -class Window; -class Framebuffer; - -class Controller -{ -public: - Controller(); - - void run(); - -private: - void recreate_framebuffer(); - - std::shared_ptr m_gameWindow; - std::shared_ptr m_scene; - - Shader post_processing_shader{"post_processing", "data/shaders"}; - Framebuffer post_processing_framebuffer; - - entt::registry registry; - - entt::dispatcher event_dispatcher{}; - Input::KeyListener key_listener; - Input::CursorListener cursor_listener; - - // Resource caches - entt::resource_cache m_image_cache; - entt::resource_cache m_material_cache; - entt::resource_cache m_mesh_cache; - entt::resource_cache m_scene_cache; - entt::resource_cache m_shader_cache; - entt::resource_cache m_gltf_mesh_cache; - entt::resource_cache m_gltf_node_cache; - - GltfLoader m_gltf_loader; - entt::resource_cache m_gltf_cache; -}; diff --git a/src/bin/controller.cpp b/src/bin/controller.cpp new file mode 100644 index 0000000..8777ed5 --- /dev/null +++ b/src/bin/controller.cpp @@ -0,0 +1,65 @@ +#include "controller.h" +#include "components/name.h" +#include "components/transform.h" +#include "core/camera.h" +#include "core/light.h" +#include "window/window.h" + +using namespace entt::literals; + +Controller::Controller() +{ + std::filesystem::path document_path("WaterBottle/glTF-Binary/WaterBottle.glb"); + entt::hashed_string document_hash(document_path.c_str()); + + entt::resource gltf_document = + gltf_cache.load(document_hash, document_path).first->second; + + gltf_document->spawn_default_scene(registry(), gltf_node_cache); + + // Convert meshes + auto mesh_view = registry().view>(); + for (auto [entity, mesh] : mesh_view.each()) { + registry().emplace(entity, GpuMesh(mesh)); + + // Remove Mesh resource as it is no longer needed. + registry().erase>(entity); + } + + // Convert materials + auto material_view = registry().view>(); + for (auto [entity, material] : material_view.each()) { + registry().emplace(entity, GpuMaterial(material)); + + // Remove Material resource as it is no longer needed. + registry().erase>(entity); + } + + // Spawn default lights + auto directional_light = registry().create(); + registry().emplace(directional_light, "Directional Light"); + registry().emplace( + directional_light, + Transform{.orientation = glm::toQuat( + glm::lookAt({}, DirectionalLight::DEFAULT_DIRECTION, Camera::UP_VECTOR))}); + registry().emplace(directional_light, GlobalTransform{}); + registry().emplace( + directional_light, DirectionalLight{.illuminance = DirectionalLight::DEFAULT_ILLUMINANCE}); + + auto point_light = registry().create(); + registry().emplace(point_light, "Point Light"); + registry().emplace(point_light, + Transform{.translation = PointLight::DEFAULT_POSITION}); + registry().emplace(point_light, GlobalTransform{}); + registry().emplace(point_light, + PointLight{.intensity = PointLight::DEFAULT_INTENSITY}); +} + +void Controller::update() +{ + Camera::keyboard_movement(registry()); + + if (registry().ctx().get().catched) { + Camera::mouse_orientation(registry()); + } +} diff --git a/src/bin/controller.h b/src/bin/controller.h new file mode 100644 index 0000000..96fc0b4 --- /dev/null +++ b/src/bin/controller.h @@ -0,0 +1,16 @@ +#pragma once + +#include "core/game_loop.h" + +#include +#include +#include +#include +#include + +class Controller : public GameLoop +{ +public: + Controller(); + void update() override; +}; diff --git a/src/bin/debug.cpp b/src/bin/debug.cpp new file mode 100644 index 0000000..7ff0124 --- /dev/null +++ b/src/bin/debug.cpp @@ -0,0 +1 @@ +// todo camera movement here ... \ No newline at end of file diff --git a/src/bin/main.cpp b/src/bin/main.cpp index 030d469..66cbd73 100644 --- a/src/bin/main.cpp +++ b/src/bin/main.cpp @@ -1,4 +1,4 @@ -#include "Controller.h" +#include "controller.h" #include "util/log.h" #include diff --git a/src/components/transform.h b/src/components/transform.h index a0d9ca6..1eb7028 100644 --- a/src/components/transform.h +++ b/src/components/transform.h @@ -6,8 +6,8 @@ struct Transform { - glm::vec3 translation; - glm::quat orientation; + glm::vec3 translation{}; + glm::quat orientation{}; glm::vec3 scale{1.0, 1.0, 1.0}; }; diff --git a/src/core/camera.cpp b/src/core/camera.cpp index b76d473..4386bfa 100644 --- a/src/core/camera.cpp +++ b/src/core/camera.cpp @@ -6,6 +6,7 @@ #include #include #include +#include auto Camera::projection_matrix() const -> glm::mat4 { @@ -45,14 +46,20 @@ void Camera::keyboard_movement(entt::registry& registry) auto camera_view = registry.view(); auto camera_entity = camera_view.front(); + + if (camera_entity == entt::null) { + spdlog::debug("No camera entity found"); + return; + } + auto [camera, camera_transform, camera_global_transform] = camera_view.get(camera_entity); glm::vec3 front_vec = front_vector(camera_global_transform); front_vec.y = 0; glm::vec3 delta_pos = glm::vec3(0., 0., 0.); - float delta_factor = - SPEED * delta_time.delta.count() * (movement_context.accelerate ? ACCELERATION : 1.0F); + float acceleration = movement_context.accelerate ? ACCELERATION : 1.0F; + float delta_factor = static_cast(delta_time.delta.count()) * SPEED * acceleration; movement_context.accelerate = false; if (key_state.pressed(Input::KeyCode{GLFW_KEY_W})) { @@ -84,6 +91,12 @@ void Camera::mouse_orientation(entt::registry& registry) { auto camera_view = registry.view(); auto camera_entity = camera_view.front(); + + if (camera_entity == entt::null) { + spdlog::debug("No camera entity found"); + return; + } + auto [camera, camera_transform] = camera_view.get(camera_entity); auto const& mouse_cursor_input = registry.ctx().get(); @@ -113,6 +126,12 @@ void Camera::aspect_ratio_update(entt::registry& registry) auto camera_view = registry.view(); auto camera_entity = camera_view.front(); + + if (camera_entity == entt::null) { + spdlog::debug("No camera entity found"); + return; + } + auto [camera] = camera_view.get(camera_entity); // Orthographic projection currently unsupported diff --git a/src/core/game_loop.cpp b/src/core/game_loop.cpp new file mode 100644 index 0000000..d7b730c --- /dev/null +++ b/src/core/game_loop.cpp @@ -0,0 +1,104 @@ +#include "game_loop.h" +#include "core/camera.h" +#include "core/light.h" +#include "core/render.h" +#include "core/shader.h" +#include "core/time.h" +#include "input/input.h" +#include "scene/scene.h" +#include "window/window.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +GameLoop::~GameLoop() = default; + +GameLoop::GameLoop() : + game_window(std::make_shared(event_dispatcher)), + post_processing_framebuffer(game_window->physical_dimensions()), + key_listener{.registry = entt_registry}, + cursor_listener{.registry = entt_registry}, + gltf_loader{.image_cache = image_cache, + .material_cache = material_cache, + .mesh_cache = mesh_cache, + .shader_cache = shader_cache, + .gltf_mesh_cache = gltf_mesh_cache, + .gltf_node_cache = gltf_node_cache}, + gltf_cache(gltf_loader) +{ + register_context_variables(); + + event_dispatcher.sink().connect<&GameLoop::recreate_framebuffer>(this); + event_dispatcher.sink().connect<&Input::KeyListener::key_event>(key_listener); + event_dispatcher.sink().connect<&Input::CursorListener::cursor_event>( + cursor_listener); +} + +void GameLoop::run() +{ + entt::hashed_string shader_hash(Material::SHADER_NAME.data()); + auto standard_material_shader = + shader_cache.load(shader_hash, Material::SHADER_NAME).first->second; + + spdlog::info("Startup complete. Enter game loop."); + + // This is the game loop + while (glfwWindowShouldClose(&game_window->handle()) == GLFW_FALSE) { + // --- Timing --- + Time::update_delta_time(entt_registry); + + // --- Check events, handle input --- + glfwPollEvents(); + + // --- Update game state --- + event_dispatcher.update(); + + game_window->update_descriptor(entt_registry); + game_window->mouse_catching(entt_registry); + game_window->close_on_esc(entt_registry); + + GlobalTransform::update(entt_registry); + Camera::aspect_ratio_update(entt_registry); + + update(); + + Input::State::update_state(entt_registry); + Input::reset_mouse_motion(entt_registry); + + // --- Render and buffer swap --- + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + post_processing_framebuffer.bind(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + Light::update_lights(entt_registry, standard_material_shader); + Render::render(entt_registry); + + Framebuffer::unbind(); + post_processing_framebuffer.draw(post_processing_shader); + + glfwSwapBuffers(&game_window->handle()); + } +} + +void GameLoop::register_context_variables() +{ + entt_registry.ctx().emplace>(); + entt_registry.ctx().emplace(); +} + +void GameLoop::recreate_framebuffer() +{ + auto dimensions = game_window->physical_dimensions(); + post_processing_framebuffer = Framebuffer(dimensions); +} diff --git a/src/core/game_loop.h b/src/core/game_loop.h new file mode 100644 index 0000000..2925264 --- /dev/null +++ b/src/core/game_loop.h @@ -0,0 +1,65 @@ +#pragma once + +#include "core/graphics/framebuffer.h" +#include "core/shader.h" +#include "entt/entity/fwd.hpp" +#include "entt/signal/fwd.hpp" +#include "input/input.h" +#include "scene/gltf_loader.h" + +#include +#include +#include +#include +#include + +class Camera; +class Window; + +class GameLoop +{ +public: + GameLoop(); + + virtual ~GameLoop(); + GameLoop(GameLoop const&) = delete; + GameLoop(GameLoop&&) = delete; + auto operator=(GameLoop const&) -> GameLoop& = delete; + auto operator=(GameLoop&&) -> GameLoop& = delete; + + auto registry() -> entt::registry& { return entt_registry; } + auto registry() const -> entt::registry const& { return entt_registry; } + + auto dispatcher() -> entt::dispatcher& { return event_dispatcher; } + auto dispatcher() const -> entt::dispatcher const& { return event_dispatcher; } + + void run(); + + virtual void update() = 0; + +protected: + virtual void register_context_variables(); + void recreate_framebuffer(); + + std::shared_ptr game_window; + + Shader post_processing_shader{"post_processing", "data/shaders"}; + Framebuffer post_processing_framebuffer; + + entt::registry entt_registry; + + entt::dispatcher event_dispatcher{}; + Input::KeyListener key_listener; + Input::CursorListener cursor_listener; + + // Resource caches + entt::resource_cache image_cache; + entt::resource_cache material_cache; + entt::resource_cache mesh_cache; + entt::resource_cache shader_cache; + entt::resource_cache gltf_mesh_cache; + entt::resource_cache gltf_node_cache; + + GltfLoader gltf_loader; + entt::resource_cache gltf_cache; +}; \ No newline at end of file diff --git a/src/core/graphics/mesh.h b/src/core/graphics/mesh.h index ce767cb..4d107f0 100644 --- a/src/core/graphics/mesh.h +++ b/src/core/graphics/mesh.h @@ -53,6 +53,8 @@ struct GpuMesh auto operator=(GpuMesh &&other) noexcept -> GpuMesh & { + glDeleteVertexArrays(1, &vao); + vao = other.vao; indices_count = other.indices_count; indices_type = other.indices_type; diff --git a/src/core/render.cpp b/src/core/render.cpp index ce3f781..3fe6ecb 100644 --- a/src/core/render.cpp +++ b/src/core/render.cpp @@ -4,11 +4,19 @@ #include "core/graphics/mesh.h" #include "core/shader.h" +#include + void Render::render(entt::registry& registry) { auto mesh_view = registry.view(); auto camera_view = registry.view(); auto camera_entity = camera_view.front(); + + if (camera_entity == entt::null) { + spdlog::debug("No camera entity found"); + return; + } + auto [camera, camera_transform] = camera_view.get(camera_entity); glm::mat4 view_projection_matrix = camera.projection_matrix() * Camera::view_matrix(camera_transform); diff --git a/src/input/input.cpp b/src/input/input.cpp index 37350c3..af518f9 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -6,7 +6,7 @@ namespace Input { void KeyListener::key_event(KeyInput const& key_input_event) { - auto& key_state = registry.ctx().emplace>(); + auto& key_state = registry.ctx().get>(); if (key_input_event.action == static_cast(GLFW_PRESS)) { key_state.press(key_input_event.key_code); @@ -17,21 +17,16 @@ void KeyListener::key_event(KeyInput const& key_input_event) void CursorListener::cursor_event(MouseMotion const& mouse_motion_event) { - auto& mouse_motion = registry.ctx().emplace(); + auto& mouse_motion = registry.ctx().get(); mouse_motion.delta += mouse_motion_event.delta; } void reset_mouse_motion(entt::registry& registry) { - auto& mouse_motion = registry.ctx().emplace(); + auto& mouse_motion = registry.ctx().get(); mouse_motion = {}; } -template void State::init_state(entt::registry& registry) -{ - registry.ctx().emplace>(); -} - template void State::update_state(entt::registry& registry) { auto& state = registry.ctx().get>(); diff --git a/src/input/input.h b/src/input/input.h index 9b23bdc..cb60202 100644 --- a/src/input/input.h +++ b/src/input/input.h @@ -34,7 +34,6 @@ public: auto just_pressed(T input) const -> bool { return just_pressed_keys.contains(input); } auto just_released(T input) const -> bool { return just_pressed_keys.contains(input); } - static void init_state(entt::registry& registry); static void update_state(entt::registry& registry); private: diff --git a/src/post_processing/post_processing.cpp b/src/post_processing/post_processing.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/post_processing/post_processing.h b/src/post_processing/post_processing.h new file mode 100644 index 0000000..3f59c93 --- /dev/null +++ b/src/post_processing/post_processing.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/src/scene/gltf.cpp b/src/scene/gltf.cpp new file mode 100644 index 0000000..cfe3a35 --- /dev/null +++ b/src/scene/gltf.cpp @@ -0,0 +1,124 @@ +#include "gltf.h" +#include "components/name.h" +#include "components/relationship.h" +#include "core/camera.h" + +#include + +auto Gltf::spawn_scene(std::size_t index, + entt::registry& registry, + entt::resource_cache& node_cache) -> entt::entity +{ + if (document.scenes.size() <= index) { + return entt::null; + } + + auto& gltf_scene = document.scenes.at(index); + + entt::entity scene_entity = registry.create(); + registry.emplace(scene_entity, Transform{}); + registry.emplace(scene_entity, GlobalTransform{}); + registry.emplace(scene_entity, Children{}); + + std::vector> nodes; + nodes.reserve(gltf_scene.nodes.size()); + + for (auto node_id : gltf_scene.nodes) { + auto const& node = document.nodes.at(node_id); + entt::hashed_string node_hash(node.name.c_str()); + nodes.push_back(node_cache[node_hash]); + } + + if (gltf_scene.name.empty()) { + spdlog::warn("glTF scene has no name."); + } + + // Spawn an entity for every node in scene + for (auto const& node : nodes) { + std::function spawn_node = + [®istry, &spawn_node](GltfNode const& node, entt::entity parent) { + auto entity = registry.create(); + registry.emplace(entity, node.name); + registry.emplace(entity, node.transform); + registry.emplace(entity, GlobalTransform{}); + registry.emplace(entity, Parent{.parent = parent}); + + std::vector child_entities; + + auto mesh = node.mesh; + if (mesh.has_value()) { + for (auto const& primitive : mesh.value()->primitives) { + auto mesh_entity = registry.create(); + registry.emplace(mesh_entity, Parent{.parent = entity}); + registry.emplace(mesh_entity, Transform{}); + registry.emplace(mesh_entity, GlobalTransform{}); + registry.emplace>(mesh_entity, primitive.mesh); + registry.emplace>(mesh_entity, primitive.material); + + child_entities.push_back(mesh_entity); + } + } + + auto camera = node.camera; + if (camera.has_value()) { + auto perspective = + std::get(camera.value().projection); + Camera::Perspective camera_perspective{.fov = perspective.yfov, + .aspect_ratio = perspective.aspectRatio, + .near = perspective.znear, + .far = perspective.zfar}; + registry.emplace(entity, Camera{.projection = camera_perspective}); + } + + // Spawn child nodes + for (auto const& child : node.children) { + auto child_entity = spawn_node(child, entity); + child_entities.push_back(child_entity); + } + + registry.emplace(entity, Children{.children = child_entities}); + return entity; + }; + + auto node_entity = spawn_node(node, scene_entity); + registry.get(scene_entity).children.push_back(node_entity); + } + + auto camera_view = registry.view(); + if (camera_view.empty()) { + // Spawn default camera + auto entity = registry.create(); + registry.emplace(entity, "Camera"); + registry.emplace(entity, Transform{.translation = Camera::DEFAULT_POSITION}); + registry.emplace(entity, GlobalTransform{}); + registry.emplace(entity, Camera{.projection = Camera::Perspective{}}); + } + + return scene_entity; +} + +auto Gltf::spawn_scene(std::string_view name, + entt::registry& registry, + entt::resource_cache& node_cache) -> entt::entity +{ + auto it = std::find_if(document.scenes.cbegin(), document.scenes.cend(), [name](auto& scene) { + return scene.name == name; + }); + + if (it != document.scenes.cend()) { + auto index = std::distance(document.scenes.cbegin(), it); + return spawn_scene(index, registry, node_cache); + } + + return entt::null; +} + +auto Gltf::spawn_default_scene(entt::registry& registry, entt::resource_cache& node_cache) + -> entt::entity +{ + if (document.scene != -1) { + return spawn_scene(document.scene, registry, node_cache); + } + + return entt::null; +} diff --git a/src/scene/gltf.h b/src/scene/gltf.h index d7a491f..8545e50 100644 --- a/src/scene/gltf.h +++ b/src/scene/gltf.h @@ -9,11 +9,6 @@ #include #include -class Mesh; -class Scene; -class Material; -class Image; - struct GltfPrimitive { entt::resource mesh; @@ -44,8 +39,17 @@ struct Gltf std::vector> materials; std::vector> meshes; std::vector> nodes; - std::vector> scenes; - std::optional> default_scene; fx::gltf::Document document; + + auto spawn_scene(std::size_t index, + entt::registry& registry, + entt::resource_cache& node_cache) -> entt::entity; + + auto spawn_scene(std::string_view name, + entt::registry& registry, + entt::resource_cache& node_cache) -> entt::entity; + + auto spawn_default_scene(entt::registry& registry, entt::resource_cache& node_cache) + -> entt::entity; }; diff --git a/src/scene/gltf_loader.cpp b/src/scene/gltf_loader.cpp index 824ee51..a91e4d4 100644 --- a/src/scene/gltf_loader.cpp +++ b/src/scene/gltf_loader.cpp @@ -2,6 +2,7 @@ #include "components/name.h" #include "components/relationship.h" #include "core/camera.h" +#include "entt/entity/fwd.hpp" #include "scene.h" #include @@ -388,107 +389,105 @@ auto GltfLoader::operator()(std::filesystem::path const& document_path) -> resul nodes.push_back(node.second); } - // Load scenes - std::vector> scenes; - for (auto const& gltf_scene : gltf.scenes) { - // Get nodes by hash - std::vector> nodes; - nodes.reserve(gltf_scene.nodes.size()); + // // Load scenes + // std::vector> scenes; + // for (auto const& gltf_scene : gltf.scenes) { + // // Get nodes by hash + // std::vector> nodes; + // nodes.reserve(gltf_scene.nodes.size()); - for (auto node_id : gltf_scene.nodes) { - auto const& node = gltf.nodes.at(node_id); - entt::hashed_string node_hash(node.name.c_str()); - nodes.push_back(gltf_node_cache[node_hash]); - } + // for (auto node_id : gltf_scene.nodes) { + // auto const& node = gltf.nodes.at(node_id); + // entt::hashed_string node_hash(node.name.c_str()); + // nodes.push_back(gltf_node_cache[node_hash]); + // } - if (gltf_scene.name.empty()) { - spdlog::warn("glTF scene has no name."); - } + // if (gltf_scene.name.empty()) { + // spdlog::warn("glTF scene has no name."); + // } - // Spawn an entity for every node in scene - for (auto const& node : nodes) { - std::function)> spawn_node = - [this, &spawn_node](GltfNode const& node, std::optional parent) { - auto entity = registry.create(); - registry.emplace(entity, node.name); - registry.emplace(entity, node.transform); - registry.emplace(entity, GlobalTransform{}); + // // Spawn an entity for every node in scene + // for (auto const& node : nodes) { + // std::function)> spawn_node = + // [this, &spawn_node](GltfNode const& node, std::optional parent) { + // auto entity = registry.create(); + // registry.emplace(entity, node.name); + // registry.emplace(entity, node.transform); + // registry.emplace(entity, GlobalTransform{}); - if (parent.has_value()) { - registry.emplace(entity, Parent{.parent = parent.value()}); - } + // if (parent.has_value()) { + // registry.emplace(entity, Parent{.parent = parent.value()}); + // } - std::vector child_entities; + // std::vector child_entities; - auto mesh = node.mesh; - if (mesh.has_value()) { - for (auto const& primitive : mesh.value()->primitives) { - auto mesh_entity = registry.create(); - registry.emplace(mesh_entity, Parent{.parent = entity}); - registry.emplace(mesh_entity, Transform{}); - registry.emplace(mesh_entity, GlobalTransform{}); - registry.emplace>(mesh_entity, primitive.mesh); - registry.emplace>(mesh_entity, - primitive.material); + // auto mesh = node.mesh; + // if (mesh.has_value()) { + // for (auto const& primitive : mesh.value()->primitives) { + // auto mesh_entity = registry.create(); + // registry.emplace(mesh_entity, Parent{.parent = entity}); + // registry.emplace(mesh_entity, Transform{}); + // registry.emplace(mesh_entity, GlobalTransform{}); + // registry.emplace>(mesh_entity, primitive.mesh); + // registry.emplace>(mesh_entity, + // primitive.material); - child_entities.push_back(mesh_entity); - } - } + // child_entities.push_back(mesh_entity); + // } + // } - auto camera = node.camera; - if (camera.has_value()) { - auto perspective = - std::get(camera.value().projection); - Camera::Perspective camera_perspective{.fov = perspective.yfov, - .aspect_ratio = - perspective.aspectRatio, - .near = perspective.znear, - .far = perspective.zfar}; - registry.emplace(entity, Camera{.projection = camera_perspective}); - } + // auto camera = node.camera; + // if (camera.has_value()) { + // auto perspective = + // std::get(camera.value().projection); + // Camera::Perspective camera_perspective{.fov = perspective.yfov, + // .aspect_ratio = + // perspective.aspectRatio, + // .near = perspective.znear, + // .far = perspective.zfar}; + // registry.emplace(entity, Camera{.projection = camera_perspective}); + // } - // Spawn child nodes - for (auto const& child : node.children) { - auto child_entity = spawn_node(child, entity); - child_entities.push_back(child_entity); - } + // // Spawn child nodes + // for (auto const& child : node.children) { + // auto child_entity = spawn_node(child, entity); + // child_entities.push_back(child_entity); + // } - registry.emplace(entity, Children{.children = child_entities}); - return entity; - }; + // registry.emplace(entity, Children{.children = child_entities}); + // return entity; + // }; - spawn_node(node, {}); - } + // spawn_node(node, {}); + // } - auto camera_view = registry.view(); - if (camera_view.empty()) { - // Spawn default camera - auto entity = registry.create(); - registry.emplace(entity, "Camera"); - registry.emplace(entity, Transform{.translation = Camera::DEFAULT_POSITION}); - registry.emplace(entity, GlobalTransform{}); - registry.emplace(entity, Camera{.projection = Camera::Perspective{}}); - } + // auto camera_view = registry.view(); + // if (camera_view.empty()) { + // // Spawn default camera + // auto entity = registry.create(); + // registry.emplace(entity, "Camera"); + // registry.emplace(entity, Transform{.translation = Camera::DEFAULT_POSITION}); + // registry.emplace(entity, GlobalTransform{}); + // registry.emplace(entity, Camera{.projection = Camera::Perspective{}}); + // } - entt::hashed_string scene_hash(gltf_scene.name.c_str()); - entt::resource scene_resource = - scene_cache.load(scene_hash, Scene{registry}).first->second; - scenes.push_back(scene_resource); - } + // entt::hashed_string scene_hash(gltf_scene.name.c_str()); + // entt::resource scene_resource = + // scene_cache.load(scene_hash, Scene{}).first->second; + // scenes.push_back(scene_resource); + // } - // Default scene - auto default_scene = [&gltf, &scenes]() -> std::optional> { - if (gltf.scene != -1) { - return scenes.at(gltf.scene); - } + // // Default scene + // auto default_scene = [&gltf, &scenes]() -> std::optional> { + // if (gltf.scene != -1) { + // return scenes.at(gltf.scene); + // } - return {}; - }(); + // return {}; + // }(); return std::make_shared(Gltf{.materials = std::move(materials), .meshes = std::move(gltf_meshes), .nodes = std::move(nodes), - .scenes = std::move(scenes), - .default_scene = default_scene, .document = std::move(gltf)}); } \ No newline at end of file diff --git a/src/scene/gltf_loader.h b/src/scene/gltf_loader.h index 2759e95..1be5468 100644 --- a/src/scene/gltf_loader.h +++ b/src/scene/gltf_loader.h @@ -1,6 +1,5 @@ #pragma once -#include "entt/entity/fwd.hpp" #include "gltf.h" #include @@ -19,10 +18,7 @@ struct GltfLoader entt::resource_cache& material_cache; entt::resource_cache& mesh_cache; entt::resource_cache& shader_cache; - entt::resource_cache& scene_cache; entt::resource_cache& gltf_mesh_cache; entt::resource_cache& gltf_node_cache; - - entt::registry& registry; }; diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 6bd8c9b..09a0e40 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -1,57 +1,21 @@ #include "scene.h" -#include "components/name.h" -#include "components/transform.h" -#include "core/camera.h" -#include "core/graphics/material.h" -#include "core/graphics/mesh.h" -#include "core/light.h" -#include "window/window.h" -Scene::Scene(entt::registry& registry) : registry(registry) -{ - auto mesh_view = registry.view>(); - for (auto [entity, mesh] : mesh_view.each()) { - registry.emplace(entity, GpuMesh(mesh)); +// void Scene::spawn_scenes(entt::registry& registry) +// { +// auto scene_view = registry.view>(); +// for (auto [entity, scene] : scene_view.each()) { +// registry.erase>(entity); - // Remove Mesh resource as it is no longer needed. - registry.erase>(entity); - } +// for (auto [id, storage] : scene->registry.storage()) { +// if (auto* other = registry.storage(id); other && storage.contains(entity)) { +// other->push(copy, storage.value(entity)); +// } +// } +// } +// } - auto material_view = registry.view>(); - for (auto [entity, material] : material_view.each()) { - registry.emplace(entity, GpuMaterial(material)); +// Notes: +// By loading a scene from disk, spawn it directly into the world. +// This is less flexible but easier to implement - // Remove Material resource as it is no longer needed. - registry.erase>(entity); - } - - // Spawn default lights - auto directional_light = registry.create(); - registry.emplace(directional_light, "Directional Light"); - registry.emplace( - directional_light, - Transform{.orientation = glm::toQuat( - glm::lookAt({}, DirectionalLight::DEFAULT_DIRECTION, Camera::UP_VECTOR))}); - registry.emplace(directional_light, GlobalTransform{}); - registry.emplace( - directional_light, DirectionalLight{.illuminance = DirectionalLight::DEFAULT_ILLUMINANCE}); - - auto point_light = registry.create(); - registry.emplace(point_light, "Point Light"); - registry.emplace(point_light, - Transform{.translation = PointLight::DEFAULT_POSITION}); - registry.emplace(point_light, GlobalTransform{}); - registry.emplace(point_light, - PointLight{.intensity = PointLight::DEFAULT_INTENSITY}); -} - -void Scene::update() -{ - GlobalTransform::update(registry); - Camera::aspect_ratio_update(registry); - Camera::keyboard_movement(registry); - - if (registry.ctx().get().catched) { - Camera::mouse_orientation(registry); - } -} +// Use bevy format: file.gltf#Scene0 otherwise default scene... diff --git a/src/scene/scene.h b/src/scene/scene.h index f198c93..babd37d 100644 --- a/src/scene/scene.h +++ b/src/scene/scene.h @@ -3,13 +3,10 @@ #include #include -class Scene +struct Scene { -public: - Scene(entt::registry& registry); + // entt::registry registry; - void update(); - -private: - entt::registry& registry; + // Spawns a scene for every entity having an entt:resource component + // static void spawn_scenes(entt::registry& registry); };