Files
fs2open.github.com/code/osapi/DebugWindow.cpp
T
LuytenKy e76e844d02 Vulkan: Skip MSAA resolve when no deferred pass is active (#7854)
* stub check for msaa

* initialize viewport variables
2026-10-15 18:04:32 +02:00

260 lines
6.8 KiB
C++

//
//
#include "DebugWindow.h"
#include "globalincs/alphacolors.h"
#include "osapi/osapi.h"
namespace {
SDL_DisplayID get_debug_display() {
// If we have multiple displays then try to put the debug window on the one
// that isn't used by the main game window
auto primaryDisplay = SDL_GetPrimaryDisplay();
auto gameDisplay = SDL_GetDisplayForWindow(os::getSDLMainWindow());
if (primaryDisplay != gameDisplay) {
return primaryDisplay;
}
auto debugDisplay = primaryDisplay;
auto displays = SDL_GetDisplays(nullptr);
if (displays) {
for (int i = 0; displays[i]; ++i) {
if (displays[i] != gameDisplay) {
debugDisplay = displays[i];
break;
}
}
SDL_free(displays);
}
return debugDisplay;
}
}
namespace osapi {
DebugWindow::DebugWindow() {
os::ViewPortProperties attrs = {};
uint32_t display = get_debug_display();
attrs.display = display;
SDL_Rect size;
SDL_GetDisplayBounds(display, &size);
// Make the window a bit smaller so that it doesn't take up the whole screen
attrs.width = (uint32_t) (size.w / 1.3f);
attrs.height = (uint32_t) (size.h / 1.3f);
attrs.title = "FreeSpace Open - Debug Window";
attrs.flags.set(os::ViewPortFlags::Resizeable); // Make this window resizeable
auto debugView = gr_create_viewport(attrs);
if (debugView) {
debug_view = os::addViewport(std::move(debugView));
debug_sdl_window = debug_view->toSDLWindow();
if (debug_sdl_window != nullptr) {
os::events::addEventListener(SDL_EVENT_KEY_UP,
os::events::DEFAULT_LISTENER_WEIGHT - 5,
[this](const SDL_Event& e) { return this->debug_key_handler(e); });
}
}
// try and return focus to the game window (this may be ignored by the DE)
if (debug_sdl_window != nullptr && os::getSDLMainWindow() != nullptr) {
SDL_RaiseWindow(os::getSDLMainWindow());
}
}
DebugWindow::~DebugWindow() {
}
void DebugWindow::doFrame(float) {
if (!debug_view) {
// Failed to create debug window, nothing to do here
return;
}
gr_use_viewport(debug_view);
gr_clear();
font::set_font(font::FONT1);
if (max_category_width != 0) {
// Draw a line to separate the category from the text
auto x_pos = max_category_width + 14;
gr_set_color_fast(&Color_grey);
gr_line(x_pos, 0, x_pos, gr_screen.max_h, GR_RESIZE_NONE);
}
// Print the saved debug log lines from the bottom up
float current_y = i2fl(gr_screen.max_h - 10);
// If the current view offset is at the end of the list then we also need to display the line that is currently being constructed
if (log_view_offset == lines.size() - 1) {
if (!current_line.empty()) {
LineInfo info;
info.text = current_line;
info.category = current_category;
current_y = print_line(current_y, info);
}
}
// Now print all the stored lines
// Backwards iteration of the vector comes from here: http://stackoverflow.com/a/4206815
for (auto i = log_view_offset + 1; i-- > 0;) {
auto& line = lines[i];
current_y = print_line(current_y, line);
if (current_y < 0.f) {
// End to iteration if the rendered string would be invisible
break;
}
}
// Don't run scripting here
gr_flip(false);
gr_use_viewport(os::getMainViewport());
}
float DebugWindow::print_line(float bottom_y, const LineInfo& line) {
int category_width;
gr_get_string_size(&category_width, nullptr, line.category.c_str());
// Wrap the string to make sure everything can be read
SCP_vector<const char*> split_lines;
SCP_vector<int> line_lengths;
// Substract 40 so that we can have margins on both sides
// Make sure that the width doesn't go too low or else split_str will not be able to fit enough characters in one line
auto max_w = std::max(40, gr_screen.max_w - max_category_width - 40);
split_str(line.text.c_str(), max_w, line_lengths, split_lines);
auto text_height = split_lines.size() * font::get_current_font()->getHeight();
float y_pos = bottom_y - text_height;
float cat_x_pos = max_category_width - category_width + 10.f;
// Give each category a unique color. We do this by hashing the string and using that to construct the RGB values
auto hash = std::hash<SCP_string>()(line.category);
gr_set_color((int) (hash & 0xFF), (int) ((hash & 0xFF00) >> 8), (int) ((hash & 0xFF0000) >> 16));
gr_string(cat_x_pos, y_pos, line.category.c_str(), GR_RESIZE_NONE);
gr_set_color_fast(&Color_white);
for (size_t i = 0; i < split_lines.size(); ++i) {
gr_string(max_category_width + 18.f, y_pos, split_lines[i], GR_RESIZE_NONE, 1.0f, static_cast<size_t>(line_lengths[i]));
y_pos += font::get_current_font()->getHeight();
}
return bottom_y - text_height;
}
bool DebugWindow::debug_key_handler(const SDL_Event& evt) {
if (!os::events::isWindowEvent(evt, debug_sdl_window)) {
// Event belongs to another window
return false;
}
ptrdiff_t diff = 0;
switch(evt.key.key) {
case SDLK_DOWN:
diff = 1;
break;
case SDLK_UP:
diff = -1;
break;
case SDLK_PAGEDOWN:
diff = 60; // It's not actually a page but this should still work
break;
case SDLK_PAGEUP:
diff = -60;
break;
case SDLK_END:
log_view_offset = lines.size() - 1;
return true;
case SDLK_HOME:
log_view_offset = 0;
return true;
default:
return true;
}
auto prev = log_view_offset;
log_view_offset += diff;
if (diff < 0 && log_view_offset > prev) {
// We had an overflow of the counter
log_view_offset = 0;
}
log_view_offset = std::min(log_view_offset, lines.size() - 1);
return true;
}
void DebugWindow::addDebugMessage(const char* category, const char* text) {
if (!debug_view) {
// Failed to create debug window, nothing to do here
return;
}
if (category != current_category) {
// There is a new category so we need to write the old string to our log
// Find finished lines and add them to our vector
split_current_and_add_to_log(category);
if (!current_line.empty()) {
// Write the last line to our log
LineInfo info;
info.text = current_line;
info.category = category;
addToLog(std::move(info));
current_line.clear();
}
}
current_category = category;
current_line += text;
split_current_and_add_to_log(category);
}
void DebugWindow::split_current_and_add_to_log(const SCP_string& category) {
size_t pos;
while ((pos = current_line.find('\n')) != SCP_string::npos) {
LineInfo info;
info.text = current_line.substr(0, pos);
info.category = category;
addToLog(std::move(info));
// Since pos refers to a valid position in the string, the expression pos + 1 is always valid since substr
// allows values up to str.size()
current_line = current_line.substr(pos + 1);
}
}
void DebugWindow::addToLog(LineInfo&& line) {
int cat_width;
gr_get_string_size(&cat_width, nullptr, line.category.c_str());
max_category_width = std::max(cat_width, max_category_width);
if (log_view_offset == lines.size() - 1) {
// We are currently showing the last line so we need to follow new entries
++log_view_offset;
}
lines.push_back(std::move(line));
}
}