// // #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()(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)); } }