Screenshot functionality Added

Added a screenshot functionality based on this pr https://github.com/xenia-project/xenia/pull/2074 and added some minor adjustments.

GUI wise, "take screenshot" is under the Display menu and the keyboard shortcut to take it is F10

The screenshots folder will save to where xenia.exe or xenia_canary.exe is located. As for save paths, it will only use the id of the game due to illegal characters in some titles.
This commit is contained in:
Vonce 2024-06-17 00:18:22 -07:00 committed by Radosław Gliński
parent 34322ebb41
commit e4408b6bc3
2 changed files with 79 additions and 0 deletions

View File

@ -17,8 +17,10 @@
#include <utility> #include <utility>
#include "third_party/cpptoml/include/cpptoml.h" #include "third_party/cpptoml/include/cpptoml.h"
#include "third_party/fmt/include/fmt/chrono.h"
#include "third_party/fmt/include/fmt/format.h" #include "third_party/fmt/include/fmt/format.h"
#include "third_party/imgui/imgui.h" #include "third_party/imgui/imgui.h"
#include "third_party/stb/stb_image_write.h"
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
#include "xenia/base/clock.h" #include "xenia/base/clock.h"
#include "xenia/base/cvar.h" #include "xenia/base/cvar.h"
@ -649,6 +651,9 @@ bool EmulatorWindow::Initialize() {
display_menu->AddChild( display_menu->AddChild(
MenuItem::Create(MenuItem::Type::kString, "&Fullscreen", "F11", MenuItem::Create(MenuItem::Type::kString, "&Fullscreen", "F11",
std::bind(&EmulatorWindow::ToggleFullscreen, this))); std::bind(&EmulatorWindow::ToggleFullscreen, this)));
display_menu->AddChild(
MenuItem::Create(MenuItem::Type::kString, "&Take Screenshot", "F10",
std::bind(&EmulatorWindow::TakeScreenshot, this)));
} }
main_menu->AddChild(std::move(display_menu)); main_menu->AddChild(std::move(display_menu));
@ -833,6 +838,10 @@ void EmulatorWindow::OnKeyDown(ui::KeyEvent& e) {
case ui::VirtualKey::kF11: { case ui::VirtualKey::kF11: {
ToggleFullscreen(); ToggleFullscreen();
} break; } break;
case ui::VirtualKey::kF10: {
TakeScreenshot();
} break;
case ui::VirtualKey::kEscape: { case ui::VirtualKey::kEscape: {
// Allow users to escape fullscreen (but not enter it). // Allow users to escape fullscreen (but not enter it).
if (!window_->IsFullscreen()) { if (!window_->IsFullscreen()) {
@ -890,6 +899,71 @@ void EmulatorWindow::OnMouseUp(const ui::MouseEvent& e) {
last_mouse_up = steady_clock::now(); last_mouse_up = steady_clock::now();
} }
void EmulatorWindow::TakeScreenshot() {
xe::ui::RawImage image;
if (!GetGraphicsSystemPresenter()->CaptureGuestOutput(image) ||
GetGraphicsSystemPresenter() == nullptr) {
XELOGE("Failed to capture guest output for screenshot");
return;
}
ExportScreenshot(image);
}
void EmulatorWindow::ExportScreenshot(const xe::ui::RawImage& image) {
auto t = std::time(nullptr);
// The format is: Year-Month-DayTHours-Minutes-Seconds based off ISO 8601
std::string datetime = fmt::format("{:%Y-%m-%dT%H-%M-%S}", fmt::localtime(t));
// Get the title id of the game because some titles contain characters that
// cannot be used as a directory
std::string title_id;
if (emulator()->title_id()) {
title_id = fmt::format("{:08X}", emulator()->title_id());
} else {
XELOGE("Failed to get the current title id");
return;
}
// Find where xenia.exe or xenia_canary.exe is located and create a
// screenshots folder
auto screenshot_path =
(xe::filesystem::GetExecutableFolder() / "screenshots" / title_id);
if (!std::filesystem::exists(screenshot_path)) {
std::filesystem::create_directories(screenshot_path);
}
std::string filename = fmt::format("{} - {}.png", title_id, datetime);
SaveImage(screenshot_path / filename, image);
xe::ui::ImGuiDialog::ShowMessageBox(
imgui_drawer_.get(), "Screenshot saved",
fmt::format("Screenshot saved to {}", xe::path_to_utf8(screenshot_path)));
}
// Converts a RawImage into a PNG file
void EmulatorWindow::SaveImage(const std::filesystem::path& filepath,
const xe::ui::RawImage& image) {
auto file = std::ofstream(filepath, std::ios::binary);
if (!file.is_open()) {
XELOGE("Failed to open file for writing: {}", xe::path_to_utf8(filepath));
return;
}
auto result = stbi_write_png_to_func(
[](void* context, void* data, int size) {
auto file = reinterpret_cast<std::ofstream*>(context);
file->write(reinterpret_cast<const char*>(data), size);
},
&file, image.width, image.height, 4, image.data.data(),
(int)image.stride);
if (result == 0) {
XELOGE("Failed to write PNG to file: {}", xe::path_to_utf8(filepath));
return;
}
}
void EmulatorWindow::ToggleFullscreenOnDoubleClick() { void EmulatorWindow::ToggleFullscreenOnDoubleClick() {
// this function tests if user has double clicked. // this function tests if user has double clicked.
// if double click was achieved the fullscreen gets toggled // if double click was achieved the fullscreen gets toggled

View File

@ -87,6 +87,11 @@ class EmulatorWindow {
void ToggleFullscreen(); void ToggleFullscreen();
void SetInitializingShaderStorage(bool initializing); void SetInitializingShaderStorage(bool initializing);
void TakeScreenshot();
void ExportScreenshot(const xe::ui::RawImage& image);
void SaveImage(const std::filesystem::path& path,
const xe::ui::RawImage& image);
// Types of button functions for hotkeys. // Types of button functions for hotkeys.
enum class ButtonFunctions { enum class ButtonFunctions {
ToggleFullscreen, ToggleFullscreen,