diff --git a/pcsx2-qt/Settings/FolderSettingsWidget.cpp b/pcsx2-qt/Settings/FolderSettingsWidget.cpp index 902919c9b0..b6c0860a66 100644 --- a/pcsx2-qt/Settings/FolderSettingsWidget.cpp +++ b/pcsx2-qt/Settings/FolderSettingsWidget.cpp @@ -2,12 +2,9 @@ // SPDX-License-Identifier: GPL-3.0+ #include "FolderSettingsWidget.h" -#include "pcsx2/GS/GS.h" #include "SettingWidgetBinder.h" #include "SettingsWindow.h" -#include - FolderSettingsWidget::FolderSettingsWidget(SettingsWindow* settings_dialog, QWidget* parent) : SettingsWidget(settings_dialog, parent) { @@ -20,12 +17,15 @@ FolderSettingsWidget::FolderSettingsWidget(SettingsWindow* settings_dialog, QWid SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.covers, m_ui.coversBrowse, m_ui.coversOpen, m_ui.coversReset, "Folders", "Covers", Path::Combine(EmuFolders::DataRoot, "covers")); SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.snapshots, m_ui.snapshotsBrowse, m_ui.snapshotsOpen, m_ui.snapshotsReset, "Folders", "Snapshots", Path::Combine(EmuFolders::DataRoot, "snaps")); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.organizeSnapshotsByGame, "EmuCore/GS", "OrganizeScreenshotsByGame", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.organizeVideoDumpByGame, "EmuCore/GS", "OrganizeVideoCaptureByGame", false); SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.saveStates, m_ui.saveStatesBrowse, m_ui.saveStatesOpen, m_ui.saveStatesReset, "Folders", "SaveStates", Path::Combine(EmuFolders::DataRoot, "sstates")); SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.videoDumpingDirectory, m_ui.videoDumpingDirectoryBrowse, m_ui.videoDumpingDirectoryOpen, m_ui.videoDumpingDirectoryReset, "Folders", "Videos", Path::Combine(EmuFolders::DataRoot, "videos")); dialog()->registerWidgetHelp(m_ui.organizeSnapshotsByGame, tr("Organize Snapshots by Game"), tr("Unchecked"), tr("Saves snapshots to per-game subfolders instead of a shared folder.")); + dialog()->registerWidgetHelp(m_ui.organizeVideoDumpByGame, tr("Organize Video Recordings by Game"), tr("Unchecked"), + tr("Saves video recordings to per-game subfolders instead of a shared folder.")); } FolderSettingsWidget::~FolderSettingsWidget() = default; diff --git a/pcsx2-qt/Settings/FolderSettingsWidget.ui b/pcsx2-qt/Settings/FolderSettingsWidget.ui index 58de409046..d96bfe8aa8 100644 --- a/pcsx2-qt/Settings/FolderSettingsWidget.ui +++ b/pcsx2-qt/Settings/FolderSettingsWidget.ui @@ -46,12 +46,12 @@ Used for storing shaders, game list, and achievement data. + + Qt::TextInteractionFlag::TextBrowserInteraction + cache - - Qt::TextBrowserInteraction - @@ -92,12 +92,12 @@ Used for storing .pnach files containing game cheats. + + Qt::TextInteractionFlag::TextBrowserInteraction + cheats - - Qt::TextBrowserInteraction - @@ -139,7 +139,7 @@ Used for saving screenshots and GS dumps. - Qt::TextBrowserInteraction + Qt::TextInteractionFlag::TextBrowserInteraction snapshots @@ -167,12 +167,12 @@ Used for storing save states. + + Qt::TextInteractionFlag::TextBrowserInteraction + saveStates - - Qt::TextBrowserInteraction - @@ -237,12 +237,12 @@ Used for storing covers in the game grid/Big Picture UIs. + + Qt::TextInteractionFlag::TextBrowserInteraction + covers - - Qt::TextBrowserInteraction - @@ -251,7 +251,7 @@ - Video Dumping Directory + Video Recording Directory @@ -271,6 +271,19 @@ + + + + Used for storing video recordings. + + + Qt::TextInteractionFlag::TextBrowserInteraction + + + videoDumpingDirectory + + + @@ -278,16 +291,10 @@ - - + + - Used for storing video captures. - - - videoDumpingDirectory - - - Qt::TextBrowserInteraction + Save Video Recording in Game-Specific Folders diff --git a/pcsx2/Config.h b/pcsx2/Config.h index c17cc9e4e4..b7a84a8472 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -830,7 +830,8 @@ struct Pcsx2Config VideoCaptureAutoResolution : 1, EnableAudioCapture : 1, EnableAudioCaptureParameters : 1, - OrganizeSnapshotsByGame : 1; + OrganizeSnapshotsByGame : 1, + OrganizeVideoCaptureByGame : 1; }; }; diff --git a/pcsx2/GS/Renderers/Common/GSRenderer.cpp b/pcsx2/GS/Renderers/Common/GSRenderer.cpp index 0eefbbdb2e..5993ccfe45 100644 --- a/pcsx2/GS/Renderers/Common/GSRenderer.cpp +++ b/pcsx2/GS/Renderers/Common/GSRenderer.cpp @@ -112,12 +112,12 @@ bool GSRenderer::Merge(int field) (!(m_regs->PMODE.MMOD == 1 && m_regs->PMODE.ALP == 0) || // Blend RC1 with non-zero alpha. (m_regs->PMODE.AMOD == 0) || // Use alpha of RC1. (feedback_merge && m_regs->EXTBUF.FBIN == 0)); // Use RC1 for feedback merge. - + // The following two flags determine if RC1 output completely overwrites RC2 output // due to the alpha used for blending and the respective rectangles of the outputs. const bool rc1_contains_rc2 = PCRTCDisplays.PCRTCDisplays[0].displayRect.rcontains(PCRTCDisplays.PCRTCDisplays[1].displayRect); - + const bool rc1_overwrites_rc2 = use_rc1 && rc1_contains_rc2 && m_regs->PMODE.MMOD == 1 && m_regs->PMODE.ALP == 255; const bool use_rc2 = @@ -184,7 +184,7 @@ bool GSRenderer::Merge(int field) // src_gs_read is the size which we're really reading from GS memory. src_gs_read[i] = ((GSVector4(curCircuit.framebufferRect) + GSVector4(0, y_offset[i], 0, y_offset[i])) * scale) / GSVector4(tex[i]->GetSize()).xyxy(); - + float interlace_offset = 0.0f; if (isReallyInterlaced() && m_regs->SMODE2.FFMD && !is_bob && !GSConfig.DisableInterlaceOffset && GSConfig.InterlaceMode != GSInterlaceMode::Off) { @@ -194,7 +194,7 @@ bool GSRenderer::Merge(int field) if (m_scanmask_used) { int displayIntOffset = PCRTCDisplays.PCRTCDisplays[i].displayRect.y - PCRTCDisplays.PCRTCDisplays[1 - i].displayRect.y; - + if (displayIntOffset > 0) { displayIntOffset &= 1; @@ -908,7 +908,8 @@ std::string GSGetBaseSnapshotFilename() // If organize by game is enabled, use or create a game-specific folder. if (GSConfig.OrganizeSnapshotsByGame) { - std::string game_name = VMManager::GetTitle(true); + const bool prefer_english = Host::GetBaseBoolSettingValue("UI", "PreferEnglishGameList", false); + std::string game_name = VMManager::GetTitle(prefer_english); if (!game_name.empty()) { Path::SanitizeFileName(&game_name); @@ -925,6 +926,21 @@ std::string GSGetBaseSnapshotFilename() std::string GSGetBaseVideoFilename() { + // If organize by game is enabled, use or create a game-specific folder. + if (GSConfig.OrganizeVideoCaptureByGame) + { + const bool prefer_english = Host::GetBaseBoolSettingValue("UI", "PreferEnglishGameList", false); + std::string game_name = VMManager::GetTitle(prefer_english); + if (!game_name.empty()) + { + Path::SanitizeFileName(&game_name); + const std::string game_dir = Path::Combine(EmuFolders::Videos, game_name); + + // Make sure the per-game directory exists or that we can successfully create it. + if (FileSystem::DirectoryExists(game_dir.c_str()) || FileSystem::CreateDirectoryPath(game_dir.c_str(), false)) + return Path::Combine(game_dir, GSGetBaseFilename()); + } + } // prepend video directory return Path::Combine(EmuFolders::Videos, GSGetBaseFilename()); } diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 6f8d48038e..325771142f 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -934,6 +934,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap) SettingsWrapIntEnumEx(ScreenshotFormat, "ScreenshotFormat"); SettingsWrapEntry(ScreenshotQuality); SettingsWrapBitBoolEx(OrganizeSnapshotsByGame, "OrganizeScreenshotsByGame"); + SettingsWrapBitBoolEx(OrganizeVideoCaptureByGame, "OrganizeVideoCaptureByGame"); SettingsWrapEntry(StretchY); SettingsWrapEntryEx(Crop[0], "CropLeft"); SettingsWrapEntryEx(Crop[1], "CropTop");