mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-12 02:01:29 -10:00
This allows to show the debug output in a second window in real time. This system could be expanded further to allow more interactivity but the current status is good enough.
176 lines
4.6 KiB
C++
176 lines
4.6 KiB
C++
//
|
|
//
|
|
|
|
#include "DebugWindow.h"
|
|
|
|
#include "globalincs/alphacolors.h"
|
|
|
|
namespace {
|
|
uint32_t get_debug_display() {
|
|
// If there are two or more monitors then we would like to display the window on the second monitor but it shouldn't
|
|
// be shown on the same monitor that the game is running on
|
|
// If there is only then then we'll just display it on that one
|
|
auto numDisplays = SDL_GetNumVideoDisplays();
|
|
|
|
if (numDisplays < 1) {
|
|
// Some kind of error
|
|
return 0;
|
|
}
|
|
|
|
if (numDisplays == 1) {
|
|
// We only have one display
|
|
return 0;
|
|
}
|
|
auto mainDisplay = os_config_read_uint("Video", "Display", 0);
|
|
if (mainDisplay == 1) {
|
|
// Game is on the second monitor => use the primary screen
|
|
return 0;
|
|
} else {
|
|
// Use the secondary screen
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace osapi {
|
|
|
|
DebugWindow::DebugWindow() {
|
|
os::ViewPortProperties attrs;
|
|
uint32_t display = get_debug_display();
|
|
attrs.display = display;
|
|
|
|
SDL_Rect size;
|
|
SDL_GetDisplayBounds(display, &size);
|
|
attrs.width = (uint32_t) size.w;
|
|
attrs.height = (uint32_t) size.h - 40; // Reduce the height a bit to account for window decorations
|
|
|
|
attrs.title = "FreeSpace Open - Debug Window";
|
|
|
|
auto debugView = gr_create_viewport(attrs);
|
|
if (debugView) {
|
|
debug_view = os::addViewport(std::move(debugView));
|
|
}
|
|
}
|
|
|
|
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 (!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 = lines.size(); 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 width, height;
|
|
gr_get_string_size(&width, &height, line.text.c_str());
|
|
|
|
int category_width;
|
|
gr_get_string_size(&category_width, nullptr, line.category.c_str());
|
|
|
|
float y_pos = bottom_y - 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);
|
|
|
|
// We could use word wrapping here if the width if the string is too big but that's currently not a problem
|
|
gr_set_color_fast(&Color_white);
|
|
gr_string(max_category_width + 18.f, bottom_y - height, line.text.c_str(), GR_RESIZE_NONE);
|
|
|
|
return bottom_y - height;
|
|
}
|
|
|
|
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);
|
|
|
|
lines.push_back(std::move(line));
|
|
}
|
|
|
|
}
|