diff --git a/framework/engine/src/mm/update_strategies/default_strategy.hpp b/framework/engine/src/mm/update_strategies/default_strategy.hpp index d37c7a3..473701c 100644 --- a/framework/engine/src/mm/update_strategies/default_strategy.hpp +++ b/framework/engine/src/mm/update_strategies/default_strategy.hpp @@ -7,9 +7,16 @@ #include #include +// fwd +namespace MM::Services { + class ImGuiEngineTools; +} + namespace MM::UpdateStrategies { class SingleThreadedDefault : public MM::UpdateStrategies::UpdateStrategy { + friend MM::Services::ImGuiEngineTools; + private: struct Task { std::string name; diff --git a/framework/imgui/src/mm/services/engine_tools.cpp b/framework/imgui/src/mm/services/engine_tools.cpp index 3d8a506..bfff92c 100644 --- a/framework/imgui/src/mm/services/engine_tools.cpp +++ b/framework/imgui/src/mm/services/engine_tools.cpp @@ -1,124 +1,345 @@ #include "./engine_tools.hpp" +#include "mm/update_strategies/update_strategy.hpp" #include #include #include +#include + +#include + #include namespace MM::Services { - bool ImGuiEngineTools::enable(Engine& engine) { - auto& menu_bar = engine.getService(); +using UpdateStrategies::update_key_t; - menu_bar.menu_tree["Engine"]["Stop Engine"] = [](Engine& e) { - ImGui::Separator(); - if (ImGui::MenuItem("Stop Engine")) { - e.stop(); - } - }; +template +static void renderUpdateStratGraph(const std::unordered_map>& g, std::set& a, NColFn&& node_color_fn, LColFn&& line_color_fn, TTFn&& tooltip_fn) { + //auto& g = us_default->getGraph(UpdateStrategies::update_phase_t::MAIN); + //auto& a = us_default->getActiveSet(UpdateStrategies::update_phase_t::MAIN); - menu_bar.menu_tree["Engine"]["About"] = [this](Engine&) { - ImGui::MenuItem("About", NULL, &_show_about); - }; + using UpdateStrategies::update_key_t; - menu_bar.menu_tree["Engine"]["Services"] = [this](Engine&) { - ImGui::MenuItem("Services", NULL, &_show_services); - }; + std::set work_queue{a.begin(), a.end()}; - return true; - } + std::vector> node_table{}; + node_table.push_back({}); - void ImGuiEngineTools::disable(Engine& engine) { - auto& menu_bar = engine.getService(); + std::unordered_map> node_table_pos; - menu_bar.menu_tree["Engine"].erase("Stop Engine"); - menu_bar.menu_tree["Engine"].erase("About"); - menu_bar.menu_tree["Engine"].erase("Services"); - } + // THX to the schwammal - std::vector ImGuiEngineTools::registerUpdates(void) { - using namespace entt::literals; - return { - { - "ImGuiEngineTools::render"_hs, - "ImGuiEngineTools::render", - [this](Engine& e){ renderImGui(e); }, - UpdateStrategies::update_phase_t::MAIN, - true, - { - "ImGuiMenuBar::render"_hs + { // phase one, extract dep less nodes + for (auto it = work_queue.begin(); it != work_queue.end();) { + bool no_deps = g.at(*it).empty(); + + if (!no_deps) { + for (auto dep : g.at(*it)) { + if (a.count(dep)) { + no_deps = false; + break; + } } } - }; - } - void ImGuiEngineTools::renderImGui(Engine& engine) { - if (_show_about) { - renderAbout(); - } - - if (_show_services) { - renderServices(engine); + if (no_deps) { + node_table_pos[*it] = {0, node_table[0].size()}; + node_table[0].emplace_back(*it); + it = work_queue.erase(it); + } else { + it++; + } } } - void ImGuiEngineTools::renderAbout(void) { - if (ImGui::Begin("About##EngineTools", &_show_about)) { - ImGui::Text("TODO"); - ImGui::Text("MushMachine"); - ImGui::Text("EnTT v%d.%d.%d", ENTT_VERSION_MAJOR, ENTT_VERSION_MINOR, ENTT_VERSION_PATCH); - } - ImGui::End(); - } + { // phase two, do rest + size_t curr_col = 0; + while (!work_queue.empty()) { + curr_col++; + node_table.push_back({}); - void ImGuiEngineTools::renderServices(Engine& engine) { - if (ImGui::Begin("Services##EngineTools", &_show_services)) { - ImGui::Text("TODO: make sortable"); - ImGui::Checkbox("edit mode", &_services_edit_mode); + std::vector nodes_this_round{}; + for (auto it = work_queue.begin(); it != work_queue.end();) { + bool deps_resolved = true; + const auto& it_deps = g.at(*it); - if (ImGui::BeginTable( - "services_table", - 3, - ImGuiTableFlags_RowBg //| - )) { - ImGui::TableSetupColumn("id", ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("name"); - ImGui::TableSetupColumn("status"); - ImGui::TableHeadersRow(); - - for (auto& it : engine._services) { - ImGui::TableNextRow(); - - ImGui::TableNextColumn(); - ImGui::Text("%d", it.first); - - ImGui::TableNextColumn(); - ImGui::Text("%s", it.second->second->name()); - - ImGui::TableNextColumn(); - if (_services_edit_mode) { - ImGui::PushID(it.first); - if (ImGui::SmallButton(it.second->first ? "enabled" : "disabled")) { - if (it.second->first) { - engine.disableService(it.first); - } else { - engine.enableService(it.first); - } - } - //ImGui::SetTooltip("click to toggle!"); the heck? - ImGui::PopID(); - } else { - ImGui::Text("%s", it.second->first ? "enabled" : "disabled"); + for (const update_key_t dep : it_deps) { + if (a.count(dep) && work_queue.count(dep)) { + deps_resolved = false; + break; } } - ImGui::EndTable(); + if (deps_resolved) { + //node_table_pos[*it] = {curr_col, node_table[curr_col].size()}; + //node_table[curr_col].emplace_back(*it); + //it = work_queue.erase(it); + nodes_this_round.push_back(*it); + } else { + //it++; + } + it++; + } + + // apply nodes + for (auto it : nodes_this_round) { + node_table_pos[it] = {curr_col, node_table[curr_col].size()}; + node_table[curr_col].emplace_back(it); + work_queue.erase(it); } } - ImGui::End(); } + { // display + //ImGui::BeginChild("canvas", {0, 0}, true); + + const ImVec2 cp = ImGui::GetCursorScreenPos(); + const auto max_cont = ImGui::GetWindowContentRegionMax(); + ImGui::Dummy(max_cont); + + auto* dl = ImGui::GetWindowDrawList(); + const float circle_radius = 20.f; + const float circle_padding = 40.f; + + // lines + for (const update_key_t node : a) { + for (const update_key_t dep : g.at(node)) { + if (!a.count(dep)) { + continue; + } + + ImVec2 p_start{ + cp.x + node_table_pos[node].first*(2*circle_radius+circle_padding) + circle_radius, + cp.y + node_table_pos[node].second*(2*circle_radius+circle_padding) + circle_radius, + }; + + ImVec2 p_end{ + cp.x + node_table_pos[dep].first*(2*circle_radius+circle_padding) + circle_radius, + cp.y + node_table_pos[dep].second*(2*circle_radius+circle_padding) + circle_radius, + }; + + dl->AddLine(p_start, p_end, ImGui::ColorConvertFloat4ToU32(line_color_fn(node, dep))); + } + } + + // nodes + for (size_t curr_col = 0; curr_col < node_table.size(); curr_col++) { + const auto& curr_table_col = node_table[curr_col]; + for (size_t curr_row = 0; curr_row < curr_table_col.size(); curr_row++) { + ImVec2 p{ + cp.x + curr_col*(2*circle_radius+circle_padding) + circle_radius, + cp.y + curr_row*(2*circle_radius+circle_padding) + circle_radius, + }; + + //dl->AddCircleFilled(p, circle_radius, IM_COL32(100, 100, 100, 100)); + auto col_vec = node_color_fn(curr_table_col.at(curr_row)); + ImVec4 col_vec_bg = col_vec; + col_vec_bg.w *= 0.2f; + + dl->AddCircleFilled(p, circle_radius, ImGui::ColorConvertFloat4ToU32(col_vec_bg)); + dl->AddCircle(p, circle_radius, ImGui::ColorConvertFloat4ToU32(col_vec)); + + if (ImGui::IsMouseHoveringRect( + {p.x - circle_radius, p.y - circle_radius}, + {p.x + circle_radius, p.y + circle_radius} + )) { + //ImGui::SetTooltip("'%s'\n[%u]", , curr_table_col.at(curr_row)); + tooltip_fn(curr_table_col.at(curr_row)); + } + } + } + + //ImGui::EndChild(); + } +} + +bool ImGuiEngineTools::enable(Engine& engine) { + auto& menu_bar = engine.getService(); + + // use underscore hack to make it last + menu_bar.menu_tree["Engine"]["_Stop Engine"] = [](Engine& e) { + ImGui::Separator(); + if (ImGui::MenuItem("Stop Engine")) { + e.stop(); + } + }; + + menu_bar.menu_tree["Engine"]["About"] = [this](Engine&) { + ImGui::MenuItem("About", NULL, &_show_about); + }; + + menu_bar.menu_tree["Engine"]["Services"] = [this](Engine&) { + ImGui::MenuItem("Services", NULL, &_show_services); + }; + + menu_bar.menu_tree["Engine"]["UpdateStrategy"] = [this](Engine&) { + ImGui::MenuItem("UpdateStrategy", NULL, &_show_update_stategy); + }; + + return true; +} + +void ImGuiEngineTools::disable(Engine& engine) { + auto& menu_bar = engine.getService(); + + menu_bar.menu_tree["Engine"].erase("_Stop Engine"); + menu_bar.menu_tree["Engine"].erase("About"); + menu_bar.menu_tree["Engine"].erase("Services"); + menu_bar.menu_tree["Engine"].erase("UpdateStrategy"); +} + +std::vector ImGuiEngineTools::registerUpdates(void) { +using namespace entt::literals; + return { + { + "ImGuiEngineTools::render"_hs, + "ImGuiEngineTools::render", + [this](Engine& e){ renderImGui(e); }, + UpdateStrategies::update_phase_t::MAIN, + true, + { + "ImGuiMenuBar::render"_hs + } + } + }; +} + +void ImGuiEngineTools::renderImGui(Engine& engine) { + if (_show_about) { + renderAbout(engine); + } + + if (_show_services) { + renderServices(engine); + } + + if (_show_update_stategy) { + renderUpdateStrategy(engine); + } +} + +void ImGuiEngineTools::renderAbout(Engine& engine) { + if (ImGui::Begin("About##EngineTools", &_show_about)) { + ImGui::Text("TODO"); + ImGui::Text("MushMachine"); + ImGui::Text("UpdateStrategy: %s", engine.getUpdateStrategy().name()); + ImGui::Text("EnTT v%d.%d.%d", ENTT_VERSION_MAJOR, ENTT_VERSION_MINOR, ENTT_VERSION_PATCH); + } + ImGui::End(); +} + +void ImGuiEngineTools::renderServices(Engine& engine) { + if (ImGui::Begin("Services##EngineTools", &_show_services)) { + ImGui::Text("TODO: make sortable"); + ImGui::Checkbox("edit mode", &_services_edit_mode); + + if (ImGui::BeginTable( + "services_table", + 3, + ImGuiTableFlags_RowBg //| + )) { + ImGui::TableSetupColumn("id", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("name"); + ImGui::TableSetupColumn("status"); + ImGui::TableHeadersRow(); + + for (auto& it : engine._services) { + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + ImGui::Text("%d", it.first); + + ImGui::TableNextColumn(); + ImGui::Text("%s", it.second->second->name()); + + ImGui::TableNextColumn(); + if (_services_edit_mode) { + ImGui::PushID(it.first); + if (ImGui::SmallButton(it.second->first ? "enabled" : "disabled")) { + if (it.second->first) { + engine.disableService(it.first); + } else { + engine.enableService(it.first); + } + } + //ImGui::SetTooltip("click to toggle!"); the heck? + ImGui::PopID(); + } else { + ImGui::Text("%s", it.second->first ? "enabled" : "disabled"); + } + } + + ImGui::EndTable(); + } + } + ImGui::End(); +} + +void ImGuiEngineTools::renderUpdateStrategy(Engine& engine) { + if (ImGui::Begin("UpdateStrategy##EngineTools", &_show_update_stategy, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { + auto& us = engine.getUpdateStrategy(); + auto us_name = us.name(); + + ImGui::Text("UpdateStrategy: '%s'", us_name); + ImGui::Separator(); + + auto* us_default = dynamic_cast(&us); + if (us_default) { + auto& g = us_default->getGraph(UpdateStrategies::update_phase_t::MAIN); + auto& a = us_default->getActiveSet(UpdateStrategies::update_phase_t::MAIN); + std::set nodes; + for (const auto& it : g) { + nodes.emplace(it.first); + } + + if (ImGui::BeginTabBar("tabs")) { + if (ImGui::BeginTabItem("table")) { + if (ImGui::BeginTable("table", 2)) { + for (const auto it : nodes) { + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + ImGui::Text("%u", it); + + ImGui::TableNextColumn(); + ImGui::Text("%s", us_default->_tasks[it].name.c_str()); + } + ImGui::EndTable(); + } + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("graph")) { + renderUpdateStratGraph(g, nodes, + [&a](const update_key_t key) -> ImVec4 { + if (a.count(key)) { + return {0.9f, 1.f, 0.9f, 1.f}; + } else { + return {0.4f, 0.2f, 0.2f, 1.f}; + } + }, + [&a](const update_key_t from, const update_key_t to) -> ImVec4 { + if (a.count(from) && a.count(to)) { + return {0.9f, 1.f, 0.9f, 1.f}; + } else { + return {0.4f, 0.2f, 0.2f, 1.f}; + } + }, + [us_default](update_key_t key) { + ImGui::SetTooltip("'%s'\n[%u]", us_default->_tasks[key].name.c_str(), key); + }); + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + } + } + ImGui::End(); +} + } // namespace MM::Services diff --git a/framework/imgui/src/mm/services/engine_tools.hpp b/framework/imgui/src/mm/services/engine_tools.hpp index a2fa4f8..e549b2e 100644 --- a/framework/imgui/src/mm/services/engine_tools.hpp +++ b/framework/imgui/src/mm/services/engine_tools.hpp @@ -16,14 +16,16 @@ namespace MM::Services { private: bool _show_about = false; bool _show_services = false; + bool _show_update_stategy = false; bool _services_edit_mode = false; private: void renderImGui(Engine& engine); - void renderAbout(void); + void renderAbout(Engine& engine); void renderServices(Engine& engine); + void renderUpdateStrategy(Engine& engine); }; } // namespace MM::Services diff --git a/framework/simple_scene/src/mm/services/simple_scene.cpp b/framework/simple_scene/src/mm/services/simple_scene.cpp index a4dc079..64af80b 100644 --- a/framework/simple_scene/src/mm/services/simple_scene.cpp +++ b/framework/simple_scene/src/mm/services/simple_scene.cpp @@ -44,7 +44,8 @@ std::vector SimpleSceneService::registerUp [this](Engine& e) { this->changeSceneFixedUpdate(e); }, UpdateStrategies::update_phase_t::MAIN, true, - {"SimpleSceneService::scene_update"_hs} // first update, than change???? + //{"SimpleSceneService::scene_update"_hs} // first update, than change???? + {"SimpleSceneService::scene_tick"_hs} } }; }