Commit 77880abb authored by Florian Oetke's avatar Florian Oetke
Browse files

tweaked console and support for properties

parent a8535228
Subproject commit 047a45313c80155ade06f2a5f01e3dbc5ec826e3
Subproject commit 0b0ea10eaad60ee280f9f8fbd745a42fda37ee67
......@@ -27,7 +27,7 @@ namespace mirrage {
char** argv,
char** env)
: Engine(org, title, version_major, version_minor, debug, false, argc, argv, env)
, _debug_ui(gui(), bus())
, _debug_ui(assets(), gui(), bus())
, _renderer_factory(std::make_unique<renderer::Deferred_renderer_factory>(
*this,
window(),
......
......@@ -84,6 +84,17 @@ namespace mirrage {
auto cornell = _meta_system.entities().emplace("cornell");
cornell.get<Transform_comp>().process([&](auto& transform) { transform.position = {1000, 0, 0}; });
_cmd_commands.add_property("pos",
[&](glm::vec3 position) {
_camera.get<Transform_comp>().process(
[&](auto& transform) { transform.position = position; });
},
[&]() {
return _camera.get<Transform_comp>().process(
glm::vec3(0, 0, 0),
[&](auto& transform) { return transform.position; });
});
_meta_system.entities().emplace("sponza");
_sun = _meta_system.entities().emplace("sun");
......
......@@ -13,6 +13,7 @@
#include <mirrage/engine.hpp>
#include <mirrage/gui/gui.hpp>
#include <mirrage/renderer/deferred_renderer.hpp>
#include <mirrage/utils/console_command.hpp>
#include <mirrage/utils/maybe.hpp>
......@@ -70,6 +71,8 @@ namespace mirrage {
util::Time _performance_log_delay_left{1};
bool _preformance_log_first_row = true;
util::Console_command_container _cmd_commands;
void _set_preset(int);
void _update_sun_position();
......
......@@ -334,7 +334,7 @@ namespace mirrage::asset {
}
auto Asset_manager::open_rw(const AID& id) -> ostream
{
auto path = resolve(id);
auto path = resolve(id, false);
if(path.is_nothing()) {
path = resolve(AID{id.type(), ""}).process(id.str(), [&](auto&& prefix) {
return append_file(prefix, id.str());
......@@ -448,6 +448,7 @@ namespace mirrage::asset {
auto kvp = util::split(l, "=");
std::string path = util::trim_copy(kvp.second);
if(!path.empty()) {
LOG(plog::debug) << " " << AID{kvp.first}.str() << " = " << path;
_dispatchers.emplace(AID{kvp.first}, std::move(path));
}
}
......
......@@ -19,6 +19,7 @@ add_library(mirrage_gui STATIC
add_library(mirrage::gui ALIAS mirrage_gui)
file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/assets_mirrage_gui.map" CONTENT
"cfg:gui = settings/gui.json
cfg:console_history = console_history.txt
font: = fonts/
font:default_font = fonts/default_font.ttf
")
......
......@@ -7,6 +7,7 @@
#pragma once
#include <mirrage/asset/asset_manager.hpp>
#include <mirrage/utils/console_command.hpp>
#include <mirrage/utils/messagebus.hpp>
......@@ -40,7 +41,7 @@ namespace mirrage::gui {
class Debug_ui {
public:
Debug_ui(Gui&, util::Message_bus&);
Debug_ui(asset::Asset_manager&, Gui&, util::Message_bus&);
void draw();
......@@ -49,6 +50,7 @@ namespace mirrage::gui {
Gui& _gui;
util::Mailbox_collection _mailbox;
asset::Asset_manager& _assets;
bool _show_console = false;
bool _focus_prompt = false;
bool _show_suggestions = false;
......@@ -60,6 +62,10 @@ namespace mirrage::gui {
int _command_input_length = 0;
util::Console_command_container _commands;
std::unordered_set<std::string> _shown_debug_menus;
std::vector<std::string> _history;
int _current_history_entry = -1;
void _save_history();
};
......
......@@ -20,16 +20,61 @@ namespace mirrage::gui {
nk_color{140, 140, 140, 255}, // debug = 5,
nk_color{140, 140, 140, 255} // verbose = 6
}};
const auto history_aid = "cfg:console_history"_aid;
} // namespace
void Debug_console_appender::write(const plog::Record& record)
{
_messages.emplace_back(record.getSeverity(), plog::TxtFormatter::format(record));
auto msg = plog::TxtFormatter::format(record);
auto prev_pos = std::string::size_type(0);
auto pos = std::string::size_type(0);
while((pos = msg.find("\n", prev_pos)) != std::string::npos) {
auto len = pos - prev_pos + 1;
if(len > 0)
_messages.emplace_back(record.getSeverity(),
prev_pos == 0 ? msg.substr(prev_pos, pos - prev_pos)
: " " + msg.substr(prev_pos, pos - prev_pos));
prev_pos = pos + 1;
}
}
Debug_ui::Debug_ui(Gui& gui, util::Message_bus& bus) : _gui(gui), _mailbox(bus)
Debug_ui::Debug_ui(asset::Asset_manager& assets, Gui& gui, util::Message_bus& bus)
: _gui(gui), _mailbox(bus), _assets(assets)
{
assets.open(history_aid).process([&](auto& is) { _history = is.lines(); });
_commands.add("help | Prints all available commands", [&]() {
LOG(plog::info) << "Available commands:\n"
<< [](std::ostream& stream) -> std::ostream& {
for(auto& c : util::Console_command_container::list_all_commands()) {
stream << c.second.api() << "\n";
}
return stream;
};
});
_commands.add("history | Prints all previous commands", [&]() {
IF_LOG_(PLOG_DEFAULT_INSTANCE, plog::info)
{
auto record =
plog::Record(plog::info, PLOG_GET_FUNC(), __LINE__, PLOG_GET_FILE(), PLOG_GET_THIS());
record << "History:\n";
for(auto& h : _history) {
record << h << "\n";
}
(*plog::get<PLOG_DEFAULT_INSTANCE>()) += std::move(record);
}
});
_commands.add("history.clear | Clears the history", [&]() {
_history.clear();
_save_history();
});
_commands.add("show <ui> | Enables a specific debug UI element (see list_uis for possible options)",
[&](std::string ui) {
if(Debug_menu::is_debug_menu(ui)) {
......@@ -108,7 +153,7 @@ namespace mirrage::gui {
else
nk_text_colored(ctx,
msg.msg.c_str(),
int(msg.msg.size()) - 1,
int(msg.msg.size()),
NK_TEXT_ALIGN_LEFT,
msg_color[std::size_t(msg.severity)]);
......@@ -147,7 +192,10 @@ namespace mirrage::gui {
_selected_suggestion = -1;
} else if(util::Console_command_container::call(cmd)) {
_command_input_length = 0;
_history.emplace_back(cmd);
_save_history();
_command_input_length = 0;
_current_history_entry = -1;
}
} else if(cmd_event & NK_EDIT_ACTIVE && _selected_suggestion >= 0) {
for(auto i : util::range(static_cast<int>(NK_KEY_MAX))) {
......@@ -176,6 +224,30 @@ namespace mirrage::gui {
_selected_suggestion = suggestions_size - 1;
else if(_selected_suggestion >= suggestions_size)
_selected_suggestion = 0;
_current_history_entry = -1;
}
if(!_history.empty()) {
auto history_up = nk_input_is_key_pressed(&ctx->input, NK_KEY_SCROLL_UP);
auto history_down = nk_input_is_key_pressed(&ctx->input, NK_KEY_SCROLL_DOWN);
if(history_up) {
_current_history_entry--;
} else if(history_down) {
_current_history_entry++;
}
if(history_up || history_down) {
if(_current_history_entry < 0)
_current_history_entry = int(_history.size() - 1);
else if(_current_history_entry >= int(_history.size() - 1))
_current_history_entry = 0;
auto& history = _history[std::size_t(_current_history_entry)];
std::copy(history.begin(), history.end(), _command_input_buffer.begin());
_command_input_length = int(history.size());
}
}
nk_layout_row_dynamic(ctx, 12, 3);
......@@ -200,10 +272,11 @@ namespace mirrage::gui {
if(space != std::string::npos)
name_sep = space;
if(s->api()[name_sep] != '|')
button_state |= nk_interactive_text(
ctx, s->api().c_str() + name_sep, int(sep - name_sep), color);
else
if(s->api()[name_sep] != '|') {
auto len = sep != std::string::npos ? int(sep - name_sep)
: int(s->api().size() - name_sep);
button_state |= nk_interactive_text(ctx, s->api().c_str() + name_sep, len, color);
} else
button_state |= nk_interactive_text(ctx, "", 0, color);
} else {
......@@ -236,6 +309,14 @@ namespace mirrage::gui {
nk_end(ctx);
}
void Debug_ui::_save_history()
{
auto os = _assets.open_rw(history_aid);
for(auto& h : _history)
os << h << "\n";
os.close();
}
Debug_menu::Debug_menu(std::string name) : _name(std::move(name)) { instances().emplace_back(this); }
Debug_menu::~Debug_menu() { util::erase_fast(instances(), this); }
......
......@@ -55,6 +55,13 @@ namespace mirrage::util {
Func _exec;
};
namespace detail {
template <typename T>
struct Default_var_setter {
void operator()(T& org, T new_val) { org = new_val; }
};
} // namespace detail
class Console_command_container {
public:
~Console_command_container();
......@@ -62,13 +69,33 @@ namespace mirrage::util {
template <typename F>
auto add(std::string api, F &&) -> Console_command_container&;
template <typename T, typename F = detail::Default_var_setter<T>>
auto add_var(const std::string& name, T& var, F setter = {})
{
add_property(name,
[&var, setter = std::move(setter)](T new_val) mutable { setter(var, new_val); },
[&var, name = name]() -> decltype(auto) { return var; });
}
template <typename FS, typename FG>
auto add_property(const std::string& name, FS&& setter, FG&& getter)
{
add("set." + name + " <value> | Sets the value of the property", std::forward<FS>(setter));
add("get." + name + " | Gets the value of the property",
[name = name, getter = std::forward<FG>(getter)] {
LOG(plog::info) << "Value of " << name << ": " << util::to_string(getter());
});
}
/// returns false if no such command could be found
static auto call(std::string_view cmd) -> bool;
static auto complete(std::string_view input) -> std::vector<Console_command*>;
static auto list_all_commands() -> const auto& { return all_commands(); }
private:
static auto all_commands() -> auto&
static auto all_commands() -> std::unordered_multimap<std::string, Console_command>&
{
static std::unordered_multimap<std::string, Console_command> cmds;
return cmds;
......@@ -88,7 +115,7 @@ namespace mirrage::util {
auto Console_command_container::add(std::string api, F&& f) -> Console_command_container&
{
static const auto split_args_regex =
std::regex(R"xxx(\"((?:[^"]|\\")+)(?!\\).\"|([^ ]+))xxx", std::regex::optimize);
std::regex(R"xxx(\"((?:[^"]|\\")+(?!\\).)\"|([^ ]+))xxx", std::regex::optimize);
auto name = api.substr(0, api.find(" "));
auto c = all_commands().emplace(
......@@ -119,7 +146,7 @@ namespace mirrage::util {
auto arg_str = std::string(arg);
util::replace_inplace(arg_str, "\\\"", "\"");
util::replace_inplace(arg_str, "\\\\", "\\");
return util::from_string<typename decltype(type)::type>(arg);
return util::from_string<typename decltype(type)::type>(arg_str);
}
}
});
......
......@@ -55,9 +55,19 @@ namespace mirrage::util {
template <class T>
inline std::string to_string(const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
if constexpr(sf2::is_json_deserializable<T>) {
auto ss = std::stringstream();
sf2::serialize_json<T>(ss, t);
return ss.str();
} else if constexpr(sf2::is_annotated_enum<T>::value) {
return sf2::get_enum_info<T>().name_of(t);
} else {
std::stringstream ss;
ss << t;
return ss.str();
}
}
template <class T>
......@@ -70,10 +80,22 @@ namespace mirrage::util {
else
return v;
} else if constexpr(sf2::is_annotated_struct<T>()) {
return sf2::deserialize_json<T>(std::stringstream(std::string(view)));
} else if constexpr(sf2::is_annotated_enum<T>()) {
} else if constexpr(sf2::is_json_deserializable<T>) {
auto ss = std::stringstream(std::string(view));
auto val = T{};
auto error = false;
sf2::deserialize_json<T>(ss,
[&](auto& msg, uint32_t row, uint32_t column) {
error = true;
LOG(plog::error)
<< "Unable to parse string \"" << view << "\". Error at "
<< row << ":" << column << ": " << msg;
},
val);
return error ? util::nothing : util::just(std::move(val));
} else if constexpr(sf2::is_annotated_enum<T>::value) {
return sf2::get_enum_info<T>().value_of(view);
} else {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment