game/debugging: Add a new imgui menu to filter debug text and adjust imgui config settings (#2085)

This adds a new ImGUI menu to help filter out the clutter on screen.


https://user-images.githubusercontent.com/13153231/210192912-b1c28319-bacb-449c-ad7f-e7308fb75f50.mp4

This also:
- moves the imgui display bool into a game specific config file (you can
hide it in jak1, and not in jak2)
- the config file also persists the settings from this menu (except the
filters for now, future TODO)
- there is a new `ignore_imgui_hide_keybind` in this file to ignore
hiding it when you press Alt
This commit is contained in:
Tyler Wilding
2023-01-02 09:45:38 -05:00
committed by GitHub
parent bb94c84d4b
commit 9f53edae7a
20 changed files with 257 additions and 46 deletions
+16
View File
@@ -1,9 +1,15 @@
#include "StringUtil.h"
#include <regex>
namespace str_util {
const std::string WHITESPACE = " \n\r\t\f\v";
bool contains(const std::string& s, const std::string& substr) {
return s.find(substr) != std::string::npos;
}
bool starts_with(const std::string& s, const std::string& prefix) {
return s.rfind(prefix) == 0;
}
@@ -31,4 +37,14 @@ int line_count(const std::string& str) {
}
return result;
}
// NOTE - this won't work running within gk.exe!
bool valid_regex(const std::string& regex) {
try {
std::regex re(regex);
} catch (const std::regex_error& e) {
return false;
}
return true;
}
} // namespace str_util
+2
View File
@@ -1,9 +1,11 @@
#include <string>
namespace str_util {
bool contains(const std::string& s, const std::string& substr);
bool starts_with(const std::string& s, const std::string& prefix);
std::string ltrim(const std::string& s);
std::string rtrim(const std::string& s);
std::string trim(const std::string& s);
int line_count(const std::string& str);
bool valid_regex(const std::string& regex);
} // namespace str_util
@@ -650,7 +650,5 @@
[1, "(function float)"],
[3, "(function none :behavior scene-player)"]
],
"collectables": [
[69, "(function part-tracker vector)"]
]
"collectables": [[69, "(function part-tracker vector)"]]
}
+5 -13
View File
@@ -5474,7 +5474,7 @@
[19, "a0", "int"],
[23, "a0", "int"],
[155, "v1", "process-drawable"]
],
],
"(anon-function 69 collectables)": [
//[[1, 6], "v1", "handle"],
[2, "v1", "handle"],
@@ -5483,12 +5483,8 @@
[13, "v1", "collectable"],
[[34, 39], "a0", "process-focusable"]
],
"check-blue-suck": [
[19, "v1", "collide-shape"]
],
"add-blue-motion": [
[27, "s2", "process-focusable"]
],
"check-blue-suck": [[19, "v1", "collide-shape"]],
"add-blue-motion": [[27, "s2", "process-focusable"]],
"collectable-standard-event-handler": [
[84, "a0", "vector"],
[102, "a0", "vector"],
@@ -5499,16 +5495,12 @@
[17, "a0", "vector"],
[18, "v1", "vector"]
],
"(code die eco)": [
[55, "v1", "float"]
],
"(code die eco)": [[55, "v1", "float"]],
"(code pickup eco)": [
[39, "v0", "state"],
[41, "t9", "(function none)"]
],
"(method 10 gem)": [
[12, "t9", "(function gem none)"]
],
"(method 10 gem)": [[12, "t9", "(function gem none)"]],
"(method 9 fact-info)": [
[245, "a0", "process-drawable"],
[293, "a0", "process-drawable"]
+3 -2
View File
@@ -167,7 +167,8 @@ set(RUNTIME_SOURCE
graphics/pipelines/opengl.cpp
system/vm/dmac.cpp
system/vm/vm.cpp
tools/subtitles/subtitle_editor.cpp)
tools/subtitles/subtitle_editor.cpp
tools/filter_menu/filter_menu.cpp)
find_package(Git)
@@ -212,5 +213,5 @@ else()
target_link_libraries(runtime pthread dl)
endif()
add_executable(gk main.cpp)
add_executable(gk main.cpp "tools/filter_menu/filter_menu.cpp" "tools/filter_menu/filter_menu.h")
target_link_libraries(gk runtime)
+5 -1
View File
@@ -80,7 +80,11 @@ class GfxDisplay {
GfxDisplayMode last_fullscreen_mode() const { return m_last_fullscreen_mode; }
GfxDisplayMode fullscreen_mode() { return m_fullscreen_mode; }
int fullscreen_screen() const { return m_fullscreen_screen; }
void set_imgui_visible(bool visible) { m_imgui_visible = visible; }
void set_imgui_visible(bool visible) {
m_imgui_visible = visible;
Gfx::g_debug_settings.show_imgui = visible;
Gfx::g_debug_settings.save_settings();
}
bool is_imgui_visible() const { return m_imgui_visible; }
bool windowed() { return fullscreen_mode() == GfxDisplayMode::Windowed; }
+54 -17
View File
@@ -54,6 +54,40 @@ namespace Gfx {
std::function<void()> vsync_callback;
GfxGlobalSettings g_global_settings;
GfxSettings g_settings;
DebugSettings g_debug_settings;
void DebugSettings::load_settings(const ghc::filesystem::path& filepath) {
auto file_txt = file_util::read_text_file(filepath);
auto json = parse_commented_json(file_txt, filepath.string());
if (json.contains("show_imgui")) {
show_imgui = json["show_imgui"].get<bool>();
}
if (json.contains("ignore_imgui_hide_keybind")) {
ignore_imgui_hide_keybind = json["ignore_imgui_hide_keybind"].get<bool>();
}
if (json.contains("debug_text_check_range")) {
debug_text_check_range = json["debug_text_check_range"].get<bool>();
}
if (json.contains("debug_text_max_range")) {
debug_text_max_range = json["debug_text_max_range"].get<float>();
}
// TODO - not loading filters because they aren't being persisted
}
void DebugSettings::save_settings() {
nlohmann::json json;
json["show_imgui"] = show_imgui;
json["ignore_imgui_hide_keybind"] = ignore_imgui_hide_keybind;
json["debug_text_check_range"] = debug_text_check_range;
json["debug_text_max_range"] = debug_text_max_range;
// TODO - persist the filters as well, not doing it yet because i havn't added a way to remove em
// via the UI
auto debug_settings_filename =
file_util::get_user_misc_dir(g_game_version) / "debug-settings.json";
file_util::create_dir_if_needed_for_file(debug_settings_filename);
file_util::write_text_file(debug_settings_filename, json.dump(2));
}
Pad::MappingInfo& get_button_mapping() {
return g_settings.pad_mapping_info;
@@ -84,15 +118,8 @@ const std::pair<std::string, Pad::Analog> analog_map[] = {
{"Right Y Axis", Pad::Analog::Right_Y},
};
bool g_is_debug_menu_visible_on_startup = false;
bool get_debug_menu_visible_on_startup() {
return g_is_debug_menu_visible_on_startup;
}
void DumpToJson(ghc::filesystem::path& filename) {
nlohmann::json json;
json["Debug Menu Visibility"] = false; // Assume start up debug display is disabled
auto& peripherals_json = json["Peripherals"];
json["Use Mouse"] = g_settings.pad_mapping_info.use_mouse;
@@ -152,10 +179,6 @@ void LoadPeripheralSettings(const ghc::filesystem::path& filepath) {
auto file_txt = file_util::read_text_file(filepath);
auto configuration = parse_commented_json(file_txt, filepath.string());
if (configuration.find("Debug Menu Visibility") != configuration.end()) {
g_is_debug_menu_visible_on_startup = configuration["Debug Menu Visibility"].get<bool>();
}
if (configuration.find("Use Mouse") != configuration.end()) {
g_settings.pad_mapping_info.use_mouse = configuration["Use Mouse"].get<bool>();
}
@@ -224,14 +247,28 @@ void LoadPeripheralSettings(const ghc::filesystem::path& filepath) {
}
void LoadSettings() {
auto filename = (file_util::get_user_config_dir() / "controller" / "controller-settings.json");
if (fs::exists(filename)) {
LoadPeripheralSettings(filename);
lg::info("Loaded graphics configuration file.");
return;
// load controller settings
// TODO - make this game specific as well
auto controller_settings_filename =
file_util::get_user_config_dir() / "controller" / "controller-settings.json";
if (fs::exists(controller_settings_filename)) {
LoadPeripheralSettings(controller_settings_filename);
lg::info("Loaded controller configuration file.");
} else {
SavePeripheralSettings();
lg::info("Couldn't find controller-settings.json creating new controller settings file.");
lg::info(
"Couldn't find $USER/controller/controller-settings.json creating new controller settings "
"file.");
}
// load debug settings
auto debug_settings_filename =
file_util::get_user_misc_dir(g_game_version) / "debug-settings.json";
if (fs::exists(debug_settings_filename)) {
g_debug_settings.load_settings(debug_settings_filename);
lg::info("Loaded debug settings file.");
} else {
lg::info("Couldn't find $USER/misc/debug-settings.json creating new controller settings file.");
g_debug_settings.save_settings();
}
}
+15 -1
View File
@@ -10,10 +10,12 @@
#include <memory>
#include "common/common_types.h"
#include "common/util/FileUtil.h"
#include "common/versions.h"
#include "game/kernel/common/kboot.h"
#include "game/system/newpad.h"
#include "game/tools/filter_menu/filter_menu.h"
// forward declarations
struct GfxSettings;
@@ -122,6 +124,19 @@ namespace Gfx {
extern GfxGlobalSettings g_global_settings;
extern GfxSettings g_settings;
struct DebugSettings {
bool show_imgui = false;
bool ignore_imgui_hide_keybind = false;
std::vector<DebugTextFilter> debug_text_filters = {};
bool debug_text_check_range = false;
float debug_text_max_range = 0;
void load_settings(const ghc::filesystem::path& filepath);
void save_settings();
};
extern DebugSettings g_debug_settings;
const GfxRendererModule* GetCurrentRenderer();
u32 Init(GameVersion version);
@@ -159,7 +174,6 @@ void set_msaa(int samples);
void input_mode_set(u32 enable);
void input_mode_save();
s64 get_mapped_button(s64 pad, s64 button);
bool get_debug_menu_visible_on_startup();
int PadIsPressed(Pad::Button button, int port);
int PadGetAnalogValue(Pad::Analog analog, int port);
@@ -543,6 +543,10 @@ void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) {
m_subtitle_editor.draw_window();
}
if (settings.draw_filters_window) {
m_filters_menu.draw_window();
}
if (settings.save_screenshot) {
Fbo* screenshot_src;
int read_buffer;
@@ -10,6 +10,7 @@
#include "game/graphics/opengl_renderer/Profiler.h"
#include "game/graphics/opengl_renderer/Shader.h"
#include "game/graphics/opengl_renderer/opengl_utils.h"
#include "game/tools/filter_menu/filter_menu.h"
#include "game/tools/subtitles/subtitle_editor.h"
struct RenderOptions {
@@ -17,6 +18,7 @@ struct RenderOptions {
bool draw_profiler_window = false;
bool draw_small_profiler_window = false;
bool draw_subtitle_editor_window = false;
bool draw_filters_window = false;
// internal rendering settings - The OpenGLRenderer will internally use this resolution/format.
int msaa_samples = 4;
@@ -136,6 +138,7 @@ class OpenGLRenderer {
Profiler m_profiler;
SmallProfiler m_small_profiler;
SubtitleEditor m_subtitle_editor;
FiltersMenu m_filters_menu;
std::vector<std::unique_ptr<BucketRenderer>> m_bucket_renderers;
std::vector<BucketCategory> m_bucket_categories;
+1 -4
View File
@@ -104,6 +104,7 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) {
if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Subtitle Editor", nullptr, &m_subtitle_editor);
ImGui::MenuItem("Filters", nullptr, &m_filters_menu);
ImGui::EndMenu();
}
@@ -141,10 +142,6 @@ void OpenGlDebugGui::draw(const DmaStats& dma_stats) {
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu(fmt::format("WORK IN PROGRESS VERSION ({})!", GIT_VERSION).c_str())) {
ImGui::EndMenu();
}
}
ImGui::EndMainMenuBar();
@@ -45,6 +45,7 @@ class OpenGlDebugGui {
bool should_draw_render_debug() const { return m_draw_debug; }
bool should_draw_profiler() const { return m_draw_profiler; }
bool should_draw_subtitle_editor() const { return m_subtitle_editor; }
bool should_draw_filters_menu() const { return m_filters_menu; }
const char* screenshot_name() const { return m_screenshot_save_name; }
bool should_advance_frame() { return m_frame_timer.should_advance_frame(); }
@@ -74,6 +75,7 @@ class OpenGlDebugGui {
bool m_draw_profiler = false;
bool m_draw_debug = false;
bool m_subtitle_editor = false;
bool m_filters_menu = false;
bool m_want_screenshot = false;
char m_screenshot_save_name[256] = "screenshot.png";
float target_fps_input = 60.f;
+4 -2
View File
@@ -216,7 +216,7 @@ static std::shared_ptr<GfxDisplay> gl_make_display(int width,
}
auto display = std::make_shared<GLDisplay>(window, is_main);
display->set_imgui_visible(Gfx::get_debug_menu_visible_on_startup());
display->set_imgui_visible(Gfx::g_debug_settings.show_imgui);
display->update_cursor_visibility(window, display->is_imgui_visible());
// lg::debug("init display #x{:x}", (uintptr_t)display);
@@ -326,7 +326,8 @@ void GLDisplay::on_key(GLFWwindow* window, int key, int /*scancode*/, int action
switch (key) {
case GLFW_KEY_LEFT_ALT:
case GLFW_KEY_RIGHT_ALT:
if (glfwGetWindowAttrib(window, GLFW_FOCUSED)) {
if (glfwGetWindowAttrib(window, GLFW_FOCUSED) &&
!Gfx::g_debug_settings.ignore_imgui_hide_keybind) {
set_imgui_visible(!is_imgui_visible());
update_cursor_visibility(window, is_imgui_visible());
}
@@ -459,6 +460,7 @@ void render_game_frame(int game_width,
options.draw_render_debug_window = g_gfx_data->debug_gui.should_draw_render_debug();
options.draw_profiler_window = g_gfx_data->debug_gui.should_draw_profiler();
options.draw_subtitle_editor_window = g_gfx_data->debug_gui.should_draw_subtitle_editor();
options.draw_filters_window = g_gfx_data->debug_gui.should_draw_filters_menu();
options.save_screenshot = false;
options.gpu_sync = g_gfx_data->debug_gui.should_gl_finish();
options.borderless_windows_hacks = windows_borderless_hack;
+41 -1
View File
@@ -4,6 +4,7 @@
#include "common/log/log.h"
#include "common/symbols.h"
#include "common/util/FileUtil.h"
#include "common/util/StringUtil.h"
#include "common/util/Timer.h"
#include "game/graphics/gfx.h"
@@ -530,4 +531,43 @@ void pc_texture_upload_now(u32 page, u32 mode) {
void pc_texture_relocate(u32 dst, u32 src, u32 format) {
Gfx::texture_relocate(dst, src, format);
}
}
u64 pc_filter_debug_string(u32 str_ptr, u32 dist_ptr) {
auto str = std::string(Ptr<String>(str_ptr).c()->data());
float dist;
memcpy(&dist, &dist_ptr, 4);
// Check distance first
if (Gfx::g_debug_settings.debug_text_check_range) {
if (dist / 4096.0 > Gfx::g_debug_settings.debug_text_max_range) {
return s7.offset + true_symbol_offset(g_game_version);
}
}
// Get the current filters
const auto& filters = Gfx::g_debug_settings.debug_text_filters;
if (filters.empty()) {
// there are no filters, exit early
return s7.offset;
}
// Currently very dumb contains check
for (const auto& filter : filters) {
if (filter.type == DebugTextFilter::Type::CONTAINS) {
if (!str.empty() && !filter.content.empty() && !str_util::contains(str, filter.content)) {
return s7.offset + true_symbol_offset(g_game_version);
}
} else if (filter.type == DebugTextFilter::Type::NOT_CONTAINS) {
if (!str.empty() && !filter.content.empty() && str_util::contains(str, filter.content)) {
return s7.offset + true_symbol_offset(g_game_version);
}
} else if (filter.type == DebugTextFilter::Type::REGEX) {
if (str_util::valid_regex(filter.content) &&
std::regex_match(str, std::regex(filter.content))) {
return s7.offset + true_symbol_offset(g_game_version);
}
}
}
return s7.offset;
}
+2 -1
View File
@@ -82,4 +82,5 @@ void vif_interrupt_callback(int bucket_id);
u64 pc_get_mips2c(u32 name);
void send_gfx_dma_chain(u32 /*bank*/, u32 chain);
void pc_texture_upload_now(u32 page, u32 mode);
void pc_texture_relocate(u32 dst, u32 src, u32 format);
void pc_texture_relocate(u32 dst, u32 src, u32 format);
u64 pc_filter_debug_string(u32 str_ptr, u32 distance);
+3
View File
@@ -556,6 +556,9 @@ void InitMachine_PCPort() {
// profiler
make_function_symbol_from_c("pc-prof", (void*)prof_event);
// debugging tools
make_function_symbol_from_c("pc-filter-debug-string?", (void*)pc_filter_debug_string);
// init ps2 VM
if (VM::use) {
make_function_symbol_from_c("vm-ptr", (void*)VM::get_vm_ptr);
+71
View File
@@ -0,0 +1,71 @@
#include "filter_menu.h"
#include "game/graphics/gfx.h"
#include "third-party/fmt/core.h"
#include "third-party/imgui/imgui.h"
#include "third-party/imgui/imgui_stdlib.h"
// TODO:
// - persist filters (need ability to remove option too)
FiltersMenu::FiltersMenu() {}
void FiltersMenu::draw_window() {
ImGui::Begin("Filters");
ImGui::SetNextItemOpen(true);
if (ImGui::TreeNode("Debug Text Filters")) {
auto& current_filters = Gfx::g_debug_settings.debug_text_filters;
// Iterate and display all current debug text filters
for (int i = 0; i < current_filters.size(); i++) {
std::string label = "contains?";
if (current_filters[i].type == DebugTextFilter::Type::NOT_CONTAINS) {
label = "not-contains?";
} else if (current_filters[i].type == DebugTextFilter::Type::REGEX) {
label = "regex?";
}
ImGui::Text(label.c_str());
ImGui::SameLine();
ImGui::InputText(fmt::format("##filter-{}", i).c_str(), &current_filters[i].content);
}
if (ImGui::Button("Add Contains")) {
DebugTextFilter new_filter;
new_filter.type = DebugTextFilter::Type::CONTAINS;
current_filters.push_back(new_filter);
}
ImGui::SameLine();
if (ImGui::Button("Add Not-Contains")) {
DebugTextFilter new_filter;
new_filter.type = DebugTextFilter::Type::NOT_CONTAINS;
current_filters.push_back(new_filter);
}
if (ImGui::Button("Clear Filters")) {
current_filters.clear();
}
// TODO - can't use regexes because i can't check it it's a valid regex without using a
// try-catch and this has issues running within gk
//
// An option is to bring in boost's regex lib
/*ImGui::SameLine();
if (ImGui::Button("Add Regex")) {
DebugTextFilter new_filter;
new_filter.type = DebugTextFilter::Type::REGEX;
current_filters.push_back(new_filter);
}*/
if (ImGui::Checkbox("Enable Distance Check", &Gfx::g_debug_settings.debug_text_check_range)) {
Gfx::g_debug_settings.save_settings();
}
if (Gfx::g_debug_settings.debug_text_check_range) {
if (ImGui::SliderFloat("Max Range", &Gfx::g_debug_settings.debug_text_max_range, 0, 250)) {
Gfx::g_debug_settings.save_settings();
}
}
ImGui::TreePop();
}
ImGui::End();
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <optional>
#include <string>
#include "third-party/imgui/imgui.h"
struct DebugTextFilter {
enum class Type { CONTAINS, NOT_CONTAINS, REGEX };
std::string content;
Type type;
};
class FiltersMenu {
public:
FiltersMenu();
void draw_window();
};
+5
View File
@@ -884,6 +884,11 @@
)
"Draw text at the given point. screen-offset can be #f."
(when enable
(#when PC_PORT
;; Check to see if the string should be filtered or not
(when (pc-filter-debug-string? text (vector-vector-distance position (target-pos 0)))
;; no-op the function!
(return #f)))
(cond
(*debug-draw-pauseable*
(let ((v1-2 (get-debug-text-3d)))
+1 -1
View File
@@ -218,4 +218,4 @@
)
(define-extern pc-prof (function string pc-prof-event none))
(define-extern pc-filter-debug-string? (function string float symbol))