2021-01-11 17:45:51 +01:00
|
|
|
#include "./engine_tools.hpp"
|
|
|
|
|
|
|
|
#include <entt/config/version.h>
|
|
|
|
|
|
|
|
#include <mm/engine.hpp>
|
|
|
|
|
2021-04-28 19:38:25 +02:00
|
|
|
#include <mm/update_strategies/update_strategy.hpp>
|
2021-02-21 13:42:29 +01:00
|
|
|
|
|
|
|
#include <list>
|
|
|
|
|
2021-01-11 17:45:51 +01:00
|
|
|
#include <imgui/imgui.h>
|
|
|
|
|
|
|
|
namespace MM::Services {
|
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
using UpdateStrategies::update_key_t;
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
template<typename NColFn, typename LColFn, typename TTFn>
|
2021-04-28 19:38:25 +02:00
|
|
|
static void renderUpdateStratGraph(
|
|
|
|
const std::unordered_map<update_key_t, std::set<update_key_t>>& g,
|
|
|
|
std::set<update_key_t>& a,
|
|
|
|
NColFn&& node_color_fn,
|
|
|
|
LColFn&& line_color_fn,
|
|
|
|
TTFn&& tooltip_fn
|
|
|
|
) {
|
2021-02-21 13:42:29 +01:00
|
|
|
using UpdateStrategies::update_key_t;
|
|
|
|
|
|
|
|
std::set<update_key_t> work_queue{a.begin(), a.end()};
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
std::vector<std::vector<update_key_t>> node_table{};
|
|
|
|
node_table.push_back({});
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
std::unordered_map<update_key_t, std::pair<size_t, size_t>> node_table_pos;
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
// THX to the schwammal
|
|
|
|
|
|
|
|
{ // 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
2021-01-11 17:45:51 +01:00
|
|
|
}
|
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
{ // phase two, do rest
|
|
|
|
size_t curr_col = 0;
|
|
|
|
while (!work_queue.empty()) {
|
|
|
|
curr_col++;
|
|
|
|
node_table.push_back({});
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
std::vector<update_key_t> nodes_this_round{};
|
|
|
|
for (auto it = work_queue.begin(); it != work_queue.end();) {
|
|
|
|
bool deps_resolved = true;
|
|
|
|
const auto& it_deps = g.at(*it);
|
|
|
|
|
|
|
|
for (const update_key_t dep : it_deps) {
|
|
|
|
if (a.count(dep) && work_queue.count(dep)) {
|
|
|
|
deps_resolved = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2021-01-11 17:45:51 +01:00
|
|
|
}
|
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
{ // 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));
|
2021-01-11 17:45:51 +01:00
|
|
|
}
|
|
|
|
}
|
2021-02-21 13:42:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//ImGui::EndChild();
|
2021-01-11 17:45:51 +01:00
|
|
|
}
|
2021-02-21 13:42:29 +01:00
|
|
|
}
|
|
|
|
|
2021-04-28 19:38:25 +02:00
|
|
|
bool ImGuiEngineTools::enable(Engine& engine, std::vector<UpdateStrategies::TaskInfo>& task_array) {
|
2021-02-21 13:42:29 +01:00
|
|
|
auto& menu_bar = engine.getService<MM::Services::ImGuiMenuBar>();
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
// 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();
|
2021-01-11 17:45:51 +01:00
|
|
|
}
|
2021-02-21 13:42:29 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
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);
|
|
|
|
};
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-04-28 19:38:25 +02:00
|
|
|
// add task
|
|
|
|
task_array.push_back(
|
|
|
|
UpdateStrategies::TaskInfo{"ImGuiEngineTools::render"}
|
|
|
|
.fn([this](Engine& e){ renderImGui(e); })
|
2021-05-17 01:35:35 +02:00
|
|
|
.phase(UpdateStrategies::update_phase_t::PRE)
|
2021-04-28 19:38:25 +02:00
|
|
|
.succeed("ImGuiMenuBar::render")
|
|
|
|
);
|
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImGuiEngineTools::disable(Engine& engine) {
|
|
|
|
auto& menu_bar = engine.getService<MM::Services::ImGuiMenuBar>();
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImGuiEngineTools::renderImGui(Engine& engine) {
|
|
|
|
if (_show_about) {
|
|
|
|
renderAbout(engine);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_show_services) {
|
|
|
|
renderServices(engine);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_show_update_stategy) {
|
|
|
|
renderUpdateStrategy(engine);
|
2021-01-11 17:45:51 +01:00
|
|
|
}
|
2021-02-21 13:42:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
for (auto& it : engine._services) {
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
|
|
|
|
ImGui::TableNextColumn();
|
2021-04-28 19:38:25 +02:00
|
|
|
ImGui::Text("%u", it.first);
|
2021-02-21 13:42:29 +01:00
|
|
|
|
|
|
|
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();
|
2021-01-11 17:45:51 +01:00
|
|
|
}
|
|
|
|
}
|
2021-02-21 13:42:29 +01:00
|
|
|
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();
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
ImGui::Text("UpdateStrategy: '%s'", us_name);
|
|
|
|
|
2021-04-28 19:38:25 +02:00
|
|
|
// TODO: tabs? dropdown(combo)?
|
|
|
|
static const char* const phase_str[4] = {
|
|
|
|
"All",
|
|
|
|
"Pre",
|
|
|
|
"Main",
|
|
|
|
"Post",
|
|
|
|
};
|
|
|
|
static int curr_phase = 2;
|
|
|
|
|
|
|
|
ImGui::Combo("Phase", &curr_phase, phase_str, 4);
|
|
|
|
|
|
|
|
if (ImGui::BeginTabBar("tabs")) {
|
|
|
|
if (curr_phase != 0 && ImGui::BeginTabItem("Graph")) {
|
|
|
|
// BRUHHH this is needs to be cached
|
|
|
|
std::unordered_map<update_key_t, std::set<update_key_t>> graph;
|
|
|
|
std::unordered_map<update_key_t, UpdateStrategies::TaskInfo*> task_lut;
|
|
|
|
std::set<update_key_t> nodes;
|
|
|
|
|
|
|
|
// build lut
|
|
|
|
us.forEachTask([&graph, &nodes, &task_lut](UpdateStrategies::TaskInfo& task) -> bool {
|
|
|
|
if (task._phase != UpdateStrategies::update_phase_t(curr_phase-1)) {
|
|
|
|
return true; // skip, not our phase
|
|
|
|
}
|
|
|
|
|
|
|
|
graph[task._key] = task._dependencies;
|
|
|
|
task_lut[task._key] = &task;
|
|
|
|
nodes.emplace(task._key);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
// also do dependents // ugh, 2*N
|
|
|
|
us.forEachTask([&graph](UpdateStrategies::TaskInfo& task) -> bool {
|
|
|
|
if (task._phase != UpdateStrategies::update_phase_t(curr_phase-1)) {
|
|
|
|
return true; // skip, not our phase
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto it : task._dependents) {
|
|
|
|
graph[it].emplace(task._key);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
|
|
|
|
// TODO: make sense of the colloring
|
|
|
|
renderUpdateStratGraph(graph, nodes,
|
|
|
|
[](const update_key_t key) -> ImVec4 {
|
|
|
|
return {0.9f, 1.f, 0.9f, 1.f};
|
|
|
|
},
|
|
|
|
[](const update_key_t from, const update_key_t to) -> ImVec4 {
|
|
|
|
return {0.9f, 1.f, 0.9f, 1.f};
|
|
|
|
},
|
|
|
|
[&task_lut](update_key_t key) {
|
|
|
|
ImGui::SetTooltip("%s\n[%u]", task_lut.at(key)->_name.c_str(), key);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::BeginTabItem("List")) {
|
|
|
|
if (ImGui::BeginTable("table", curr_phase == 0 ? 3 : 2)) {
|
|
|
|
us.forEachTask([](UpdateStrategies::TaskInfo& task) -> bool {
|
|
|
|
if (
|
|
|
|
curr_phase == 0 ||
|
|
|
|
task._phase == UpdateStrategies::update_phase_t(curr_phase-1)
|
|
|
|
) {
|
|
|
|
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%u", task._key);
|
|
|
|
|
|
|
|
if (curr_phase == 0) {
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%s", phase_str[task._phase + 1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%s", task._name.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
ImGui::EndTable();
|
|
|
|
}
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndTabBar();
|
|
|
|
}
|
|
|
|
#if 0
|
2021-02-21 13:42:29 +01:00
|
|
|
auto& g = us_default->getGraph(UpdateStrategies::update_phase_t::MAIN);
|
|
|
|
auto& a = us_default->getActiveSet(UpdateStrategies::update_phase_t::MAIN);
|
|
|
|
std::set<update_key_t> 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();
|
2021-04-28 19:38:25 +02:00
|
|
|
ImGui::Text("%s", us_default->_tasks.at(it)._name.c_str());
|
2021-02-09 17:31:35 +01:00
|
|
|
}
|
2021-02-21 13:42:29 +01:00
|
|
|
ImGui::EndTable();
|
2021-02-09 17:31:35 +01:00
|
|
|
}
|
2021-02-21 13:42:29 +01:00
|
|
|
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) {
|
2021-04-28 19:38:25 +02:00
|
|
|
ImGui::SetTooltip("'%s'\n[%u]", us_default->_tasks.at(key)._name.c_str(), key);
|
2021-02-21 13:42:29 +01:00
|
|
|
});
|
|
|
|
ImGui::EndTabItem();
|
2021-02-09 17:31:35 +01:00
|
|
|
}
|
2021-01-11 17:45:51 +01:00
|
|
|
|
2021-02-21 13:42:29 +01:00
|
|
|
ImGui::EndTabBar();
|
2021-01-11 17:45:51 +01:00
|
|
|
}
|
|
|
|
}
|
2021-04-28 19:38:25 +02:00
|
|
|
#endif
|
2021-01-11 17:45:51 +01:00
|
|
|
}
|
2021-02-21 13:42:29 +01:00
|
|
|
ImGui::End();
|
|
|
|
}
|
2021-01-11 17:45:51 +01:00
|
|
|
|
|
|
|
} // namespace MM::Services
|
|
|
|
|