diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index 21f97cc..8f3030f 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(std_utils) add_subdirectory(screen_director) add_subdirectory(filesystem) add_subdirectory(simple_scene) +add_subdirectory(organizer_scene) if(NOT MM_HEADLESS) add_subdirectory(sdl_service) diff --git a/framework/imgui/src/mm/services/scene_tools.cpp b/framework/imgui/src/mm/services/scene_tools.cpp index 16d6d25..6f0b7d0 100644 --- a/framework/imgui/src/mm/services/scene_tools.cpp +++ b/framework/imgui/src/mm/services/scene_tools.cpp @@ -6,6 +6,7 @@ #include #include "./imgui_menu_bar.hpp" +#include "mm/components/time_delta.hpp" #include @@ -70,6 +71,17 @@ namespace MM::Services { ImGui::MenuItem("Camera3D Tool", NULL, &_show_camera_tool); }; + menu_bar.menu_tree["Scene"]["TimeCtx"] = [this](Engine& e) { + MM::Components::TimeDelta* td_ptr = nullptr; + + if (auto* ssi_ptr = e.tryService()) { + auto& scene = ssi_ptr->getScene(); + td_ptr = scene.try_ctx(); + } + + ImGui::MenuItem("TimeDelta Context", NULL, &_show_time_delta_ctx, td_ptr); + }; + return true; } @@ -78,6 +90,8 @@ namespace MM::Services { menu_bar.menu_tree["Scene"].erase("Metrics"); menu_bar.menu_tree["Scene"].erase("EntityEditor"); + menu_bar.menu_tree["Scene"].erase("CameraTool"); + menu_bar.menu_tree["Scene"].erase("TimeCtx"); } std::vector ImGuiSceneToolsService::registerUpdates(void) { @@ -97,15 +111,6 @@ namespace MM::Services { } void ImGuiSceneToolsService::renderImGui(Engine& engine) { - //if (show_menu && ImGui::BeginMainMenuBar()) { - - //if (ImGui::BeginMenu("Windows")) { - //ImGui::MenuItem("Camera Tool", NULL, &_show_camera_tool); - //ImGui::EndMenu(); - //} - - //} - auto& scene = engine.tryService()->getScene(); if (_show_scene_metrics) { @@ -150,6 +155,16 @@ namespace MM::Services { } ImGui::End(); } + + if (_show_time_delta_ctx) { + if (ImGui::Begin("Scene TimeDelta Context", &_show_time_delta_ctx)) { + auto* td_ptr = scene.try_ctx(); + ImGui::Value("tickDelta", td_ptr->tickDelta); + ImGui::SliderFloat("deltaFactor", &td_ptr->deltaFactor, 0.f, 10.f, "%.5f", ImGuiSliderFlags_Logarithmic); + + } + ImGui::End(); + } } EntityEditor& ImGuiSceneToolsService::getEntityEditor(void) { diff --git a/framework/imgui/src/mm/services/scene_tools.hpp b/framework/imgui/src/mm/services/scene_tools.hpp index 143748a..f9a0edd 100644 --- a/framework/imgui/src/mm/services/scene_tools.hpp +++ b/framework/imgui/src/mm/services/scene_tools.hpp @@ -23,6 +23,7 @@ namespace MM::Services { bool _show_entity_editor = false; bool _show_entity_list = true; bool _show_camera_tool = false; + bool _show_time_delta_ctx = false; EntityEditor _entity_editor; // for list diff --git a/framework/organizer_scene/CMakeLists.txt b/framework/organizer_scene/CMakeLists.txt new file mode 100644 index 0000000..32e18d0 --- /dev/null +++ b/framework/organizer_scene/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.2) +project(organizer_scene CXX) + +add_library(organizer_scene + src/mm/services/organizer_scene.hpp + src/mm/services/organizer_scene.cpp +) + +target_include_directories(organizer_scene PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src") + +target_link_libraries(organizer_scene + engine + common_components +) + +if (BUILD_TESTING) + #add_subdirectory(test) +endif() + diff --git a/framework/organizer_scene/src/mm/services/organizer_scene.cpp b/framework/organizer_scene/src/mm/services/organizer_scene.cpp new file mode 100644 index 0000000..cb85616 --- /dev/null +++ b/framework/organizer_scene/src/mm/services/organizer_scene.cpp @@ -0,0 +1,174 @@ +#include "./organizer_scene.hpp" + +#include + +#include +#include + +#include + +#include +#include +#define LOG_OSS(x) LOG("OrganizerSceneService", x) + +namespace entt { + +// graphviz dot export +static std::ostream& operator<<(std::ostream& out, const std::vector& nodes) { + out << "digraph EnTT_organizer {\nrankdir=RL;\n"; + + + for (size_t i = 0; i < nodes.size(); i++) { + out << "n" << i << "[shape=" << (nodes[i].top_level() ? "doublecircle" : "circle") << " label=\"" << (nodes[i].name() == nullptr ? "NoName" : nodes[i].name()) << "\"];\n"; + } + + for (size_t i = 0; i < nodes.size(); i++) { + for (const size_t child : nodes[i].children()) { + out << "n" << child << " -> " << "n" << i << ";\n"; + } + } + + out << "}"; + return out; +} + +} // entt + +namespace MM::Services { + +bool OrganizerSceneService::enable(Engine& engine) { + // default scene + if (!_scene) { + _scene = std::make_unique(); + _scene->set(&engine); + updateOrganizerVertices(*_scene); + } + + resetTime(); + + return true; +} + +void OrganizerSceneService::disable(Engine&) { +} + +std::vector OrganizerSceneService::registerUpdates(void) { + using namespace entt::literals; + return { + { + "OrganizerSceneService::scene_update"_hs, + "OrganizerSceneService::scene_update", + [this](Engine& e) { sceneUpdate(e); }, + // depends on imgui + }, + { + "OrganizerSceneService::scene_tick"_hs, + "OrganizerSceneService::scene_tick", + [this](Engine& e) { sceneFixedUpdate(e); }, + UpdateStrategies::update_phase_t::MAIN, + true, + { + "OrganizerSceneService::scene_update"_hs, // bc it renders imgui, but this is not "hard" + } + }, + { + "OrganizerSceneService::scene_changer"_hs, + "OrganizerSceneService::scene_changer", + [this](Engine& e) { changeSceneFixedUpdate(e); }, + UpdateStrategies::update_phase_t::MAIN, + true, + { + "OrganizerSceneService::scene_tick"_hs, + } + }, + }; +} + +void OrganizerSceneService::sceneFixedUpdate(Engine&) { + ZoneScoped; + + auto newNow = clock::now(); + auto deltaTime = std::chrono::duration_cast(newNow - _last_time); + _last_time = newNow; + _accumulator += deltaTime.count(); + const double dt = f_delta * 1'000'000'000.0; + + size_t continuous_counter = 0; + + auto& time_ctx = _scene->ctx_or_set(f_delta, delta_factor); + time_ctx.tickDelta = f_delta * delta_factor; + time_ctx.deltaFactor = delta_factor; + + // TODO: this while is just cancer + while (_accumulator >= static_cast(dt)){ + _accumulator -= static_cast(dt); + continuous_counter++; + + for (auto&& v : _scene->ctx>()) { + v.callback()(v.data(), *_scene); + } + + TracyPlot("MM::Services::OrganizerSceneService::_scene.alive", (int64_t)_scene->alive()); + } + + if (continuous_counter > 2) { + LOG_OSS(fmt::format("had {} contiguous scene ticks!", continuous_counter)); + } +} + +void OrganizerSceneService::changeSceneFixedUpdate(Engine& engine) { + if (_next_scene) { + LOG_OSS("changing scene..."); + _scene = std::move(_next_scene); + _scene->set(&engine); // make engine accessible from scene + updateOrganizerVertices(*_scene); + } +} + +void OrganizerSceneService::sceneUpdate(Engine&) { + ZoneScoped; + + //if (ImGui::Begin("OrganizerScene")) { + //ImGui::SliderFloat("time_factor", &delta_factor, 0.f, 10.f, "%.5f", ImGuiSliderFlags_Logarithmic); + //} + //ImGui::End(); + + //for (auto&& v : _scene->ctx>()) { + //v.callback()(v.data(), *_scene); + //} + + //TracyPlot("MM::Services::OrganizerSceneService::_scene.alive", (int64_t)_scene->alive()); +} + +void OrganizerSceneService::changeScene(std::unique_ptr&& new_scene) { + if (_next_scene) { + LOG_OSS("warn: already next scene enqueued! overwriting..."); + } + + _next_scene = std::move(new_scene); +} + +void OrganizerSceneService::changeSceneNow(std::unique_ptr&& new_scene) { + _scene = std::move(new_scene); + //_scene->set(&engine); // make engine accessible from scene + updateOrganizerVertices(*_scene); +} + +void OrganizerSceneService::updateOrganizerVertices(Scene& scene) { + scene.ctx_or_set>() = + scene.ctx_or_set().graph(); + + if (!scene.try_ctx()) { + scene.set(); + } + + SPDLOG_DEBUG("graph:\n{}", scene.ctx>()); +} + +void OrganizerSceneService::resetTime(void) { + _last_time = clock::now(); + _accumulator = 0; +} + +} // MM::Services + diff --git a/framework/organizer_scene/src/mm/services/organizer_scene.hpp b/framework/organizer_scene/src/mm/services/organizer_scene.hpp new file mode 100644 index 0000000..bcfc846 --- /dev/null +++ b/framework/organizer_scene/src/mm/services/organizer_scene.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include + +namespace MM::Services { + + // provides an ~implementation for SceneServiceInterface + // !! IMPORTANT: relies on entt::organizer. Use it to add systems! + class OrganizerSceneService : public SceneServiceInterface { + private: + std::unique_ptr _scene; + std::unique_ptr _next_scene; // enqueued next scene + + using clock = std::chrono::high_resolution_clock; + long long int _accumulator = 0; + std::chrono::time_point _last_time; + + public: + const float f_delta; + + float delta_factor = 1.f; + + public: // service + explicit OrganizerSceneService(const float update_delta = 1.f/60.f) : f_delta(update_delta) {} + + const char* name(void) override { return "OrganizerSceneService"; } + + bool enable(Engine& engine) override; + void disable(Engine& engine) override; + + std::vector registerUpdates(void) override; + + public: // scene interface + Scene& getScene(void) override { return *_scene; } + + void changeScene(std::unique_ptr&& new_scene) override; + + // be carefull of that one + void changeSceneNow(std::unique_ptr&& new_scene) override; + + public: + void sceneFixedUpdate(Engine& engine); + void changeSceneFixedUpdate(Engine& engine); + + void sceneUpdate(Engine& engine); + void updateOrganizerVertices(Scene& scene); + + void resetTime(void); + }; + +} // MM::Services +