input-rec: remove input recording code from wx-related source
|
@ -841,10 +841,9 @@ void cdvdReset()
|
|||
|
||||
// If we are recording, always use the same RTC setting
|
||||
// for games that use the RTC to seed their RNG -- this is very important to be the same everytime!
|
||||
#ifndef PCSX2_CORE
|
||||
const bool input_recording_active = g_InputRecording.IsActive();
|
||||
#else
|
||||
const bool input_recording_active = g_InputRecording.isActive();
|
||||
bool input_recording_active = false;
|
||||
#ifdef PCSX2_CORE
|
||||
input_recording_active = g_InputRecording.isActive();
|
||||
#endif
|
||||
if (input_recording_active)
|
||||
{
|
||||
|
|
|
@ -1390,12 +1390,8 @@ set(pcsx2RecordingSources
|
|||
${rec_src}/InputRecording.cpp
|
||||
${rec_src}/InputRecordingControls.cpp
|
||||
${rec_src}/InputRecordingFile.cpp
|
||||
${rec_src}/NewRecordingFrame.cpp
|
||||
${rec_src}/PadData.cpp
|
||||
${rec_src}/Utilities/InputRecordingLogger.cpp
|
||||
${rec_vp_src}/VirtualPad.cpp
|
||||
${rec_vp_src}/VirtualPadData.cpp
|
||||
${rec_vp_src}/VirtualPadResources.cpp
|
||||
)
|
||||
|
||||
# Recording headers
|
||||
|
@ -1403,38 +1399,8 @@ set(pcsx2RecordingHeaders
|
|||
${rec_src}/InputRecording.h
|
||||
${rec_src}/InputRecordingControls.h
|
||||
${rec_src}/InputRecordingFile.h
|
||||
${rec_src}/NewRecordingFrame.h
|
||||
${rec_src}/PadData.h
|
||||
${rec_src}/Utilities/InputRecordingLogger.h
|
||||
${rec_vp_src}/VirtualPad.h
|
||||
${rec_vp_src}/VirtualPadData.h
|
||||
${rec_vp_src}/VirtualPadResources.h
|
||||
)
|
||||
|
||||
# Warning: the declaration of the .h are mandatory in case of resources files. It will ensure the creation
|
||||
# from the bin2cpp tools at the right moment (ie .h must be created before the pcsx2 compilation)
|
||||
# Recording - VirtualPad resources headers
|
||||
set(res_rec_vp_src "${CMAKE_SOURCE_DIR}/pcsx2/Recording/VirtualPad/img")
|
||||
set(pcsx2RecordingVirtualPadResources
|
||||
${res_rec_vp_src}/circlePressed.h
|
||||
${res_rec_vp_src}/controllerFull.h
|
||||
${res_rec_vp_src}/controllerHalf.h
|
||||
${res_rec_vp_src}/controllerThreeQuarters.h
|
||||
${res_rec_vp_src}/crossPressed.h
|
||||
${res_rec_vp_src}/downPressed.h
|
||||
${res_rec_vp_src}/l1Pressed.h
|
||||
${res_rec_vp_src}/l2Pressed.h
|
||||
${res_rec_vp_src}/l3Pressed.h
|
||||
${res_rec_vp_src}/leftPressed.h
|
||||
${res_rec_vp_src}/r1Pressed.h
|
||||
${res_rec_vp_src}/r2Pressed.h
|
||||
${res_rec_vp_src}/r3Pressed.h
|
||||
${res_rec_vp_src}/rightPressed.h
|
||||
${res_rec_vp_src}/selectPressed.h
|
||||
${res_rec_vp_src}/squarePressed.h
|
||||
${res_rec_vp_src}/startPressed.h
|
||||
${res_rec_vp_src}/trianglePressed.h
|
||||
${res_rec_vp_src}/upPressed.h
|
||||
)
|
||||
|
||||
# System headers
|
||||
|
@ -1737,18 +1703,6 @@ if(NOT PCSX2_CORE)
|
|||
COMMAND ${BIN2CPP} "${res_src}/${res_file}.png" "${res_bin}/${res_file}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
### Generate Recording resource files
|
||||
### Drop them into the folder alongside the png files
|
||||
foreach(res_file IN ITEMS
|
||||
circlePressed controllerFull controllerHalf controllerThreeQuarters crossPressed downPressed l1Pressed l2Pressed l3Pressed leftPressed
|
||||
r1Pressed r2Pressed r3Pressed rightPressed selectPressed squarePressed startPressed trianglePressed upPressed)
|
||||
add_custom_command(
|
||||
OUTPUT "${res_rec_vp_src}/${res_file}.h"
|
||||
DEPENDS ${BIN2CPPDEP} "${res_rec_vp_src}/${res_file}.png"
|
||||
COMMAND ${BIN2CPP} "${res_rec_vp_src}/${res_file}.png" "${res_rec_vp_src}/${res_file}"
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# additonal include directories
|
||||
|
|
|
@ -608,15 +608,6 @@ static __fi void frameLimit()
|
|||
|
||||
static __fi void VSyncStart(u32 sCycle)
|
||||
{
|
||||
if (EmuConfig.EnableRecordingTools)
|
||||
{
|
||||
// It is imperative that any frame locking that must happen occurs before Vsync is started
|
||||
// Not doing so would sacrifice a frame of a savestate-based recording when loading any savestate
|
||||
#ifndef PCSX2_CORE
|
||||
g_InputRecordingControls.HandlePausingAndLocking();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
// Update vibration at the end of a frame.
|
||||
PAD::Update();
|
||||
|
@ -676,13 +667,6 @@ static __fi void GSVSync()
|
|||
|
||||
static __fi void VSyncEnd(u32 sCycle)
|
||||
{
|
||||
#ifndef PCSX2_CORE
|
||||
if (EmuConfig.EnableRecordingTools)
|
||||
{
|
||||
g_InputRecordingControls.CheckPauseStatus();
|
||||
}
|
||||
#endif
|
||||
|
||||
if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll)
|
||||
SysTrace.EE.Counters.Write( " ================ EE COUNTER VSYNC END (frame: %d) ================", g_FrameCount );
|
||||
|
||||
|
|
|
@ -15,24 +15,8 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
// TODO - Vaser - kill with wxWidgets
|
||||
|
||||
#include "common/StringUtil.h"
|
||||
#include "SaveState.h"
|
||||
#include "Counters.h"
|
||||
#include "SaveState.h"
|
||||
|
||||
#include "gui/App.h"
|
||||
#include "gui/AppSaveStates.h"
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "GameDatabase.h"
|
||||
|
||||
#include "InputRecording.h"
|
||||
#include "InputRecordingControls.h"
|
||||
#include "Utilities/InputRecordingLogger.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
void SaveStateBase::InputRecordingFreeze()
|
||||
{
|
||||
|
@ -40,430 +24,9 @@ void SaveStateBase::InputRecordingFreeze()
|
|||
// CHANGING THIS WILL BREAK BACKWARDS COMPATIBILITY ON SAVESTATES
|
||||
FreezeTag("InputRecording");
|
||||
Freeze(g_FrameCount);
|
||||
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
{
|
||||
// Loading a save-state is an asynchronous task. If we are playing a recording
|
||||
// that starts from a savestate (not power-on) and the starting (pcsx2 internal) frame
|
||||
// marker has not been set (which comes from the save-state), we initialize it.
|
||||
if (g_InputRecording.IsInitialLoad())
|
||||
g_InputRecording.SetupInitialState(g_FrameCount);
|
||||
else if (g_InputRecording.IsActive() && IsLoading())
|
||||
g_InputRecording.SetFrameCounter(g_FrameCount);
|
||||
}
|
||||
}
|
||||
|
||||
InputRecording g_InputRecording;
|
||||
|
||||
InputRecording::InputRecordingPad::InputRecordingPad()
|
||||
{
|
||||
padData = new PadData;
|
||||
}
|
||||
|
||||
InputRecording::InputRecordingPad::~InputRecordingPad()
|
||||
{
|
||||
delete padData;
|
||||
}
|
||||
|
||||
void InputRecording::InitVirtualPadWindows(wxWindow* parent)
|
||||
{
|
||||
for (int port = 0; port < 2; ++port)
|
||||
if (!pads[port].virtualPad)
|
||||
pads[port].virtualPad = new VirtualPad(parent, port, g_Conf->inputRecording);
|
||||
}
|
||||
|
||||
void InputRecording::ShowVirtualPad(const int port)
|
||||
{
|
||||
pads[port].virtualPad->Show();
|
||||
}
|
||||
|
||||
void InputRecording::RecordingReset()
|
||||
{
|
||||
// Booting is an asynchronous task. If we are playing a recording
|
||||
// that starts from power-on and the starting (pcsx2 internal) frame
|
||||
// marker has not been set, we initialize it.
|
||||
if (g_InputRecording.IsInitialLoad())
|
||||
g_InputRecording.SetupInitialState(0);
|
||||
else if (g_InputRecording.IsActive())
|
||||
{
|
||||
g_InputRecording.SetFrameCounter(0);
|
||||
g_InputRecordingControls.Lock(0);
|
||||
}
|
||||
else
|
||||
g_InputRecordingControls.Resume();
|
||||
}
|
||||
|
||||
void InputRecording::ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8 dataOut)
|
||||
{
|
||||
// TODO - Multi-Tap Support
|
||||
|
||||
if (fifoSize == 1)
|
||||
fInterruptFrame = dataIn == READ_DATA_AND_VIBRATE_FIRST_BYTE;
|
||||
else if (fifoSize == 2)
|
||||
{
|
||||
if (dataOut != READ_DATA_AND_VIBRATE_SECOND_BYTE)
|
||||
fInterruptFrame = false;
|
||||
}
|
||||
else if (fInterruptFrame)
|
||||
{
|
||||
u8& bufVal = dataOut;
|
||||
const u16 bufIndex = fifoSize - 3;
|
||||
if (state == InputRecordingMode::Replaying)
|
||||
{
|
||||
if (frameCounter >= 0 && frameCounter < INT_MAX)
|
||||
{
|
||||
if (!inputRecordingData.ReadKeyBuffer(bufVal, frameCounter, port, bufIndex))
|
||||
InputRec::consoleLog(fmt::format("Failed to read input data at frame {}", frameCounter));
|
||||
|
||||
// Update controller data state for future VirtualPad / logging usage.
|
||||
pads[port].padData->UpdateControllerData(bufIndex, bufVal);
|
||||
|
||||
if (pads[port].virtualPad->IsShown())
|
||||
pads[port].virtualPad->UpdateControllerData(bufIndex, pads[port].padData);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update controller data state for future VirtualPad / logging usage.
|
||||
pads[port].padData->UpdateControllerData(bufIndex, bufVal);
|
||||
|
||||
// Commit the byte to the movie file if we are recording
|
||||
if (state == InputRecordingMode::Recording)
|
||||
{
|
||||
if (frameCounter >= 0)
|
||||
{
|
||||
// If the VirtualPad updated the PadData, we have to update the buffer
|
||||
// before committing it to the recording / sending it to the game
|
||||
if (pads[port].virtualPad->IsShown() && pads[port].virtualPad->UpdateControllerData(bufIndex, pads[port].padData))
|
||||
bufVal = pads[port].padData->PollControllerData(bufIndex);
|
||||
|
||||
if (incrementUndo)
|
||||
{
|
||||
inputRecordingData.IncrementUndoCount();
|
||||
incrementUndo = false;
|
||||
}
|
||||
|
||||
if (frameCounter < INT_MAX && !inputRecordingData.WriteKeyBuffer(frameCounter, port, bufIndex, bufVal))
|
||||
InputRec::consoleLog(fmt::format("Failed to write input data at frame {}", frameCounter));
|
||||
}
|
||||
}
|
||||
// If the VirtualPad updated the PadData, we have to update the buffer
|
||||
// before sending it to the game
|
||||
else if (pads[port].virtualPad && pads[port].virtualPad->IsShown() && pads[port].virtualPad->UpdateControllerData(bufIndex, pads[port].padData))
|
||||
bufVal = pads[port].padData->PollControllerData(bufIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 InputRecording::GetFrameCounter()
|
||||
{
|
||||
return frameCounter;
|
||||
}
|
||||
|
||||
InputRecordingFile& InputRecording::GetInputRecordingData()
|
||||
{
|
||||
return inputRecordingData;
|
||||
}
|
||||
|
||||
u32 InputRecording::GetStartingFrame()
|
||||
{
|
||||
return startingFrame;
|
||||
}
|
||||
|
||||
void InputRecording::IncrementFrameCounter()
|
||||
{
|
||||
if (frameCounter < INT_MAX)
|
||||
{
|
||||
frameCounter++;
|
||||
switch (state)
|
||||
{
|
||||
case InputRecordingMode::Recording:
|
||||
inputRecordingData.SetTotalFrames(frameCounter);
|
||||
[[fallthrough]];
|
||||
case InputRecordingMode::Replaying:
|
||||
if (frameCounter == inputRecordingData.GetTotalFrames())
|
||||
incrementUndo = false;
|
||||
break;
|
||||
case InputRecordingMode::NotActive: // Does nothing but keep GCC happy.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecording::LogAndRedraw()
|
||||
{
|
||||
for (u8 port = 0; port < 2; port++)
|
||||
{
|
||||
pads[port].padData->LogPadData(port);
|
||||
// As well as re-render the virtual pad UI, if applicable
|
||||
// - Don't render if it's minimized
|
||||
if (pads[port].virtualPad->IsShown() && !pads[port].virtualPad->IsIconized())
|
||||
pads[port].virtualPad->Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
bool InputRecording::IsInterruptFrame()
|
||||
{
|
||||
return fInterruptFrame;
|
||||
}
|
||||
|
||||
bool InputRecording::IsActive()
|
||||
{
|
||||
return state != InputRecordingMode::NotActive;
|
||||
}
|
||||
|
||||
bool InputRecording::IsInitialLoad()
|
||||
{
|
||||
return initialLoad;
|
||||
}
|
||||
|
||||
bool InputRecording::IsReplaying()
|
||||
{
|
||||
return state == InputRecordingMode::Replaying;
|
||||
}
|
||||
|
||||
bool InputRecording::IsRecording()
|
||||
{
|
||||
return state == InputRecordingMode::Recording;
|
||||
}
|
||||
|
||||
wxString InputRecording::RecordingModeTitleSegment()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case InputRecordingMode::Recording:
|
||||
return wxString("Recording");
|
||||
case InputRecordingMode::Replaying:
|
||||
return wxString("Replaying");
|
||||
default:
|
||||
return wxString("No Movie");
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecording::SetToRecordMode()
|
||||
{
|
||||
state = InputRecordingMode::Recording;
|
||||
pads[CONTROLLER_PORT_ONE].virtualPad->SetReadOnlyMode(false);
|
||||
pads[CONTROLLER_PORT_TWO].virtualPad->SetReadOnlyMode(false);
|
||||
InputRec::log("Record mode ON");
|
||||
}
|
||||
|
||||
void InputRecording::SetToReplayMode()
|
||||
{
|
||||
state = InputRecordingMode::Replaying;
|
||||
pads[CONTROLLER_PORT_ONE].virtualPad->SetReadOnlyMode(true);
|
||||
pads[CONTROLLER_PORT_TWO].virtualPad->SetReadOnlyMode(true);
|
||||
InputRec::log("Replay mode ON");
|
||||
}
|
||||
|
||||
void InputRecording::SetFrameCounter(u32 newGFrameCount)
|
||||
{
|
||||
if (newGFrameCount > startingFrame + (u32)inputRecordingData.GetTotalFrames())
|
||||
{
|
||||
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point after the end of the original recording. This should be avoided.");
|
||||
InputRec::consoleLog("Savestate's framecount has been ignored.");
|
||||
frameCounter = inputRecordingData.GetTotalFrames();
|
||||
if (state == InputRecordingMode::Replaying)
|
||||
SetToRecordMode();
|
||||
incrementUndo = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newGFrameCount < startingFrame)
|
||||
{
|
||||
InputRec::consoleLog("Warning, you've loaded PCSX2 emulation to a point before the start of the original recording. This should be avoided.");
|
||||
if (state == InputRecordingMode::Recording)
|
||||
SetToReplayMode();
|
||||
}
|
||||
else if (newGFrameCount == 0 && state == InputRecordingMode::Recording)
|
||||
SetToReplayMode();
|
||||
frameCounter = newGFrameCount - (s32)startingFrame;
|
||||
incrementUndo = true;
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecording::SetupInitialState(u32 newStartingFrame)
|
||||
{
|
||||
startingFrame = newStartingFrame;
|
||||
if (state != InputRecordingMode::Replaying)
|
||||
{
|
||||
InputRec::log("Started new input recording");
|
||||
InputRec::consoleLog(fmt::format("Filename {}", inputRecordingData.GetFilename().ToUTF8()));
|
||||
SetToRecordMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if the current game matches with the one used to make the original recording
|
||||
if (!g_Conf->CurrentIso.IsEmpty())
|
||||
if (resolveGameName() != inputRecordingData.GetHeader().gameName)
|
||||
InputRec::consoleLog("Input recording was possibly constructed for a different game.");
|
||||
|
||||
incrementUndo = true;
|
||||
InputRec::log("Replaying input recording");
|
||||
InputRec::consoleMultiLog({fmt::format("File: {}", inputRecordingData.GetFilename().ToUTF8()),
|
||||
fmt::format("PCSX2 Version Used: {}", std::string(inputRecordingData.GetHeader().emu)),
|
||||
fmt::format("Recording File Version: {}", inputRecordingData.GetHeader().version),
|
||||
fmt::format("Associated Game Name or ISO Filename: {}", std::string(inputRecordingData.GetHeader().gameName)),
|
||||
fmt::format("Author: {}", inputRecordingData.GetHeader().author),
|
||||
fmt::format("Total Frames: {}", inputRecordingData.GetTotalFrames()),
|
||||
fmt::format("Undo Count: {}", inputRecordingData.GetUndoCount())});
|
||||
SetToReplayMode();
|
||||
}
|
||||
|
||||
if (inputRecordingData.FromSaveState())
|
||||
InputRec::consoleLog(fmt::format("Internal Starting Frame: {}", startingFrame));
|
||||
frameCounter = 0;
|
||||
initialLoad = false;
|
||||
g_InputRecordingControls.Lock(startingFrame);
|
||||
}
|
||||
|
||||
void InputRecording::FailedSavestate()
|
||||
{
|
||||
InputRec::consoleLog(fmt::format("{} is not compatible with this version of PCSX2", savestate.ToUTF8()));
|
||||
InputRec::consoleLog(fmt::format("Original PCSX2 version used: {}", inputRecordingData.GetHeader().emu));
|
||||
inputRecordingData.Close();
|
||||
initialLoad = false;
|
||||
state = InputRecordingMode::NotActive;
|
||||
g_InputRecordingControls.Resume();
|
||||
}
|
||||
|
||||
void InputRecording::Stop()
|
||||
{
|
||||
state = InputRecordingMode::NotActive;
|
||||
pads[CONTROLLER_PORT_ONE].virtualPad->SetReadOnlyMode(false);
|
||||
pads[CONTROLLER_PORT_TWO].virtualPad->SetReadOnlyMode(false);
|
||||
incrementUndo = false;
|
||||
if (inputRecordingData.Close())
|
||||
InputRec::log("Input recording stopped");
|
||||
}
|
||||
|
||||
bool InputRecording::Create(wxString fileName, const bool fromSaveState, wxString authorName)
|
||||
{
|
||||
if (!inputRecordingData.OpenNew(fileName, fromSaveState))
|
||||
return false;
|
||||
|
||||
initialLoad = true;
|
||||
state = InputRecordingMode::Recording;
|
||||
if (fromSaveState)
|
||||
{
|
||||
savestate = fileName + "_SaveState.p2s";
|
||||
if (wxFileExists(savestate))
|
||||
wxCopyFile(savestate, savestate + ".bak", true);
|
||||
StateCopy_SaveToFile(savestate);
|
||||
}
|
||||
else
|
||||
sApp.SysExecute(g_Conf->CdvdSource);
|
||||
|
||||
// Set emulator version
|
||||
inputRecordingData.GetHeader().SetEmulatorVersion();
|
||||
|
||||
// Set author name
|
||||
if (!authorName.IsEmpty())
|
||||
inputRecordingData.GetHeader().SetAuthor(authorName);
|
||||
|
||||
// Set Game Name
|
||||
inputRecordingData.GetHeader().SetGameName(resolveGameName());
|
||||
// Write header contents
|
||||
inputRecordingData.WriteHeader();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputRecording::Play(wxWindow* parent, wxString filename)
|
||||
{
|
||||
if (!inputRecordingData.OpenExisting(filename))
|
||||
return false;
|
||||
|
||||
// Either load the savestate, or restart the game
|
||||
if (inputRecordingData.FromSaveState())
|
||||
{
|
||||
if (!GetCoreThread().IsOpen())
|
||||
{
|
||||
InputRec::consoleLog("Game is not open, aborting playing input recording which starts on a save-state.");
|
||||
inputRecordingData.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
savestate = inputRecordingData.GetFilename() + "_SaveState.p2s";
|
||||
if (!wxFileExists(savestate))
|
||||
{
|
||||
wxFileDialog loadStateDialog(parent, _("Select the savestate that will accompany this recording"), L"", L"",
|
||||
L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
|
||||
if (loadStateDialog.ShowModal() == wxID_CANCEL)
|
||||
{
|
||||
InputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}", savestate.ToUTF8()));
|
||||
InputRec::log("Savestate load failed");
|
||||
inputRecordingData.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
savestate = loadStateDialog.GetPath();
|
||||
InputRec::consoleLog(fmt::format("Base savestate set to {}", savestate.ToUTF8()));
|
||||
}
|
||||
state = InputRecordingMode::Replaying;
|
||||
initialLoad = true;
|
||||
StateCopy_LoadFromFile(savestate);
|
||||
}
|
||||
else
|
||||
{
|
||||
state = InputRecordingMode::Replaying;
|
||||
initialLoad = true;
|
||||
sApp.SysExecute(g_Conf->CdvdSource);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputRecording::GoToFirstFrame(wxWindow* parent)
|
||||
{
|
||||
if (inputRecordingData.FromSaveState())
|
||||
{
|
||||
if (!wxFileExists(savestate))
|
||||
{
|
||||
const bool initiallyPaused = g_InputRecordingControls.IsPaused();
|
||||
|
||||
if (!initiallyPaused)
|
||||
g_InputRecordingControls.PauseImmediately();
|
||||
|
||||
InputRec::consoleLog(fmt::format("Could not locate savestate file at location - {}\n", savestate.ToUTF8()));
|
||||
wxFileDialog loadStateDialog(parent, _("Select a savestate to accompany the recording with"), L"", L"",
|
||||
L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
|
||||
int result = loadStateDialog.ShowModal();
|
||||
if (!initiallyPaused)
|
||||
g_InputRecordingControls.Resume();
|
||||
|
||||
if (result == wxID_CANCEL)
|
||||
{
|
||||
InputRec::log("Savestate load cancelled");
|
||||
return;
|
||||
}
|
||||
savestate = loadStateDialog.GetPath();
|
||||
InputRec::consoleLog(fmt::format("Base savestate swapped to {}", savestate.ToUTF8()));
|
||||
}
|
||||
StateCopy_LoadFromFile(savestate);
|
||||
}
|
||||
else
|
||||
sApp.SysExecute(g_Conf->CdvdSource);
|
||||
|
||||
if (IsRecording())
|
||||
SetToReplayMode();
|
||||
}
|
||||
|
||||
wxString InputRecording::resolveGameName()
|
||||
{
|
||||
std::string gameName;
|
||||
const std::string gameKey(SysGetDiscID());
|
||||
if (!gameKey.empty())
|
||||
{
|
||||
auto game = GameDatabase::findGame(gameKey);
|
||||
if (game)
|
||||
{
|
||||
gameName = game->name;
|
||||
gameName += " (" + game->region + ")";
|
||||
}
|
||||
}
|
||||
return !gameName.empty() ? StringUtil::UTF8StringToWxString(gameName) : Path::GetFilename(g_Conf->CurrentIso);
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
#include "InputRecording.h"
|
||||
|
||||
|
@ -472,7 +35,6 @@ wxString InputRecording::resolveGameName()
|
|||
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "SaveState.h"
|
||||
#include "Counters.h"
|
||||
#include "SaveState.h"
|
||||
#include "VMManager.h"
|
||||
|
@ -481,14 +43,6 @@ wxString InputRecording::resolveGameName()
|
|||
#include "fmt/format.h"
|
||||
#include "GS.h"
|
||||
|
||||
void SaveStateBase::InputRecordingFreeze()
|
||||
{
|
||||
// NOTE - BE CAREFUL
|
||||
// CHANGING THIS WILL BREAK BACKWARDS COMPATIBILITY ON SAVESTATES
|
||||
FreezeTag("InputRecording");
|
||||
Freeze(g_FrameCount);
|
||||
}
|
||||
|
||||
InputRecording g_InputRecording;
|
||||
|
||||
bool InputRecording::create(const std::string& fileName, const bool fromSaveState, const std::string& authorName)
|
||||
|
@ -633,7 +187,8 @@ void InputRecording::handleControllerDataUpdate()
|
|||
else if (m_controls.isReplaying())
|
||||
{
|
||||
const auto& modifiedFrameData = updateControllerData(i, 0);
|
||||
if (modifiedFrameData) {
|
||||
if (modifiedFrameData)
|
||||
{
|
||||
frameData = modifiedFrameData.value();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,141 +15,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
#include <queue>
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
// TODO - Vaser - kill with wxWidgets
|
||||
|
||||
#include "Recording/InputRecordingFile.h"
|
||||
#include "Recording/VirtualPad/VirtualPad.h"
|
||||
|
||||
class InputRecording
|
||||
{
|
||||
public:
|
||||
// Initializes all VirtualPad windows with "parent" as their base
|
||||
void InitVirtualPadWindows(wxWindow* parent);
|
||||
|
||||
// Save or load PCSX2's global frame counter (g_FrameCount) along with each full/fast boot
|
||||
//
|
||||
// This is to prevent any inaccuracy issues caused by having a different
|
||||
// internal emulation frame count than what it was at the beginning of the
|
||||
// original recording
|
||||
void RecordingReset();
|
||||
|
||||
// Main handler for ingesting input data and either saving it to the recording file (recording)
|
||||
// or mutating it to the contents of the recording file (replaying)
|
||||
void ControllerInterrupt(u8 port, size_t fifoSize, u8 dataIn, u8 dataOut);
|
||||
|
||||
// The running frame counter for the input recording
|
||||
s32 GetFrameCounter();
|
||||
|
||||
InputRecordingFile& GetInputRecordingData();
|
||||
|
||||
// The internal PCSX2 g_FrameCount value on the first frame of the recording
|
||||
u32 GetStartingFrame();
|
||||
|
||||
void IncrementFrameCounter();
|
||||
|
||||
// DEPRECATED: Slated for removal
|
||||
// If the current frame contains controller / input data
|
||||
bool IsInterruptFrame();
|
||||
|
||||
// If there is currently an input recording being played back or actively being recorded
|
||||
bool IsActive();
|
||||
|
||||
// Whether or not the recording's initial state has yet to be loaded or saved and
|
||||
// the rest of the recording can be initialized
|
||||
// This is not applicable to recordings from a "power-on" state
|
||||
bool IsInitialLoad();
|
||||
|
||||
// If there is currently an input recording being played back
|
||||
bool IsReplaying();
|
||||
|
||||
// If there are inputs currently being recorded to a file
|
||||
bool IsRecording();
|
||||
|
||||
// String representation of the current recording mode to be interpolated into the title
|
||||
wxString RecordingModeTitleSegment();
|
||||
|
||||
// Sets input recording to Record Mode
|
||||
void SetToRecordMode();
|
||||
|
||||
// Sets input recording to Replay Mode
|
||||
void SetToReplayMode();
|
||||
|
||||
// Set the running frame counter for the input recording to an arbitrary value
|
||||
void SetFrameCounter(u32 newGFrameCount);
|
||||
|
||||
// Sets up all values and prints console logs pertaining to the start of a recording
|
||||
void SetupInitialState(u32 newStartingFrame);
|
||||
|
||||
/// Functions called from GUI
|
||||
|
||||
// Create a new input recording file
|
||||
bool Create(wxString filename, const bool fromSaveState, wxString authorName);
|
||||
// Play an existing input recording from a file
|
||||
// Calls a file dialog if it fails to locate the default base savestate
|
||||
bool Play(wxWindow* parent, wxString filename);
|
||||
// Stop the active input recording
|
||||
void Stop();
|
||||
// Displays the VirtualPad window for the chosen pad
|
||||
void ShowVirtualPad(const int port);
|
||||
// Logs the padData and redraws the virtualPad windows of active pads
|
||||
void LogAndRedraw();
|
||||
// Resets emulation to the beginning of a recording
|
||||
// Calls a file dialog if it fails to locate the base savestate
|
||||
void GoToFirstFrame(wxWindow* parent);
|
||||
// Resets a recording if the base savestate could not be loaded at the start
|
||||
void FailedSavestate();
|
||||
|
||||
private:
|
||||
enum class InputRecordingMode
|
||||
{
|
||||
NotActive,
|
||||
Recording,
|
||||
Replaying,
|
||||
};
|
||||
|
||||
static const int CONTROLLER_PORT_ONE = 0;
|
||||
static const int CONTROLLER_PORT_TWO = 1;
|
||||
|
||||
// 0x42 is the magic number to indicate the default controller read query
|
||||
// See - PAD.cpp::PADpoll - https://github.com/PCSX2/pcsx2/blob/master/pcsx2/PAD/Windows/PAD.cpp#L1255
|
||||
static const u8 READ_DATA_AND_VIBRATE_FIRST_BYTE = 0x42;
|
||||
// 0x5A is always the second byte in the buffer when the normal READ_DATA_AND_VIBRATE (0x42) query is executed.
|
||||
// See - PAD.cpp::PADpoll - https://github.com/PCSX2/pcsx2/blob/master/pcsx2/PAD/Windows/PAD.cpp#L1256
|
||||
static const u8 READ_DATA_AND_VIBRATE_SECOND_BYTE = 0x5A;
|
||||
|
||||
// DEPRECATED: Slated for removal
|
||||
bool fInterruptFrame = false;
|
||||
InputRecordingFile inputRecordingData;
|
||||
bool initialLoad = false;
|
||||
u32 startingFrame = 0;
|
||||
s32 frameCounter = 0;
|
||||
bool incrementUndo = false;
|
||||
InputRecordingMode state = InputRecording::InputRecordingMode::NotActive;
|
||||
wxString savestate;
|
||||
|
||||
// Array of usable pads (currently, only 2)
|
||||
struct InputRecordingPad
|
||||
{
|
||||
// Controller Data
|
||||
PadData* padData;
|
||||
// VirtualPad
|
||||
VirtualPad* virtualPad;
|
||||
InputRecordingPad();
|
||||
~InputRecordingPad();
|
||||
} pads[2];
|
||||
|
||||
// Resolve the name and region of the game currently loaded using the GameDB
|
||||
// If the game cannot be found in the DB, the fallback is the ISO filename
|
||||
wxString resolveGameName();
|
||||
};
|
||||
|
||||
extern InputRecording g_InputRecording;
|
||||
|
||||
#else
|
||||
|
||||
#include "Recording/InputRecordingFile.h"
|
||||
#include "Recording/InputRecordingControls.h"
|
||||
|
||||
|
|
|
@ -13,211 +13,10 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
// TODO - Vaser - kill with wxWidgets
|
||||
|
||||
#include "Counters.h"
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "MemoryTypes.h"
|
||||
#include "gui/MainFrame.h"
|
||||
|
||||
#include "InputRecording.h"
|
||||
#include "InputRecordingControls.h"
|
||||
#include "Utilities/InputRecordingLogger.h"
|
||||
|
||||
InputRecordingControls g_InputRecordingControls;
|
||||
|
||||
void InputRecordingControls::CheckPauseStatus()
|
||||
{
|
||||
frame_advance_frame_counter++;
|
||||
if (frameAdvancing && frame_advance_frame_counter >= frames_per_frame_advance)
|
||||
{
|
||||
frameAdvancing = false;
|
||||
pauseEmulation = true;
|
||||
}
|
||||
|
||||
if (g_InputRecording.IsActive())
|
||||
{
|
||||
g_InputRecording.IncrementFrameCounter();
|
||||
|
||||
if (switchToReplay)
|
||||
{
|
||||
g_InputRecording.SetToReplayMode();
|
||||
switchToReplay = false;
|
||||
}
|
||||
|
||||
if (IsFinishedReplaying() || g_InputRecording.GetFrameCounter() == INT_MAX)
|
||||
{
|
||||
if (!pauseEmulation)
|
||||
pauseEmulation = true;
|
||||
StopCapture();
|
||||
}
|
||||
}
|
||||
g_InputRecording.LogAndRedraw();
|
||||
}
|
||||
|
||||
void InputRecordingControls::HandlePausingAndLocking()
|
||||
{
|
||||
// Explicit frame locking
|
||||
if (frameLock)
|
||||
{
|
||||
if (g_FrameCount == frameLockTracker)
|
||||
{
|
||||
frameLock = false;
|
||||
Resume();
|
||||
}
|
||||
else if (!emulationCurrentlyPaused && GetCoreThread().IsOpen() && GetCoreThread().IsRunning())
|
||||
{
|
||||
emulationCurrentlyPaused = true;
|
||||
GetCoreThread().PauseSelf();
|
||||
}
|
||||
}
|
||||
else if (pauseEmulation && GetCoreThread().IsOpen() && GetCoreThread().IsRunning())
|
||||
{
|
||||
emulationCurrentlyPaused = true;
|
||||
GetCoreThread().PauseSelf();
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecordingControls::ResumeCoreThreadIfStarted()
|
||||
{
|
||||
if (resumeEmulation && GetCoreThread().IsOpen())
|
||||
{
|
||||
GetCoreThread().Resume();
|
||||
resumeEmulation = false;
|
||||
emulationCurrentlyPaused = false;
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecordingControls::FrameAdvance()
|
||||
{
|
||||
if (!IsFinishedReplaying())
|
||||
{
|
||||
frameAdvancing = true;
|
||||
frame_advance_frame_counter = 0;
|
||||
Resume();
|
||||
}
|
||||
else
|
||||
g_InputRecording.SetToRecordMode();
|
||||
}
|
||||
|
||||
void InputRecordingControls::setFrameAdvanceAmount(int amount)
|
||||
{
|
||||
frames_per_frame_advance = amount;
|
||||
}
|
||||
|
||||
bool InputRecordingControls::IsFrameAdvancing()
|
||||
{
|
||||
return frameAdvancing;
|
||||
}
|
||||
|
||||
bool InputRecordingControls::IsPaused()
|
||||
{
|
||||
return emulationCurrentlyPaused && GetCoreThread().IsOpen() && GetCoreThread().IsPaused();
|
||||
}
|
||||
|
||||
void InputRecordingControls::Pause()
|
||||
{
|
||||
pauseEmulation = true;
|
||||
resumeEmulation = false;
|
||||
}
|
||||
|
||||
void InputRecordingControls::PauseImmediately()
|
||||
{
|
||||
if (!GetCoreThread().IsPaused())
|
||||
{
|
||||
Pause();
|
||||
if (GetCoreThread().IsOpen() && GetCoreThread().IsRunning())
|
||||
{
|
||||
emulationCurrentlyPaused = true;
|
||||
GetCoreThread().PauseSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecordingControls::Resume()
|
||||
{
|
||||
if (!IsFinishedReplaying())
|
||||
{
|
||||
pauseEmulation = false;
|
||||
resumeEmulation = true;
|
||||
}
|
||||
else
|
||||
g_InputRecording.SetToRecordMode();
|
||||
}
|
||||
|
||||
void InputRecordingControls::ResumeImmediately()
|
||||
{
|
||||
if (GetCoreThread().IsPaused())
|
||||
{
|
||||
Resume();
|
||||
if (GetCoreThread().IsRunning())
|
||||
{
|
||||
emulationCurrentlyPaused = false;
|
||||
GetCoreThread().Resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecordingControls::TogglePause()
|
||||
{
|
||||
if (!pauseEmulation || !IsFinishedReplaying())
|
||||
{
|
||||
resumeEmulation = pauseEmulation;
|
||||
pauseEmulation = !pauseEmulation;
|
||||
InputRec::log(pauseEmulation ? "Paused Emulation" : "Resumed Emulation");
|
||||
}
|
||||
else
|
||||
g_InputRecording.SetToRecordMode();
|
||||
}
|
||||
|
||||
void InputRecordingControls::RecordModeToggle()
|
||||
{
|
||||
if (g_InputRecording.IsReplaying())
|
||||
g_InputRecording.SetToRecordMode();
|
||||
else if (g_InputRecording.IsRecording())
|
||||
{
|
||||
if (IsPaused() || g_InputRecording.GetFrameCounter() < g_InputRecording.GetInputRecordingData().GetTotalFrames())
|
||||
g_InputRecording.SetToReplayMode();
|
||||
else
|
||||
switchToReplay = true;
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecordingControls::Lock(u32 frame)
|
||||
{
|
||||
frameLock = true;
|
||||
frameLockTracker = frame;
|
||||
frameAdvancing = false;
|
||||
//Ensures that g_frameCount can be used to resume emulation after a fast/full boot
|
||||
if (!g_InputRecording.GetInputRecordingData().FromSaveState())
|
||||
g_FrameCount = frame + 1;
|
||||
else
|
||||
sMainFrame.StartInputRecording();
|
||||
}
|
||||
|
||||
bool InputRecordingControls::IsFinishedReplaying() const
|
||||
{
|
||||
return g_InputRecording.IsReplaying() &&
|
||||
g_InputRecording.GetFrameCounter() >= g_InputRecording.GetInputRecordingData().GetTotalFrames();
|
||||
}
|
||||
|
||||
void InputRecordingControls::StopCapture() const
|
||||
{
|
||||
if (MainEmuFrame* mainFrame = GetMainFramePtr())
|
||||
{
|
||||
if (mainFrame->IsCapturing())
|
||||
{
|
||||
mainFrame->VideoCaptureToggle();
|
||||
InputRec::log("Capture completed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "MemoryTypes.h"
|
||||
|
||||
|
|
|
@ -15,91 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
// TODO - Vaser - kill with wxWidgets
|
||||
|
||||
class InputRecordingControls
|
||||
{
|
||||
public:
|
||||
// Intended to be called at the end of each frame, but will no-op if frame lock is active
|
||||
//
|
||||
// Will set the pausing parameters for emulation if:
|
||||
// - The InputRecordingControls::FrameAdvance was hit on the previous frame
|
||||
// - Emulation was explicitly paused using InputRecordingControls::TogglePause
|
||||
// - We are replaying an input recording and have hit the end
|
||||
void CheckPauseStatus();
|
||||
|
||||
// When loading a recording file or booting with a recording active, lock will be enabled.
|
||||
// Emulation will be forced into and remain in a paused state until the transition in progress
|
||||
// has completed - signaled when g_framecount and frameCountTracker are equal
|
||||
//
|
||||
// This function also handles actually pausing emulation when told to
|
||||
void HandlePausingAndLocking();
|
||||
|
||||
// Called much more frequently than HandleFrameAdvanceAndPausing, instead of being per frame
|
||||
// this hooks into pcsx2's main App event handler as it has to be able to resume emulation
|
||||
// when drawing frames has compltely stopped
|
||||
//
|
||||
// Resumes emulation if:
|
||||
// - CoreThread is currently open and paused
|
||||
// - We've signaled emulation to be resumed via TogglePause or FrameAdvancing
|
||||
void ResumeCoreThreadIfStarted();
|
||||
|
||||
// Resume emulation (incase the emulation is currently paused) and pause after a single frame has passed
|
||||
void FrameAdvance();
|
||||
void setFrameAdvanceAmount(int amount);
|
||||
// Returns true if emulation is currently set up to frame advance.
|
||||
bool IsFrameAdvancing();
|
||||
// Returns true if the input recording has been paused, which can occur:
|
||||
// - After a single frame has passed after InputRecordingControls::FrameAdvance
|
||||
// - Explicitly paused via an InputRecordingControls function
|
||||
bool IsPaused();
|
||||
// Pause emulation at the next available Vsync
|
||||
void Pause();
|
||||
// Pause emulation immediately, not waiting for the next Vsync
|
||||
void PauseImmediately();
|
||||
// Resume emulation when the next pcsx2 App event is handled
|
||||
void Resume();
|
||||
/**
|
||||
* @brief Resumes emulation immediately, don't wait until the next VSync
|
||||
*/
|
||||
void ResumeImmediately();
|
||||
// Alternates emulation between a paused and unpaused state
|
||||
void TogglePause();
|
||||
// Switches between recording and replaying the active input recording file
|
||||
void RecordModeToggle();
|
||||
// Enables the frame locking mechanism so that when recordings are loaded
|
||||
// or when processing a reboot with a recording active that no frames are
|
||||
// lost in prior emulation
|
||||
void Lock(u32 frame);
|
||||
|
||||
private:
|
||||
// Indicates if the input recording controls have explicitly paused emulation or not
|
||||
bool emulationCurrentlyPaused = false;
|
||||
// Indicates on the next VSync if we are frame advancing, this value
|
||||
// and should be cleared once a single frame has passed
|
||||
bool frameAdvancing = false;
|
||||
u32 frame_advance_frame_counter = 0;
|
||||
u32 frames_per_frame_advance = 1;
|
||||
// Indicates if we intend to call CoreThread.PauseSelf() on the current or next available vsync
|
||||
bool pauseEmulation = false;
|
||||
// Indicates if we intend to call CoreThread.Resume() when the next pcsx2 App event is handled
|
||||
bool resumeEmulation = false;
|
||||
// Indicates to switch to replay mode after the next vsync
|
||||
bool switchToReplay = false;
|
||||
// Used to stop recording frames from incrementing during a reset
|
||||
bool frameLock = false;
|
||||
// The frame value to use as the frame lock reset point
|
||||
u32 frameLockTracker = 0;
|
||||
|
||||
bool IsFinishedReplaying() const;
|
||||
// Calls mainEmuFrame's videoCaptureToggle to end a capture if active
|
||||
void StopCapture() const;
|
||||
};
|
||||
|
||||
extern InputRecordingControls g_InputRecordingControls;
|
||||
|
||||
#else
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
#include <queue>
|
||||
|
||||
|
|
|
@ -13,225 +13,10 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
// TODO - Vaser - kill with wxWidgets
|
||||
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "gui/MainFrame.h"
|
||||
#include "MemoryTypes.h"
|
||||
|
||||
#include "InputRecordingFile.h"
|
||||
#include "Utilities/InputRecordingLogger.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
void InputRecordingFileHeader::Init()
|
||||
{
|
||||
memset(author, 0, std::size(author));
|
||||
memset(gameName, 0, std::size(gameName));
|
||||
}
|
||||
|
||||
void InputRecordingFileHeader::SetEmulatorVersion()
|
||||
{
|
||||
wxString emuVersion = wxString::Format("%s-%d.%d.%d", pxGetAppName().c_str(), PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo);
|
||||
int max = std::size(emu) - 1;
|
||||
strncpy(emu, emuVersion.c_str(), max);
|
||||
emu[max] = 0;
|
||||
}
|
||||
|
||||
void InputRecordingFileHeader::SetAuthor(wxString _author)
|
||||
{
|
||||
int max = std::size(author) - 1;
|
||||
strncpy(author, _author.c_str(), max);
|
||||
author[max] = 0;
|
||||
}
|
||||
|
||||
void InputRecordingFileHeader::SetGameName(wxString _gameName)
|
||||
{
|
||||
int max = std::size(gameName) - 1;
|
||||
strncpy(gameName, _gameName.c_str(), max);
|
||||
gameName[max] = 0;
|
||||
}
|
||||
|
||||
bool InputRecordingFile::Close()
|
||||
{
|
||||
if (recordingFile == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
fclose(recordingFile);
|
||||
recordingFile = nullptr;
|
||||
filename = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
const wxString& InputRecordingFile::GetFilename()
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
|
||||
InputRecordingFileHeader& InputRecordingFile::GetHeader()
|
||||
{
|
||||
return header;
|
||||
}
|
||||
|
||||
long& InputRecordingFile::GetTotalFrames()
|
||||
{
|
||||
return totalFrames;
|
||||
}
|
||||
|
||||
unsigned long& InputRecordingFile::GetUndoCount()
|
||||
{
|
||||
return undoCount;
|
||||
}
|
||||
|
||||
bool InputRecordingFile::FromSaveState()
|
||||
{
|
||||
return savestate.fromSavestate;
|
||||
}
|
||||
|
||||
void InputRecordingFile::IncrementUndoCount()
|
||||
{
|
||||
undoCount++;
|
||||
if (recordingFile == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
fseek(recordingFile, seekpointUndoCount, SEEK_SET);
|
||||
fwrite(&undoCount, 4, 1, recordingFile);
|
||||
}
|
||||
|
||||
bool InputRecordingFile::open(const wxString path, bool newRecording)
|
||||
{
|
||||
if (newRecording)
|
||||
{
|
||||
if ((recordingFile = wxFopen(path, L"wb+")) != nullptr)
|
||||
{
|
||||
filename = path;
|
||||
totalFrames = 0;
|
||||
undoCount = 0;
|
||||
header.Init();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if ((recordingFile = wxFopen(path, L"rb+")) != nullptr)
|
||||
{
|
||||
if (verifyRecordingFileHeader())
|
||||
{
|
||||
filename = path;
|
||||
return true;
|
||||
}
|
||||
Close();
|
||||
InputRec::consoleLog("Input recording file header is invalid");
|
||||
return false;
|
||||
}
|
||||
InputRec::consoleLog(fmt::format("Input recording file opening failed. Error - {}", strerror(errno)));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InputRecordingFile::OpenNew(const wxString& path, bool fromSavestate)
|
||||
{
|
||||
if (!open(path, true))
|
||||
return false;
|
||||
savestate.fromSavestate = fromSavestate;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputRecordingFile::OpenExisting(const wxString& path)
|
||||
{
|
||||
return open(path, false);
|
||||
}
|
||||
|
||||
bool InputRecordingFile::ReadKeyBuffer(u8& result, const uint& frame, const uint port, const uint bufIndex)
|
||||
{
|
||||
if (recordingFile == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long seek = getRecordingBlockSeekPoint(frame) + controllerInputBytes * port + bufIndex;
|
||||
if (fseek(recordingFile, seek, SEEK_SET) != 0 || fread(&result, 1, 1, recordingFile) != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputRecordingFile::SetTotalFrames(long frame)
|
||||
{
|
||||
if (recordingFile == nullptr || totalFrames >= frame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
totalFrames = frame;
|
||||
fseek(recordingFile, seekpointTotalFrames, SEEK_SET);
|
||||
fwrite(&totalFrames, 4, 1, recordingFile);
|
||||
}
|
||||
|
||||
bool InputRecordingFile::WriteHeader()
|
||||
{
|
||||
if (recordingFile == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rewind(recordingFile);
|
||||
if (fwrite(&header, sizeof(InputRecordingFileHeader), 1, recordingFile) != 1 || fwrite(&totalFrames, 4, 1, recordingFile) != 1 || fwrite(&undoCount, 4, 1, recordingFile) != 1 || fwrite(&savestate, 1, 1, recordingFile) != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputRecordingFile::WriteKeyBuffer(const uint& frame, const uint port, const uint bufIndex, const u8& buf)
|
||||
{
|
||||
if (recordingFile == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long seek = getRecordingBlockSeekPoint(frame) + 18 * port + bufIndex;
|
||||
|
||||
if (fseek(recordingFile, seek, SEEK_SET) != 0 || fwrite(&buf, 1, 1, recordingFile) != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fflush(recordingFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
long InputRecordingFile::getRecordingBlockSeekPoint(const long& frame)
|
||||
{
|
||||
return headerSize + sizeof(bool) + frame * inputBytesPerFrame;
|
||||
}
|
||||
|
||||
bool InputRecordingFile::verifyRecordingFileHeader()
|
||||
{
|
||||
if (recordingFile == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Verify header contents
|
||||
rewind(recordingFile);
|
||||
if (fread(&header, sizeof(InputRecordingFileHeader), 1, recordingFile) != 1 || fread(&totalFrames, 4, 1, recordingFile) != 1 || fread(&undoCount, 4, 1, recordingFile) != 1 || fread(&savestate.fromSavestate, sizeof(bool), 1, recordingFile) != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for current verison
|
||||
if (header.version != 1)
|
||||
{
|
||||
InputRec::consoleLog(fmt::format("Input recording file is not a supported version - {}", header.version));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "InputRecordingFile.h"
|
||||
|
||||
#include "Utilities/InputRecordingLogger.h"
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
// TODO - Vaser - kill with wxWidgets
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
#include "System.h"
|
||||
#include "PadData.h"
|
||||
|
@ -24,103 +23,6 @@
|
|||
// NOTE / TODOs for Version 2
|
||||
// - Move fromSavestate, undoCount, and total frames into the header
|
||||
|
||||
struct InputRecordingFileHeader
|
||||
{
|
||||
u8 version = 1;
|
||||
char emu[50] = "";
|
||||
char author[255] = "";
|
||||
char gameName[255] = "";
|
||||
|
||||
public:
|
||||
void SetEmulatorVersion();
|
||||
void Init();
|
||||
void SetAuthor(wxString author);
|
||||
void SetGameName(wxString cdrom);
|
||||
};
|
||||
|
||||
|
||||
// DEPRECATED / Slated for Removal
|
||||
struct InputRecordingSavestate
|
||||
{
|
||||
// Whether we start from the savestate or from power-on
|
||||
bool fromSavestate = false;
|
||||
};
|
||||
|
||||
// Handles all operations on the input recording file
|
||||
class InputRecordingFile
|
||||
{
|
||||
public:
|
||||
~InputRecordingFile() { Close(); }
|
||||
|
||||
// Closes the underlying input recording file, writing the header and
|
||||
// prepares for a possible new recording to be started
|
||||
bool Close();
|
||||
// Retrieve the input recording's filename (not the path)
|
||||
const wxString& GetFilename();
|
||||
// Retrieve the input recording's header which contains high-level metadata on the recording
|
||||
InputRecordingFileHeader& GetHeader();
|
||||
// The maximum number of frames, or in other words, the length of the recording
|
||||
long& GetTotalFrames();
|
||||
// The number of times a save-state has been loaded while recording this movie
|
||||
// this is also often referred to as a "re-record"
|
||||
unsigned long& GetUndoCount();
|
||||
// Whether or not this input recording starts by loading a save-state or by booting the game fresh
|
||||
bool FromSaveState();
|
||||
// Increment the number of undo actions and commit it to the recording file
|
||||
void IncrementUndoCount();
|
||||
// Open an existing recording file
|
||||
bool OpenExisting(const wxString& path);
|
||||
// Create and open a brand new input recording, either starting from a save-state or from
|
||||
// booting the game
|
||||
bool OpenNew(const wxString& path, bool fromSaveState);
|
||||
// Reads the current frame's input data from the file in order to intercept and overwrite
|
||||
// the current frame's value from the emulator
|
||||
bool ReadKeyBuffer(u8& result, const uint& frame, const uint port, const uint bufIndex);
|
||||
// Updates the total frame counter and commit it to the recording file
|
||||
void SetTotalFrames(long frames);
|
||||
// Persist the input recording file header's current state to the file
|
||||
bool WriteHeader();
|
||||
// Writes the current frame's input data to the file so it can be replayed
|
||||
bool WriteKeyBuffer(const uint& frame, const uint port, const uint bufIndex, const u8& buf);
|
||||
|
||||
private:
|
||||
static const int controllerPortsSupported = 2;
|
||||
static const int controllerInputBytes = 18;
|
||||
static const int inputBytesPerFrame = controllerInputBytes * controllerPortsSupported;
|
||||
// TODO - version 2, this could be greatly simplified if everything was in the header
|
||||
// + 4 + 4 is the totalFrame and undoCount values
|
||||
static const int headerSize = sizeof(InputRecordingFileHeader) + 4 + 4;
|
||||
// DEPRECATED / Slated for Removal
|
||||
static const int recordingSavestateHeaderSize = sizeof(bool);
|
||||
static const int seekpointTotalFrames = sizeof(InputRecordingFileHeader);
|
||||
static const int seekpointUndoCount = sizeof(InputRecordingFileHeader) + 4;
|
||||
static const int seekpointSaveStateHeader = seekpointUndoCount + 4;
|
||||
|
||||
InputRecordingFileHeader header;
|
||||
wxString filename = "";
|
||||
FILE* recordingFile = nullptr;
|
||||
InputRecordingSavestate savestate;
|
||||
|
||||
// An signed 32-bit frame limit is equivalent to 1.13 years of continuous 60fps footage
|
||||
long totalFrames = 0;
|
||||
unsigned long undoCount = 0;
|
||||
|
||||
// Calculates the position of the current frame in the input recording
|
||||
long getRecordingBlockSeekPoint(const long& frame);
|
||||
bool open(const wxString path, bool newRecording);
|
||||
bool verifyRecordingFileHeader();
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#include "System.h"
|
||||
#include "PadData.h"
|
||||
|
||||
// NOTE / TODOs for Version 2
|
||||
// - Move fromSavestate, undoCount, and total frames into the header
|
||||
|
||||
|
||||
|
||||
// Handles all operations on the input recording file
|
||||
class InputRecordingFile
|
||||
{
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// This file dies along with wxWidgets
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "NewRecordingFrame.h"
|
||||
|
||||
#include <wx/gbsizer.h>
|
||||
|
||||
NewRecordingFrame::NewRecordingFrame(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, "New Input Recording", wxDefaultPosition, wxDefaultSize, wxSTAY_ON_TOP | wxCLOSE_BOX | wxCAPTION)
|
||||
{
|
||||
m_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _("panel"));
|
||||
|
||||
wxGridBagSizer* gbs = new wxGridBagSizer(20, 20);
|
||||
gbs->SetFlexibleDirection(wxBOTH);
|
||||
gbs->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
|
||||
wxBoxSizer* container = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
m_fileLabel = new wxStaticText(m_panel, wxID_ANY, _("File Path"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
||||
m_authorLabel = new wxStaticText(m_panel, wxID_ANY, _("Author"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
||||
m_fromLabel = new wxStaticText(m_panel, wxID_ANY, _("Record From"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
||||
|
||||
m_filePicker = new wxFilePickerCtrl(m_panel, MenuIds_New_Recording_Frame_File, wxEmptyString, "File", L"p2m2 file(*.p2m2)|*.p2m2", wxDefaultPosition, wxDefaultSize, wxFLP_SAVE | wxFLP_OVERWRITE_PROMPT | wxFLP_USE_TEXTCTRL);
|
||||
m_authorInput = new wxTextCtrl(m_panel, MenuIds_New_Recording_Frame_Author, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||
m_fromChoice = new wxChoice(m_panel, MenuIds_New_Recording_Frame_From, wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
m_savestate_label =
|
||||
_("Be Warned! Basing an input recording off a savestate can be a mistake as savestates can break across emulator versions. Be prepared to be stuck to an emulator version or have to re-create your starting savestate in a later version.");
|
||||
m_warning_label = new wxStaticText(m_panel, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
||||
m_warning_label->SetForegroundColour(wxColor(*wxRED));
|
||||
|
||||
m_startRecording = new wxButton(m_panel, wxID_OK, _("Browse Required"), wxDefaultPosition, wxDefaultSize);
|
||||
m_startRecording->Enable(false);
|
||||
m_cancelRecording = new wxButton(m_panel, wxID_CANCEL, _("Cancel"), wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
gbs->Add(m_fileLabel, wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
gbs->Add(m_filePicker, wxGBPosition(0, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
gbs->Add(m_authorLabel, wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
gbs->Add(m_authorInput, wxGBPosition(1, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
gbs->Add(m_fromLabel, wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
gbs->Add(m_fromChoice, wxGBPosition(2, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxEXPAND);
|
||||
|
||||
gbs->Add(m_warning_label, wxGBPosition(3, 0), wxGBSpan(1, 2), wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
gbs->Add(m_startRecording, wxGBPosition(4, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
gbs->Add(m_cancelRecording, wxGBPosition(4, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
gbs->AddGrowableCol(0);
|
||||
gbs->AddGrowableCol(1);
|
||||
gbs->AddGrowableRow(3);
|
||||
|
||||
container->Add(gbs, 1, wxALL | wxEXPAND, 15);
|
||||
m_panel->SetSizer(container);
|
||||
m_panel->GetSizer()->Fit(this);
|
||||
Centre();
|
||||
|
||||
m_fileBrowsed = false;
|
||||
m_filePicker->GetPickerCtrl()->Bind(wxEVT_FILEPICKER_CHANGED, &NewRecordingFrame::OnFileDirChange, this);
|
||||
m_filePicker->Bind(wxEVT_FILEPICKER_CHANGED, &NewRecordingFrame::OnFileChanged, this);
|
||||
m_fromChoice->Bind(wxEVT_CHOICE, &NewRecordingFrame::OnRecordingTypeChoiceChanged, this);
|
||||
}
|
||||
|
||||
int NewRecordingFrame::ShowModal(const bool isCoreThreadOpen)
|
||||
{
|
||||
static const char* choices[2] = {"Boot", "Current Frame"};
|
||||
m_fromChoice->Set(wxArrayString(1 + isCoreThreadOpen, &choices[0]));
|
||||
m_fromChoice->SetSelection(isCoreThreadOpen);
|
||||
if (m_fromChoice->GetSelection() == 1)
|
||||
{
|
||||
m_warning_label->SetLabel(m_savestate_label);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_warning_label->SetLabel("");
|
||||
}
|
||||
m_warning_label->Wrap(GetClientSize().GetWidth());
|
||||
m_panel->GetSizer()->Fit(this);
|
||||
return wxDialog::ShowModal();
|
||||
}
|
||||
|
||||
void NewRecordingFrame::OnFileDirChange(wxFileDirPickerEvent& event)
|
||||
{
|
||||
m_filePicker->wxFileDirPickerCtrlBase::OnFileDirChange(event);
|
||||
m_fileBrowsed = true;
|
||||
EnableOkBox();
|
||||
}
|
||||
|
||||
void NewRecordingFrame::OnFileChanged(wxFileDirPickerEvent& event)
|
||||
{
|
||||
EnableOkBox();
|
||||
}
|
||||
|
||||
void NewRecordingFrame::OnRecordingTypeChoiceChanged(wxCommandEvent& event)
|
||||
{
|
||||
if (m_fromChoice->GetSelection() == 1)
|
||||
{
|
||||
m_warning_label->SetLabel(m_savestate_label);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_warning_label->SetLabel("");
|
||||
}
|
||||
m_warning_label->Wrap(GetClientSize().GetWidth());
|
||||
m_panel->GetSizer()->Fit(this);
|
||||
}
|
||||
|
||||
void NewRecordingFrame::EnableOkBox()
|
||||
{
|
||||
if (m_filePicker->GetPath().length() == 0)
|
||||
{
|
||||
m_fileBrowsed = false;
|
||||
m_startRecording->SetLabel(_("Browse Required"));
|
||||
m_startRecording->Enable(false);
|
||||
}
|
||||
else if (m_fileBrowsed)
|
||||
{
|
||||
m_startRecording->SetLabel(_("Start"));
|
||||
m_startRecording->Enable(true);
|
||||
}
|
||||
}
|
||||
|
||||
wxString NewRecordingFrame::GetFile() const
|
||||
{
|
||||
wxString path = m_filePicker->GetPath();
|
||||
// wxWidget's removes the extension if it contains wildcards
|
||||
// on wxGTK https://trac.wxwidgets.org/ticket/15285
|
||||
if (!path.EndsWith(".p2m2"))
|
||||
{
|
||||
return wxString::Format("%s.p2m2", path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
wxString NewRecordingFrame::GetAuthor() const
|
||||
{
|
||||
return m_authorInput->GetValue();
|
||||
}
|
||||
|
||||
int NewRecordingFrame::GetFrom() const
|
||||
{
|
||||
return m_fromChoice->GetSelection();
|
||||
}
|
||||
#endif
|
|
@ -1,61 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/filepicker.h>
|
||||
|
||||
enum MenuIds_New_Recording_Frame
|
||||
{
|
||||
MenuIds_New_Recording_Frame_File = 0,
|
||||
MenuIds_New_Recording_Frame_Author,
|
||||
MenuIds_New_Recording_Frame_From
|
||||
};
|
||||
|
||||
// The Dialog to pop-up when recording a new movie
|
||||
class NewRecordingFrame : public wxDialog
|
||||
{
|
||||
public:
|
||||
NewRecordingFrame(wxWindow* parent);
|
||||
int ShowModal(const bool isCoreThreadOpen);
|
||||
|
||||
wxString GetFile() const;
|
||||
wxString GetAuthor() const;
|
||||
int GetFrom() const;
|
||||
|
||||
protected:
|
||||
void OnFileDirChange(wxFileDirPickerEvent& event);
|
||||
void OnFileChanged(wxFileDirPickerEvent& event);
|
||||
void OnRecordingTypeChoiceChanged(wxCommandEvent& event);
|
||||
void EnableOkBox();
|
||||
|
||||
private:
|
||||
wxPanel* m_panel;
|
||||
wxStaticText* m_fileLabel;
|
||||
wxFilePickerCtrl* m_filePicker;
|
||||
bool m_fileBrowsed;
|
||||
wxStaticText* m_authorLabel;
|
||||
wxTextCtrl* m_authorInput;
|
||||
wxStaticText* m_fromLabel;
|
||||
wxChoice* m_fromChoice;
|
||||
wxButton* m_startRecording;
|
||||
wxButton* m_cancelRecording;
|
||||
wxString m_savestate_label;
|
||||
wxStaticText* m_warning_label;
|
||||
};
|
||||
#endif
|
|
@ -13,199 +13,13 @@
|
|||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "Recording/PadData.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
void PadData::UpdateControllerData(u16 bufIndex, u8 const& bufVal)
|
||||
{
|
||||
const BufferIndex index = static_cast<BufferIndex>(bufIndex);
|
||||
switch (index)
|
||||
{
|
||||
case BufferIndex::PressedFlagsGroupOne:
|
||||
leftPressed = IsButtonPressed(LEFT, bufVal);
|
||||
downPressed = IsButtonPressed(DOWN, bufVal);
|
||||
rightPressed = IsButtonPressed(RIGHT, bufVal);
|
||||
upPressed = IsButtonPressed(UP, bufVal);
|
||||
start = IsButtonPressed(START, bufVal);
|
||||
r3 = IsButtonPressed(R3, bufVal);
|
||||
l3 = IsButtonPressed(L3, bufVal);
|
||||
select = IsButtonPressed(SELECT, bufVal);
|
||||
break;
|
||||
case BufferIndex::PressedFlagsGroupTwo:
|
||||
squarePressed = IsButtonPressed(SQUARE, bufVal);
|
||||
crossPressed = IsButtonPressed(CROSS, bufVal);
|
||||
circlePressed = IsButtonPressed(CIRCLE, bufVal);
|
||||
trianglePressed = IsButtonPressed(TRIANGLE, bufVal);
|
||||
r1Pressed = IsButtonPressed(R1, bufVal);
|
||||
l1Pressed = IsButtonPressed(L1, bufVal);
|
||||
r2Pressed = IsButtonPressed(R2, bufVal);
|
||||
l2Pressed = IsButtonPressed(L2, bufVal);
|
||||
break;
|
||||
case BufferIndex::RightAnalogXVector:
|
||||
rightAnalogX = bufVal;
|
||||
break;
|
||||
case BufferIndex::RightAnalogYVector:
|
||||
rightAnalogY = bufVal;
|
||||
break;
|
||||
case BufferIndex::LeftAnalogXVector:
|
||||
leftAnalogX = bufVal;
|
||||
break;
|
||||
case BufferIndex::LeftAnalogYVector:
|
||||
leftAnalogY = bufVal;
|
||||
break;
|
||||
case BufferIndex::RightPressure:
|
||||
rightPressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::LeftPressure:
|
||||
leftPressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::UpPressure:
|
||||
upPressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::DownPressure:
|
||||
downPressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::TrianglePressure:
|
||||
trianglePressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::CirclePressure:
|
||||
circlePressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::CrossPressure:
|
||||
crossPressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::SquarePressure:
|
||||
squarePressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::L1Pressure:
|
||||
l1Pressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::R1Pressure:
|
||||
r1Pressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::L2Pressure:
|
||||
l2Pressure = bufVal;
|
||||
break;
|
||||
case BufferIndex::R2Pressure:
|
||||
r2Pressure = bufVal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u8 PadData::PollControllerData(u16 bufIndex)
|
||||
{
|
||||
u8 byte = 0;
|
||||
const BufferIndex index = static_cast<BufferIndex>(bufIndex);
|
||||
switch (index)
|
||||
{
|
||||
case BufferIndex::PressedFlagsGroupOne:
|
||||
// Construct byte by combining flags if the buttons are pressed
|
||||
byte |= BitmaskOrZero(leftPressed, LEFT);
|
||||
byte |= BitmaskOrZero(downPressed, DOWN);
|
||||
byte |= BitmaskOrZero(rightPressed, RIGHT);
|
||||
byte |= BitmaskOrZero(upPressed, UP);
|
||||
byte |= BitmaskOrZero(start, START);
|
||||
byte |= BitmaskOrZero(r3, R3);
|
||||
byte |= BitmaskOrZero(l3, L3);
|
||||
byte |= BitmaskOrZero(select, SELECT);
|
||||
// We flip the bits because as mentioned below, 0 = pressed
|
||||
return ~byte;
|
||||
case BufferIndex::PressedFlagsGroupTwo:
|
||||
// Construct byte by combining flags if the buttons are pressed
|
||||
byte |= BitmaskOrZero(squarePressed, SQUARE);
|
||||
byte |= BitmaskOrZero(crossPressed, CROSS);
|
||||
byte |= BitmaskOrZero(circlePressed, CIRCLE);
|
||||
byte |= BitmaskOrZero(trianglePressed, TRIANGLE);
|
||||
byte |= BitmaskOrZero(r1Pressed, R1);
|
||||
byte |= BitmaskOrZero(l1Pressed, L1);
|
||||
byte |= BitmaskOrZero(r2Pressed, R2);
|
||||
byte |= BitmaskOrZero(l2Pressed, L2);
|
||||
// We flip the bits because as mentioned below, 0 = pressed
|
||||
return ~byte;
|
||||
case BufferIndex::RightAnalogXVector:
|
||||
return rightAnalogX;
|
||||
case BufferIndex::RightAnalogYVector:
|
||||
return rightAnalogY;
|
||||
case BufferIndex::LeftAnalogXVector:
|
||||
return leftAnalogX;
|
||||
case BufferIndex::LeftAnalogYVector:
|
||||
return leftAnalogY;
|
||||
case BufferIndex::RightPressure:
|
||||
return rightPressure;
|
||||
case BufferIndex::LeftPressure:
|
||||
return leftPressure;
|
||||
case BufferIndex::UpPressure:
|
||||
return upPressure;
|
||||
case BufferIndex::DownPressure:
|
||||
return downPressure;
|
||||
case BufferIndex::TrianglePressure:
|
||||
return trianglePressure;
|
||||
case BufferIndex::CirclePressure:
|
||||
return circlePressure;
|
||||
case BufferIndex::CrossPressure:
|
||||
return crossPressure;
|
||||
case BufferIndex::SquarePressure:
|
||||
return squarePressure;
|
||||
case BufferIndex::L1Pressure:
|
||||
return l1Pressure;
|
||||
case BufferIndex::R1Pressure:
|
||||
return r1Pressure;
|
||||
case BufferIndex::L2Pressure:
|
||||
return l2Pressure;
|
||||
case BufferIndex::R2Pressure:
|
||||
return r2Pressure;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool PadData::IsButtonPressed(ButtonResolver buttonResolver, u8 const& bufVal)
|
||||
{
|
||||
// Rather than the flags being SET if the button is pressed, it is the opposite
|
||||
// For example: 0111 1111 with `left` being the first bit indicates `left` is pressed.
|
||||
// So, we are forced to flip the pressed bits with a NOT first
|
||||
return (~bufVal & buttonResolver.buttonBitmask) > 0;
|
||||
}
|
||||
|
||||
u8 PadData::BitmaskOrZero(bool pressed, ButtonResolver buttonInfo)
|
||||
{
|
||||
return pressed ? buttonInfo.buttonBitmask : 0;
|
||||
}
|
||||
|
||||
// TODO - Vaser - kill with wxWidgets
|
||||
// TODO - Vaser - replace with this something better in Qt
|
||||
wxString PadData::RawPadBytesToString(int start, int end)
|
||||
{
|
||||
wxString str;
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
str += wxString::Format("%d", PollControllerData(i));
|
||||
if (i != end - 1)
|
||||
str += ", ";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void PadData::LogPadData(u8 const& port)
|
||||
{
|
||||
wxString pressedBytes = RawPadBytesToString(0, 2);
|
||||
wxString rightAnalogBytes = RawPadBytesToString(2, 4);
|
||||
wxString leftAnalogBytes = RawPadBytesToString(4, 6);
|
||||
wxString pressureBytes = RawPadBytesToString(6, 17);
|
||||
wxString fullLog =
|
||||
wxString::Format("[PAD %d] Raw Bytes: Pressed = [%s]\n", port + 1, pressedBytes) +
|
||||
wxString::Format("[PAD %d] Raw Bytes: Right Analog = [%s]\n", port + 1, rightAnalogBytes) +
|
||||
wxString::Format("[PAD %d] Raw Bytes: Left Analog = [%s]\n", port + 1, leftAnalogBytes) +
|
||||
wxString::Format("[PAD %d] Raw Bytes: Pressure = [%s]\n", port + 1, pressureBytes);
|
||||
controlLog(fullLog.ToUTF8());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "PAD/Host/KeyStatus.h"
|
||||
|
|
|
@ -15,121 +15,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
class PadData
|
||||
{
|
||||
public:
|
||||
/// Constants
|
||||
static const u8 ANALOG_VECTOR_NEUTRAL = 127;
|
||||
|
||||
enum class BufferIndex
|
||||
{
|
||||
PressedFlagsGroupOne,
|
||||
PressedFlagsGroupTwo,
|
||||
RightAnalogXVector,
|
||||
RightAnalogYVector,
|
||||
LeftAnalogXVector,
|
||||
LeftAnalogYVector,
|
||||
RightPressure,
|
||||
LeftPressure,
|
||||
UpPressure,
|
||||
DownPressure,
|
||||
TrianglePressure,
|
||||
CirclePressure,
|
||||
CrossPressure,
|
||||
SquarePressure,
|
||||
L1Pressure,
|
||||
R1Pressure,
|
||||
L2Pressure,
|
||||
R2Pressure
|
||||
};
|
||||
|
||||
/// Pressure Buttons - 0-255
|
||||
u8 circlePressure = 0;
|
||||
u8 crossPressure = 0;
|
||||
u8 squarePressure = 0;
|
||||
u8 trianglePressure = 0;
|
||||
u8 downPressure = 0;
|
||||
u8 leftPressure = 0;
|
||||
u8 rightPressure = 0;
|
||||
u8 upPressure = 0;
|
||||
u8 l1Pressure = 0;
|
||||
u8 l2Pressure = 0;
|
||||
u8 r1Pressure = 0;
|
||||
u8 r2Pressure = 0;
|
||||
|
||||
/// Pressure Button Flags
|
||||
/// NOTE - It shouldn't be possible to depress a button while also having no pressure
|
||||
/// But for the sake of completeness, it should be tracked.
|
||||
bool circlePressed = false;
|
||||
bool crossPressed = false;
|
||||
bool squarePressed = false;
|
||||
bool trianglePressed = false;
|
||||
bool downPressed = false;
|
||||
bool leftPressed = false;
|
||||
bool rightPressed = false;
|
||||
bool upPressed = false;
|
||||
bool l1Pressed = false;
|
||||
bool l2Pressed = false;
|
||||
bool r1Pressed = false;
|
||||
bool r2Pressed = false;
|
||||
|
||||
/// Normal (un)pressed buttons
|
||||
bool select = false;
|
||||
bool start = false;
|
||||
bool l3 = false;
|
||||
bool r3 = false;
|
||||
|
||||
/// Analog Sticks - 0-255 (127 center)
|
||||
u8 leftAnalogX = ANALOG_VECTOR_NEUTRAL;
|
||||
u8 leftAnalogY = ANALOG_VECTOR_NEUTRAL;
|
||||
u8 rightAnalogX = ANALOG_VECTOR_NEUTRAL;
|
||||
u8 rightAnalogY = ANALOG_VECTOR_NEUTRAL;
|
||||
|
||||
// Given the input buffer and the current index, updates the correct field(s)
|
||||
void UpdateControllerData(u16 bufIndex, u8 const& bufVal);
|
||||
u8 PollControllerData(u16 bufIndex);
|
||||
|
||||
// Prints current PadData to the Controller Log filter which disabled by default
|
||||
void LogPadData(u8 const& port);
|
||||
|
||||
private:
|
||||
struct ButtonResolver
|
||||
{
|
||||
u8 buttonBitmask;
|
||||
};
|
||||
|
||||
const ButtonResolver LEFT = ButtonResolver{0b10000000};
|
||||
const ButtonResolver DOWN = ButtonResolver{0b01000000};
|
||||
const ButtonResolver RIGHT = ButtonResolver{0b00100000};
|
||||
const ButtonResolver UP = ButtonResolver{0b00010000};
|
||||
const ButtonResolver START = ButtonResolver{0b00001000};
|
||||
const ButtonResolver R3 = ButtonResolver{0b00000100};
|
||||
const ButtonResolver L3 = ButtonResolver{0b00000010};
|
||||
const ButtonResolver SELECT = ButtonResolver{0b00000001};
|
||||
|
||||
const ButtonResolver SQUARE = ButtonResolver{0b10000000};
|
||||
const ButtonResolver CROSS = ButtonResolver{0b01000000};
|
||||
const ButtonResolver CIRCLE = ButtonResolver{0b00100000};
|
||||
const ButtonResolver TRIANGLE = ButtonResolver{0b00010000};
|
||||
const ButtonResolver R1 = ButtonResolver{0b00001000};
|
||||
const ButtonResolver L1 = ButtonResolver{0b00000100};
|
||||
const ButtonResolver R2 = ButtonResolver{0b00000010};
|
||||
const ButtonResolver L2 = ButtonResolver{0b00000001};
|
||||
|
||||
// Checks and returns if button a is pressed or not
|
||||
bool IsButtonPressed(ButtonResolver buttonResolver, u8 const& bufVal);
|
||||
u8 BitmaskOrZero(bool pressed, ButtonResolver buttonInfo);
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
wxString RawPadBytesToString(int start, int end);
|
||||
#else
|
||||
std::string RawPadBytesToString(int start, int end);
|
||||
#endif
|
||||
};
|
||||
|
||||
#else
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
class PadData
|
||||
{
|
||||
|
@ -180,12 +66,6 @@ public:
|
|||
|
||||
// Prints current PadData to the Controller Log filter which is disabled by default
|
||||
void LogPadData() const;
|
||||
|
||||
private:
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
wxString RawPadBytesToString(int start, int end);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,438 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "gui/App.h"
|
||||
#include "gui/MSWstuff.h"
|
||||
#include "gui/EmbeddedImage.h"
|
||||
#include "wx/dcbuffer.h"
|
||||
#include "wx/display.h"
|
||||
#include "wx/spinctrl.h"
|
||||
|
||||
#include "Recording/VirtualPad/VirtualPad.h"
|
||||
#include "Recording/VirtualPad/VirtualPadResources.h"
|
||||
|
||||
#include "Recording/VirtualPad/img/circlePressed.h"
|
||||
#include "Recording/VirtualPad/img/controllerFull.h"
|
||||
#include "Recording/VirtualPad/img/controllerThreeQuarters.h"
|
||||
#include "Recording/VirtualPad/img/controllerHalf.h"
|
||||
#include "Recording/VirtualPad/img/crossPressed.h"
|
||||
#include "Recording/VirtualPad/img/downPressed.h"
|
||||
#include "Recording/VirtualPad/img/l1Pressed.h"
|
||||
#include "Recording/VirtualPad/img/l2Pressed.h"
|
||||
#include "Recording/VirtualPad/img/l3Pressed.h"
|
||||
#include "Recording/VirtualPad/img/leftPressed.h"
|
||||
#include "Recording/VirtualPad/img/r1Pressed.h"
|
||||
#include "Recording/VirtualPad/img/r2Pressed.h"
|
||||
#include "Recording/VirtualPad/img/r3Pressed.h"
|
||||
#include "Recording/VirtualPad/img/rightPressed.h"
|
||||
#include "Recording/VirtualPad/img/selectPressed.h"
|
||||
#include "Recording/VirtualPad/img/squarePressed.h"
|
||||
#include "Recording/VirtualPad/img/startPressed.h"
|
||||
#include "Recording/VirtualPad/img/trianglePressed.h"
|
||||
#include "Recording/VirtualPad/img/upPressed.h"
|
||||
|
||||
|
||||
VirtualPad::VirtualPad(wxWindow* parent, int controllerPort, AppConfig::InputRecordingOptions& options)
|
||||
: wxFrame(parent, wxID_ANY, wxEmptyString)
|
||||
, options(options)
|
||||
{
|
||||
// Images at 1.00 scale are designed to work well on HiDPI (4k) at 150% scaling (default recommended setting on windows)
|
||||
// Therefore, on a 1080p monitor we halve the scaling, on 1440p we reduce it by 25%, which from some quick tests looks comparable
|
||||
// Side-note - Getting the DPI scaling amount is platform specific (with some platforms only supporting
|
||||
// integer scaling as well) this is likely not reliable.
|
||||
// Slight multi-monitor support, will use whatever window pcsx2 is opened with, but won't currently re-init if
|
||||
// windows are dragged between differing monitors!
|
||||
wxDisplay display(wxDisplay::GetFromWindow(this));
|
||||
const wxRect screen = display.GetClientArea();
|
||||
float dpiScale = MSW_GetDPIScale(); // linux returns 1.0
|
||||
if (screen.height > 1080 && screen.height <= 1440) // 1440p display
|
||||
scalingFactor = 0.75 * dpiScale;
|
||||
else if (screen.height <= 1080) // 1080p display
|
||||
{
|
||||
scalingFactor = 0.5 * dpiScale;
|
||||
}
|
||||
// otherwise use default 1.0 scaling
|
||||
|
||||
virtualPadData = VirtualPadData();
|
||||
// Based on the scaling factor, select the appropriate background image
|
||||
// Don't scale these images as they've already been pre-scaled
|
||||
if (floatCompare(scalingFactor, 0.5))
|
||||
virtualPadData.background = NewBitmap(EmbeddedImage<res_controllerHalf>().Get(), wxPoint(0, 0), true);
|
||||
else if (floatCompare(scalingFactor, 0.75))
|
||||
virtualPadData.background = NewBitmap(EmbeddedImage<res_controllerThreeQuarters>().Get(), wxPoint(0, 0), true);
|
||||
else
|
||||
// Otherwise, scale down/up (or don't in the case of 1.0) the largst image
|
||||
virtualPadData.background = NewBitmap(EmbeddedImage<res_controllerFull>().Get(), wxPoint(0, 0));
|
||||
|
||||
// Use the background image's size to define the window size
|
||||
SetClientSize(virtualPadData.background.width, virtualPadData.background.height);
|
||||
|
||||
// These hard-coded pixels correspond to where the background image's components are (ie. the buttons)
|
||||
// Everything is automatically scaled and adjusted based on the `scalingFactor` variable
|
||||
InitPressureButtonGuiElements(virtualPadData.square, NewBitmap(EmbeddedImage<res_squarePressed>().Get(), wxPoint(852, 287)), this, wxPoint(1055, 525));
|
||||
InitPressureButtonGuiElements(virtualPadData.triangle, NewBitmap(EmbeddedImage<res_trianglePressed>().Get(), wxPoint(938, 201)), this, wxPoint(1055, 565));
|
||||
InitPressureButtonGuiElements(virtualPadData.circle, NewBitmap(EmbeddedImage<res_circlePressed>().Get(), wxPoint(1024, 286)), this, wxPoint(1055, 605));
|
||||
InitPressureButtonGuiElements(virtualPadData.cross, NewBitmap(EmbeddedImage<res_crossPressed>().Get(), wxPoint(938, 369)), this, wxPoint(1055, 645));
|
||||
|
||||
InitPressureButtonGuiElements(virtualPadData.left, NewBitmap(EmbeddedImage<res_leftPressed>().Get(), wxPoint(110, 303)), this, wxPoint(175, 525), true);
|
||||
InitPressureButtonGuiElements(virtualPadData.up, NewBitmap(EmbeddedImage<res_upPressed>().Get(), wxPoint(186, 227)), this, wxPoint(175, 565), true);
|
||||
InitPressureButtonGuiElements(virtualPadData.right, NewBitmap(EmbeddedImage<res_rightPressed>().Get(), wxPoint(248, 302)), this, wxPoint(175, 605), true);
|
||||
InitPressureButtonGuiElements(virtualPadData.down, NewBitmap(EmbeddedImage<res_downPressed>().Get(), wxPoint(186, 359)), this, wxPoint(175, 645), true);
|
||||
|
||||
InitPressureButtonGuiElements(virtualPadData.l1, NewBitmap(EmbeddedImage<res_l1Pressed>().Get(), wxPoint(156, 98)), this, wxPoint(170, 135));
|
||||
InitPressureButtonGuiElements(virtualPadData.l2, NewBitmap(EmbeddedImage<res_l2Pressed>().Get(), wxPoint(156, 57)), this, wxPoint(170, 52), false, true);
|
||||
InitPressureButtonGuiElements(virtualPadData.r1, NewBitmap(EmbeddedImage<res_r1Pressed>().Get(), wxPoint(921, 98)), this, wxPoint(1035, 135), true);
|
||||
InitPressureButtonGuiElements(virtualPadData.r2, NewBitmap(EmbeddedImage<res_r2Pressed>().Get(), wxPoint(921, 57)), this, wxPoint(1035, 52), true, true);
|
||||
|
||||
InitNormalButtonGuiElements(virtualPadData.select, NewBitmap(EmbeddedImage<res_selectPressed>().Get(), wxPoint(458, 313)), this, wxPoint(530, 315));
|
||||
InitNormalButtonGuiElements(virtualPadData.start, NewBitmap(EmbeddedImage<res_startPressed>().Get(), wxPoint(688, 311)), this, wxPoint(646, 315));
|
||||
InitNormalButtonGuiElements(virtualPadData.l3, NewBitmap(EmbeddedImage<res_l3Pressed>().Get(), wxPoint(336, 453)), this, wxPoint(560, 638));
|
||||
InitNormalButtonGuiElements(virtualPadData.r3, NewBitmap(EmbeddedImage<res_r3Pressed>().Get(), wxPoint(726, 453)), this, wxPoint(615, 638));
|
||||
|
||||
InitAnalogStickGuiElements(virtualPadData.leftAnalog, this, wxPoint(404, 522), 100, wxPoint(314, 642), wxPoint(526, 432), false, wxPoint(504, 685), wxPoint(570, 425), true);
|
||||
InitAnalogStickGuiElements(virtualPadData.rightAnalog, this, wxPoint(794, 522), 100, wxPoint(706, 642), wxPoint(648, 432), true, wxPoint(700, 685), wxPoint(635, 425));
|
||||
|
||||
ignoreRealControllerBox = new wxCheckBox(this, wxID_ANY, wxEmptyString, ScaledPoint(wxPoint(586, 135)), wxDefaultSize);
|
||||
resetButton = new wxButton(this, wxID_ANY, _("Reset"), ScaledPoint(wxPoint(1195, 5), wxSize(100, 50), true), ScaledSize(wxSize(100, 50)));
|
||||
|
||||
Bind(wxEVT_CHECKBOX, &VirtualPad::OnIgnoreRealController, this, ignoreRealControllerBox->GetId());
|
||||
Bind(wxEVT_BUTTON, &VirtualPad::OnResetButton, this, resetButton->GetId());
|
||||
|
||||
// Bind Window Events
|
||||
Bind(wxEVT_MOVE, &VirtualPad::OnMoveAround, this);
|
||||
Bind(wxEVT_CLOSE_WINDOW, &VirtualPad::OnClose, this);
|
||||
Bind(wxEVT_ICONIZE, &VirtualPad::OnIconize, this);
|
||||
Bind(wxEVT_ERASE_BACKGROUND, &VirtualPad::OnEraseBackground, this);
|
||||
// Temporary Paint event handler so the window displays properly before the controller-interrupt routine takes over with manual drawing.
|
||||
// The reason for this is in order to minimize the performance impact, we need total control over when render is called
|
||||
// Windows redraws the window _alot_ otherwise which leads to major performance problems (when GS is using the software renderer)
|
||||
Bind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
|
||||
// DevCon.WriteLn("Paint Event Bound");
|
||||
|
||||
// Finalize layout
|
||||
SetIcons(wxGetApp().GetIconBundle());
|
||||
SetTitle(wxString::Format("Virtual Pad - Port %d", controllerPort + 1));
|
||||
SetPosition(options.VirtualPadPosition);
|
||||
SetBackgroundColour(*wxWHITE);
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
// This window does not allow for resizing for sake of simplicity: all images are scaled initially and stored, ready to be rendered
|
||||
SetWindowStyle(wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER & ~wxMAXIMIZE_BOX);
|
||||
|
||||
// Causes flickering, despite it supposed to be preventing it!
|
||||
// SetDoubleBuffered(true);
|
||||
}
|
||||
|
||||
void VirtualPad::OnMoveAround(wxMoveEvent& event)
|
||||
{
|
||||
if (IsBeingDeleted() || !IsVisible() || IsIconized())
|
||||
return;
|
||||
|
||||
if (!IsMaximized())
|
||||
options.VirtualPadPosition = GetPosition();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void VirtualPad::OnClose(wxCloseEvent& event)
|
||||
{
|
||||
// Re-bind the Paint event in case this is due to a game being opened/closed
|
||||
manualRedrawMode = false;
|
||||
Bind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
|
||||
// DevCon.WriteLn("Paint Event Bound");
|
||||
Hide();
|
||||
}
|
||||
|
||||
void VirtualPad::OnIconize(wxIconizeEvent& event)
|
||||
{
|
||||
if (event.IsIconized())
|
||||
{
|
||||
manualRedrawMode = false;
|
||||
Bind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
|
||||
// DevCon.WriteLn("Paint Event Bound");
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualPad::OnEraseBackground(wxEraseEvent& event)
|
||||
{
|
||||
// Intentionally Empty
|
||||
// See - https://wiki.wxwidgets.org/Flicker-Free_Drawing
|
||||
}
|
||||
|
||||
void VirtualPad::OnPaint(wxPaintEvent& event)
|
||||
{
|
||||
// DevCon.WriteLn("Paint Event Called");
|
||||
wxBufferedPaintDC dc(this, wxBUFFER_VIRTUAL_AREA);
|
||||
Render(dc);
|
||||
}
|
||||
|
||||
void VirtualPad::Redraw()
|
||||
{
|
||||
wxClientDC cdc(this);
|
||||
wxBufferedDC dc(&cdc);
|
||||
Render(dc);
|
||||
}
|
||||
|
||||
void VirtualPad::Render(wxDC& bdc)
|
||||
{
|
||||
// Update GUI Elements and figure out what needs to be rendered
|
||||
for (VirtualPadElement* virtualPadElement : virtualPadElements)
|
||||
virtualPadElement->UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
|
||||
// Update Graphic Elements off render stack
|
||||
// Before we start rendering (if we have to) clear and re-draw the background
|
||||
if (!manualRedrawMode || clearScreenRequired || !renderQueue.empty())
|
||||
{
|
||||
bdc.SetBrush(*wxWHITE);
|
||||
bdc.DrawRectangle(wxPoint(0, 0), bdc.GetSize());
|
||||
bdc.SetBrush(wxNullBrush);
|
||||
bdc.DrawBitmap(virtualPadData.background.image, virtualPadData.background.coords, true);
|
||||
clearScreenRequired = false;
|
||||
|
||||
// Switch to Manual Rendering once the first user action on the VirtualPad is taken
|
||||
if (!manualRedrawMode && !renderQueue.empty())
|
||||
{
|
||||
// DevCon.WriteLn("Paint Event Unbound");
|
||||
Unbind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
|
||||
manualRedrawMode = true;
|
||||
}
|
||||
|
||||
// NOTE - there is yet another (and I think final) micro-optimization that can be done:
|
||||
// It can be assumed that if the element has already been drawn to the screen (and not cleared) that we can skip rendering it
|
||||
//
|
||||
// For example - you hold a single button for several frames, it will currently draw that every frame
|
||||
// despite the screen never being cleared - so this is not strictly necessary.
|
||||
//
|
||||
// Though after some tests, the performance impact is well within reason, and on the hardware renderer modes, is almost non-existant.
|
||||
while (!renderQueue.empty())
|
||||
{
|
||||
VirtualPadElement* element = renderQueue.front();
|
||||
if (element)
|
||||
element->Render(bdc);
|
||||
renderQueue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VirtualPad::UpdateControllerData(u16 const bufIndex, PadData* padData)
|
||||
{
|
||||
return virtualPadData.UpdateVirtualPadData(bufIndex, padData, ignoreRealController && !readOnlyMode, readOnlyMode);
|
||||
}
|
||||
|
||||
void VirtualPad::enableUiElements(bool enable)
|
||||
{
|
||||
ignoreRealControllerBox->Enable(enable);
|
||||
resetButton->Enable(enable);
|
||||
for (VirtualPadElement* virtualPadElement : virtualPadElements)
|
||||
virtualPadElement->EnableWidgets(enable);
|
||||
}
|
||||
|
||||
void VirtualPad::SetReadOnlyMode(bool readOnly)
|
||||
{
|
||||
enableUiElements(!readOnly);
|
||||
readOnlyMode = readOnly;
|
||||
}
|
||||
|
||||
void VirtualPad::OnIgnoreRealController(wxCommandEvent& event)
|
||||
{
|
||||
const wxCheckBox* ignoreButton = (wxCheckBox*)event.GetEventObject();
|
||||
if (ignoreButton)
|
||||
ignoreRealController = ignoreButton->GetValue();
|
||||
}
|
||||
|
||||
void VirtualPad::OnResetButton(wxCommandEvent& event)
|
||||
{
|
||||
if (readOnlyMode)
|
||||
return;
|
||||
|
||||
for (VirtualPadElement* virtualPadElement : virtualPadElements)
|
||||
virtualPadElement->Reset(this);
|
||||
}
|
||||
|
||||
void VirtualPad::OnNormalButtonPress(wxCommandEvent& event)
|
||||
{
|
||||
const wxCheckBox* pressedButton = (wxCheckBox*)event.GetEventObject();
|
||||
ControllerNormalButton* eventBtn = buttonElements[pressedButton->GetId()];
|
||||
|
||||
if (pressedButton)
|
||||
eventBtn->pressed = pressedButton->GetValue();
|
||||
|
||||
if (!eventBtn->isControllerPressBypassed)
|
||||
eventBtn->isControllerPressBypassed = true;
|
||||
}
|
||||
|
||||
void VirtualPad::OnPressureButtonPressureChange(wxCommandEvent& event)
|
||||
{
|
||||
const wxSpinCtrl* pressureSpinner = (wxSpinCtrl*)event.GetEventObject();
|
||||
ControllerPressureButton* eventBtn = pressureElements[pressureSpinner->GetId()];
|
||||
|
||||
if (pressureSpinner)
|
||||
eventBtn->pressure = pressureSpinner->GetValue();
|
||||
|
||||
eventBtn->pressed = eventBtn->pressure > 0;
|
||||
|
||||
if (!eventBtn->isControllerPressureBypassed || !eventBtn->isControllerPressBypassed)
|
||||
{
|
||||
eventBtn->isControllerPressureBypassed = true;
|
||||
eventBtn->isControllerPressBypassed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualPad::OnAnalogSpinnerChange(wxCommandEvent& event)
|
||||
{
|
||||
const wxSpinCtrl* analogSpinner = (wxSpinCtrl*)event.GetEventObject();
|
||||
AnalogVector* eventVector = analogElements[analogSpinner->GetId()];
|
||||
|
||||
if (analogSpinner)
|
||||
eventVector->val = analogSpinner->GetValue();
|
||||
|
||||
eventVector->slider->SetValue(eventVector->val);
|
||||
|
||||
if (!eventVector->isControllerBypassed)
|
||||
eventVector->isControllerBypassed = true;
|
||||
}
|
||||
|
||||
void VirtualPad::OnAnalogSliderChange(wxCommandEvent& event)
|
||||
{
|
||||
const wxSlider* analogSlider = (wxSlider*)event.GetEventObject();
|
||||
AnalogVector* eventVector = analogElements[analogSlider->GetId()];
|
||||
|
||||
if (analogSlider)
|
||||
eventVector->val = analogSlider->GetValue();
|
||||
|
||||
eventVector->spinner->SetValue(eventVector->val);
|
||||
|
||||
if (!eventVector->isControllerBypassed)
|
||||
eventVector->isControllerBypassed = true;
|
||||
}
|
||||
|
||||
/// GUI Element Utility Functions
|
||||
|
||||
bool VirtualPad::floatCompare(float a, float b, float epsilon)
|
||||
{
|
||||
return (fabs(a - b) < epsilon);
|
||||
}
|
||||
|
||||
wxPoint VirtualPad::ScaledPoint(wxPoint point, wxSize widgetWidth, bool rightAlignedCoord, bool bottomAlignedCoord)
|
||||
{
|
||||
return ScaledPoint(point.x, point.y, widgetWidth.x, widgetWidth.y, rightAlignedCoord, bottomAlignedCoord);
|
||||
}
|
||||
|
||||
wxPoint VirtualPad::ScaledPoint(int x, int y, int widgetWidth, int widgetHeight, bool rightAlignedCoord, bool bottomAlignedCoord)
|
||||
{
|
||||
wxPoint scaledPoint = wxPoint(x * scalingFactor, y * scalingFactor);
|
||||
if (rightAlignedCoord)
|
||||
{
|
||||
scaledPoint.x -= widgetWidth * scalingFactor;
|
||||
if (scaledPoint.x < 0)
|
||||
scaledPoint.x = 0;
|
||||
}
|
||||
if (bottomAlignedCoord)
|
||||
{
|
||||
scaledPoint.y -= widgetHeight * scalingFactor;
|
||||
if (scaledPoint.y < 0)
|
||||
scaledPoint.y = 0;
|
||||
}
|
||||
return scaledPoint;
|
||||
}
|
||||
|
||||
wxSize VirtualPad::ScaledSize(wxSize size)
|
||||
{
|
||||
return ScaledSize(size.x, size.y);
|
||||
}
|
||||
|
||||
wxSize VirtualPad::ScaledSize(int x, int y)
|
||||
{
|
||||
return wxSize(x * scalingFactor, y * scalingFactor);
|
||||
}
|
||||
|
||||
ImageFile VirtualPad::NewBitmap(wxImage resource, wxPoint imgCoord, bool dontScale)
|
||||
{
|
||||
return NewBitmap(dontScale ? 1 : scalingFactor, resource, imgCoord);
|
||||
}
|
||||
|
||||
ImageFile VirtualPad::NewBitmap(float scalingFactor, wxImage resource, wxPoint imgCoord)
|
||||
{
|
||||
wxBitmap bitmap = wxBitmap(resource.Rescale(resource.GetWidth() * scalingFactor, resource.GetHeight() * scalingFactor, wxIMAGE_QUALITY_HIGH));
|
||||
|
||||
ImageFile image = ImageFile();
|
||||
image.image = bitmap;
|
||||
image.width = bitmap.GetWidth();
|
||||
image.height = bitmap.GetHeight();
|
||||
image.coords = ScaledPoint(imgCoord);
|
||||
return image;
|
||||
}
|
||||
|
||||
void VirtualPad::InitNormalButtonGuiElements(ControllerNormalButton& button, ImageFile image, wxWindow* parentWindow, wxPoint checkboxCoord)
|
||||
{
|
||||
button.icon = image;
|
||||
button.pressedBox = new wxCheckBox(parentWindow, wxID_ANY, wxEmptyString, ScaledPoint(checkboxCoord), wxDefaultSize);
|
||||
Bind(wxEVT_CHECKBOX, &VirtualPad::OnNormalButtonPress, this, button.pressedBox->GetId());
|
||||
buttonElements[button.pressedBox->GetId()] = &button;
|
||||
virtualPadElements.push_back(&button);
|
||||
}
|
||||
|
||||
void VirtualPad::InitPressureButtonGuiElements(ControllerPressureButton& button, ImageFile image, wxWindow* parentWindow, wxPoint pressureSpinnerCoord, bool rightAlignedCoord, bool bottomAlignedCoord)
|
||||
{
|
||||
const wxPoint scaledPoint = ScaledPoint(pressureSpinnerCoord, SPINNER_SIZE, rightAlignedCoord, bottomAlignedCoord);
|
||||
wxSpinCtrl* spinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, scaledPoint, ScaledSize(SPINNER_SIZE), wxSP_ARROW_KEYS, 0, 255, 0);
|
||||
|
||||
button.icon = image;
|
||||
button.pressureSpinner = spinner;
|
||||
Bind(wxEVT_SPINCTRL, &VirtualPad::OnPressureButtonPressureChange, this, button.pressureSpinner->GetId());
|
||||
pressureElements[button.pressureSpinner->GetId()] = &button;
|
||||
virtualPadElements.push_back(&button);
|
||||
}
|
||||
|
||||
void VirtualPad::InitAnalogStickGuiElements(AnalogStick& analog, wxWindow* parentWindow, wxPoint centerPoint, int radius,
|
||||
wxPoint xSliderPoint, wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners)
|
||||
{
|
||||
AnalogPosition analogPos = AnalogPosition();
|
||||
analogPos.centerCoords = ScaledPoint(centerPoint);
|
||||
analogPos.endCoords = ScaledPoint(centerPoint);
|
||||
analogPos.radius = radius * scalingFactor;
|
||||
analogPos.lineThickness = 6 * scalingFactor;
|
||||
|
||||
const wxPoint xSpinnerScaledPoint = ScaledPoint(xSpinnerPoint, SPINNER_SIZE, rightAlignedSpinners);
|
||||
const wxPoint ySpinnerScaledPoint = ScaledPoint(ySpinnerPoint, SPINNER_SIZE, rightAlignedSpinners, true);
|
||||
|
||||
wxSlider* xSlider = new wxSlider(parentWindow, wxID_ANY, ANALOG_NEUTRAL, 0, ANALOG_MAX,
|
||||
ScaledPoint(xSliderPoint), ScaledSize(ANALOG_SLIDER_WIDTH, ANALOG_SLIDER_HEIGHT));
|
||||
wxSlider* ySlider = new wxSlider(parentWindow, wxID_ANY, ANALOG_NEUTRAL, 0, ANALOG_MAX,
|
||||
ScaledPoint(ySliderPoint), ScaledSize(ANALOG_SLIDER_HEIGHT, ANALOG_SLIDER_WIDTH), flipYSlider ? wxSL_LEFT : wxSL_RIGHT);
|
||||
wxSpinCtrl* xSpinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, xSpinnerScaledPoint, ScaledSize(SPINNER_SIZE), wxSP_ARROW_KEYS, 0, 255, 127);
|
||||
wxSpinCtrl* ySpinner = new wxSpinCtrl(parentWindow, wxID_ANY, wxEmptyString, ySpinnerScaledPoint, ScaledSize(SPINNER_SIZE), wxSP_ARROW_KEYS, 0, 255, 127);
|
||||
|
||||
analog.xVector.slider = xSlider;
|
||||
analog.yVector.slider = ySlider;
|
||||
analog.xVector.spinner = xSpinner;
|
||||
analog.yVector.spinner = ySpinner;
|
||||
analog.positionGraphic = analogPos;
|
||||
Bind(wxEVT_SLIDER, &VirtualPad::OnAnalogSliderChange, this, xSlider->GetId());
|
||||
Bind(wxEVT_SLIDER, &VirtualPad::OnAnalogSliderChange, this, ySlider->GetId());
|
||||
Bind(wxEVT_SPINCTRL, &VirtualPad::OnAnalogSpinnerChange, this, xSpinner->GetId());
|
||||
Bind(wxEVT_SPINCTRL, &VirtualPad::OnAnalogSpinnerChange, this, ySpinner->GetId());
|
||||
analogElements[xSlider->GetId()] = &analog.xVector;
|
||||
analogElements[ySlider->GetId()] = &analog.yVector;
|
||||
analogElements[xSpinner->GetId()] = &analog.xVector;
|
||||
analogElements[ySpinner->GetId()] = &analog.yVector;
|
||||
virtualPadElements.push_back(&analog);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,119 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
||||
#include "gui/AppConfig.h"
|
||||
#include "common/Pcsx2Types.h"
|
||||
|
||||
#include "wx/button.h"
|
||||
#include "wx/checkbox.h"
|
||||
#include "wx/dc.h"
|
||||
#include "wx/event.h"
|
||||
#include "wx/frame.h"
|
||||
#include "wx/gdicmn.h"
|
||||
#include "wx/string.h"
|
||||
#include "wx/window.h"
|
||||
#include "wx/windowid.h"
|
||||
|
||||
#include "Recording/PadData.h"
|
||||
#include "Recording/VirtualPad/VirtualPadData.h"
|
||||
|
||||
class VirtualPad : public wxFrame
|
||||
{
|
||||
public:
|
||||
VirtualPad(wxWindow* parent, int controllerPort, AppConfig::InputRecordingOptions& options);
|
||||
// Updates the VirtualPad's data if necessary, as well as updates the provided PadData if the VirtualPad overrides it
|
||||
// - PadData will not be updated if ReadOnly mode is set
|
||||
// - returns a bool to indicate if the PadData has been updated
|
||||
bool UpdateControllerData(u16 const bufIndex, PadData* padData);
|
||||
// Enables/Disables read only mode and enables/disables GUI widgets
|
||||
void SetReadOnlyMode(bool readOnly);
|
||||
// To be called at maximum, once per frame to update widget's value and re-render the VirtualPad's graphics
|
||||
void Redraw();
|
||||
|
||||
private:
|
||||
/// Constants
|
||||
const wxSize SPINNER_SIZE = wxSize(100, 40);
|
||||
static const int ANALOG_SLIDER_WIDTH = 185;
|
||||
static const int ANALOG_SLIDER_HEIGHT = 30;
|
||||
|
||||
static const int PRESSURE_MAX = 255;
|
||||
static const int ANALOG_NEUTRAL = 127;
|
||||
static const int ANALOG_MAX = 255;
|
||||
|
||||
AppConfig::InputRecordingOptions& options;
|
||||
|
||||
bool clearScreenRequired = false;
|
||||
bool ignoreRealController = false;
|
||||
// When enabled, forces the VirtualPad to be re-rendered even if no updates are made.
|
||||
// This helps to make sure the UI is rendered prior to receiving data from the controller
|
||||
bool manualRedrawMode = false;
|
||||
bool readOnlyMode = false;
|
||||
|
||||
VirtualPadData virtualPadData;
|
||||
|
||||
std::vector<VirtualPadElement*> virtualPadElements;
|
||||
std::queue<VirtualPadElement*> renderQueue;
|
||||
|
||||
void enableUiElements(bool enable);
|
||||
|
||||
/// GUI Elements
|
||||
wxCheckBox* ignoreRealControllerBox;
|
||||
wxButton* resetButton;
|
||||
|
||||
std::map<wxWindowID, ControllerNormalButton*> buttonElements;
|
||||
std::map<wxWindowID, ControllerPressureButton*> pressureElements;
|
||||
std::map<wxWindowID, AnalogVector*> analogElements;
|
||||
|
||||
/// Event Listeners
|
||||
void OnMoveAround(wxMoveEvent& event);
|
||||
void OnClose(wxCloseEvent& event);
|
||||
void OnIconize(wxIconizeEvent& event);
|
||||
void OnEraseBackground(wxEraseEvent& event);
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void Render(wxDC& dc);
|
||||
|
||||
void OnAnalogSliderChange(wxCommandEvent& event);
|
||||
void OnAnalogSpinnerChange(wxCommandEvent& event);
|
||||
void OnIgnoreRealController(wxCommandEvent& event);
|
||||
void OnNormalButtonPress(wxCommandEvent& event);
|
||||
void OnPressureButtonPressureChange(wxCommandEvent& event);
|
||||
void OnResetButton(wxCommandEvent& event);
|
||||
|
||||
/// GUI Creation Utility Functions
|
||||
float scalingFactor = 1.0;
|
||||
bool floatCompare(float A, float B, float epsilon = 0.005f);
|
||||
|
||||
wxSize ScaledSize(wxSize size);
|
||||
wxSize ScaledSize(int x, int y);
|
||||
wxPoint ScaledPoint(wxPoint point, wxSize widgetSize = wxDefaultSize, bool rightAlignedCoord = false, bool bottomAlignedCoord = false);
|
||||
wxPoint ScaledPoint(int x, int y, int widgetWidth, int widgetHeight, bool rightAlignedCoord = false, bool bottomAlignedCoord = false);
|
||||
|
||||
ImageFile NewBitmap(wxImage resource, wxPoint imgCoord, bool dontScale = false);
|
||||
ImageFile NewBitmap(float scalingFactor, wxImage resource, wxPoint imgCoord);
|
||||
|
||||
void InitPressureButtonGuiElements(ControllerPressureButton& button, ImageFile image, wxWindow* parentWindow, wxPoint pressureSpinnerCoord, bool rightAlignedCoord = false, bool bottomAlignedCoord = false);
|
||||
void InitNormalButtonGuiElements(ControllerNormalButton& btn, ImageFile image, wxWindow* parentWindow, wxPoint checkboxCoord);
|
||||
void InitAnalogStickGuiElements(AnalogStick& analog, wxWindow* parentWindow, wxPoint centerPoint, int radius, wxPoint xSliderPoint,
|
||||
wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners = false);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,84 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
#include "Recording/VirtualPad/VirtualPadData.h"
|
||||
|
||||
bool VirtualPadData::UpdateVirtualPadData(u16 bufIndex, PadData* padData, bool ignoreRealController, bool readOnly)
|
||||
{
|
||||
bool changeDetected = false;
|
||||
PadData::BufferIndex index = static_cast<PadData::BufferIndex>(bufIndex);
|
||||
switch (index)
|
||||
{
|
||||
case PadData::BufferIndex::PressedFlagsGroupOne:
|
||||
changeDetected |= left.UpdateData(padData->leftPressed, ignoreRealController, readOnly);
|
||||
changeDetected |= down.UpdateData(padData->downPressed, ignoreRealController, readOnly);
|
||||
changeDetected |= right.UpdateData(padData->rightPressed, ignoreRealController, readOnly);
|
||||
changeDetected |= up.UpdateData(padData->upPressed, ignoreRealController, readOnly);
|
||||
changeDetected |= start.UpdateData(padData->start, ignoreRealController, readOnly);
|
||||
changeDetected |= r3.UpdateData(padData->r3, ignoreRealController, readOnly);
|
||||
changeDetected |= l3.UpdateData(padData->l3, ignoreRealController, readOnly);
|
||||
changeDetected |= select.UpdateData(padData->select, ignoreRealController, readOnly);
|
||||
return changeDetected;
|
||||
case PadData::BufferIndex::PressedFlagsGroupTwo:
|
||||
changeDetected |= square.UpdateData(padData->squarePressed, ignoreRealController, readOnly);
|
||||
changeDetected |= cross.UpdateData(padData->crossPressed, ignoreRealController, readOnly);
|
||||
changeDetected |= circle.UpdateData(padData->circlePressed, ignoreRealController, readOnly);
|
||||
changeDetected |= triangle.UpdateData(padData->trianglePressed, ignoreRealController, readOnly);
|
||||
changeDetected |= r1.UpdateData(padData->r1Pressed, ignoreRealController, readOnly);
|
||||
changeDetected |= l1.UpdateData(padData->l1Pressed, ignoreRealController, readOnly);
|
||||
changeDetected |= r2.UpdateData(padData->r2Pressed, ignoreRealController, readOnly);
|
||||
changeDetected |= l2.UpdateData(padData->l2Pressed, ignoreRealController, readOnly);
|
||||
return changeDetected;
|
||||
case PadData::BufferIndex::RightAnalogXVector:
|
||||
return rightAnalog.xVector.UpdateData(padData->rightAnalogX, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::RightAnalogYVector:
|
||||
return rightAnalog.yVector.UpdateData(padData->rightAnalogY, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::LeftAnalogXVector:
|
||||
return leftAnalog.xVector.UpdateData(padData->leftAnalogX, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::LeftAnalogYVector:
|
||||
return leftAnalog.yVector.UpdateData(padData->leftAnalogY, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::RightPressure:
|
||||
return right.UpdateData(padData->rightPressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::LeftPressure:
|
||||
return left.UpdateData(padData->leftPressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::UpPressure:
|
||||
return up.UpdateData(padData->upPressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::DownPressure:
|
||||
return down.UpdateData(padData->downPressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::TrianglePressure:
|
||||
return triangle.UpdateData(padData->trianglePressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::CirclePressure:
|
||||
return circle.UpdateData(padData->circlePressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::CrossPressure:
|
||||
return cross.UpdateData(padData->crossPressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::SquarePressure:
|
||||
return square.UpdateData(padData->squarePressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::L1Pressure:
|
||||
return l1.UpdateData(padData->l1Pressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::R1Pressure:
|
||||
return r1.UpdateData(padData->r1Pressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::L2Pressure:
|
||||
return l2.UpdateData(padData->l2Pressure, ignoreRealController, readOnly);
|
||||
case PadData::BufferIndex::R2Pressure:
|
||||
return r2.UpdateData(padData->r2Pressure, ignoreRealController, readOnly);
|
||||
}
|
||||
return changeDetected;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,63 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
#include "common/Pcsx2Types.h"
|
||||
|
||||
#include "Recording/PadData.h"
|
||||
#include "Recording/VirtualPad/VirtualPadResources.h"
|
||||
|
||||
class VirtualPadData
|
||||
{
|
||||
public:
|
||||
/// Controller Background
|
||||
ImageFile background;
|
||||
|
||||
/// Pressure Buttons
|
||||
ControllerPressureButton circle;
|
||||
ControllerPressureButton cross;
|
||||
ControllerPressureButton down;
|
||||
ControllerPressureButton l1;
|
||||
ControllerPressureButton l2;
|
||||
ControllerPressureButton left;
|
||||
ControllerPressureButton r1;
|
||||
ControllerPressureButton r2;
|
||||
ControllerPressureButton right;
|
||||
ControllerPressureButton square;
|
||||
ControllerPressureButton triangle;
|
||||
ControllerPressureButton up;
|
||||
|
||||
/// Normal (un)pressed buttons
|
||||
ControllerNormalButton l3;
|
||||
ControllerNormalButton r3;
|
||||
ControllerNormalButton select;
|
||||
ControllerNormalButton start;
|
||||
|
||||
/// Analog Sticks
|
||||
AnalogStick leftAnalog;
|
||||
AnalogStick rightAnalog;
|
||||
|
||||
// Given the input buffer and the current index, updates the respective field(s) within this object
|
||||
// Additionally overwrites the PadData object under the following criteria:
|
||||
// - If ignoreRealController is true (and readOnly is false) PadData will always be updated
|
||||
// - else if the VirtualPad has overwritten the value, and the real controller has not changed since that moment in time
|
||||
// returns a boolean to indicate if it has updated the PadData
|
||||
bool UpdateVirtualPadData(u16 bufIndex, PadData* padData, bool ignoreRealController = false, bool readOnly = false);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,267 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
#include <wx/spinctrl.h>
|
||||
|
||||
#include "Recording/VirtualPad/VirtualPadResources.h"
|
||||
#include "Recording/PadData.h"
|
||||
|
||||
wxCommandEvent VirtualPadElement::ConstructEvent(wxEventTypeTag<wxCommandEvent> eventType, wxWindow* obj)
|
||||
{
|
||||
wxCommandEvent event(eventType, obj->GetId());
|
||||
event.SetEventObject(obj);
|
||||
return event;
|
||||
}
|
||||
|
||||
wxCommandEvent VirtualPadElement::ConstructEvent(wxEventTypeTag<wxSpinEvent> eventType, wxWindow* obj)
|
||||
{
|
||||
wxCommandEvent event(eventType, obj->GetId());
|
||||
event.SetEventObject(obj);
|
||||
return event;
|
||||
}
|
||||
|
||||
void ControllerNormalButton::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired)
|
||||
{
|
||||
ControllerNormalButton& button = *this;
|
||||
// This boolean is set when we parse the PadData in VirtualPadData::UpdateVirtualPadData
|
||||
// Updating wxWidget elements can be expensive, we only want to do this if required
|
||||
if (button.widgetUpdateRequired)
|
||||
button.pressedBox->SetValue(button.pressed);
|
||||
|
||||
// We only render the button if it is pressed
|
||||
if (button.pressed)
|
||||
renderQueue.push(this);
|
||||
// However, if the button has been drawn to the screen in the past
|
||||
// we need to ensure the screen is cleared.
|
||||
// This is needed in the scenario where only a single button is being pressed/released
|
||||
// As no other elements will trigger a clear
|
||||
else if (button.currentlyRendered)
|
||||
{
|
||||
button.currentlyRendered = false;
|
||||
clearScreenRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerPressureButton::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired)
|
||||
{
|
||||
ControllerPressureButton& button = *this;
|
||||
if (button.widgetUpdateRequired)
|
||||
button.pressureSpinner->SetValue(button.pressure);
|
||||
|
||||
if (button.pressed)
|
||||
renderQueue.push(this);
|
||||
else if (button.currentlyRendered)
|
||||
{
|
||||
button.currentlyRendered = false;
|
||||
clearScreenRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
void AnalogStick::UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired)
|
||||
{
|
||||
AnalogStick& analogStick = *this;
|
||||
if (analogStick.xVector.widgetUpdateRequired)
|
||||
{
|
||||
analogStick.xVector.slider->SetValue(analogStick.xVector.val);
|
||||
analogStick.xVector.spinner->SetValue(analogStick.xVector.val);
|
||||
}
|
||||
if (analogStick.yVector.widgetUpdateRequired)
|
||||
{
|
||||
analogStick.yVector.slider->SetValue(analogStick.yVector.val);
|
||||
analogStick.yVector.spinner->SetValue(analogStick.yVector.val);
|
||||
}
|
||||
|
||||
// We render the analog sticks as long as they are not in the neutral position
|
||||
if (!(analogStick.xVector.val == PadData::ANALOG_VECTOR_NEUTRAL && analogStick.yVector.val == PadData::ANALOG_VECTOR_NEUTRAL))
|
||||
renderQueue.push(this);
|
||||
else if (analogStick.currentlyRendered)
|
||||
{
|
||||
analogStick.currentlyRendered = false;
|
||||
clearScreenRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerNormalButton::EnableWidgets(bool enable)
|
||||
{
|
||||
this->pressedBox->Enable(enable);
|
||||
}
|
||||
|
||||
void ControllerPressureButton::EnableWidgets(bool enable)
|
||||
{
|
||||
this->pressureSpinner->Enable(enable);
|
||||
}
|
||||
|
||||
void AnalogStick::EnableWidgets(bool enable)
|
||||
{
|
||||
this->xVector.slider->Enable(enable);
|
||||
this->yVector.slider->Enable(enable);
|
||||
this->xVector.spinner->Enable(enable);
|
||||
this->yVector.spinner->Enable(enable);
|
||||
}
|
||||
|
||||
void ControllerNormalButton::Render(wxDC& dc)
|
||||
{
|
||||
ControllerNormalButton& button = *this;
|
||||
ImageFile& img = button.icon;
|
||||
dc.DrawBitmap(img.image, img.coords, true);
|
||||
button.currentlyRendered = true;
|
||||
}
|
||||
|
||||
void ControllerPressureButton::Render(wxDC& dc)
|
||||
{
|
||||
ControllerPressureButton& button = *this;
|
||||
ImageFile& img = button.icon;
|
||||
dc.DrawBitmap(img.image, img.coords, true);
|
||||
button.currentlyRendered = true;
|
||||
}
|
||||
|
||||
void AnalogStick::Render(wxDC& dc)
|
||||
{
|
||||
AnalogStick& analogStick = *this;
|
||||
// Render graphic
|
||||
AnalogPosition analogPos = analogStick.positionGraphic;
|
||||
// Determine new end coordinates
|
||||
int newXCoord = analogPos.centerCoords.x + ((analogStick.xVector.val - 127) / 127.0) * analogPos.radius;
|
||||
int newYCoord = analogPos.centerCoords.y + ((analogStick.yVector.val - 127) / 127.0) * analogPos.radius;
|
||||
// We want to ensure the line segment length is capped at the defined radius
|
||||
// NOTE - The conventional way to do this is using arctan2, but the analog values that come out
|
||||
// of Pad in pcsx2 do not permit this, the coordinates returned do not define a circle.
|
||||
const float lengthOfLine = sqrt(pow(newXCoord - analogPos.centerCoords.x, 2) + pow(newYCoord - analogPos.centerCoords.y, 2));
|
||||
if (lengthOfLine > analogPos.radius)
|
||||
{
|
||||
newXCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.x) + analogPos.radius / lengthOfLine * newXCoord;
|
||||
newYCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.y) + analogPos.radius / lengthOfLine * newYCoord;
|
||||
}
|
||||
// Set the new end coordinate
|
||||
analogPos.endCoords = wxPoint(newXCoord, newYCoord);
|
||||
// Draw line and tip
|
||||
dc.SetPen(wxPen(*wxBLUE, analogPos.lineThickness));
|
||||
dc.DrawLine(analogPos.centerCoords, analogPos.endCoords);
|
||||
dc.DrawCircle(analogPos.endCoords, wxCoord(analogPos.lineThickness));
|
||||
dc.SetPen(wxNullPen);
|
||||
analogStick.currentlyRendered = true;
|
||||
}
|
||||
|
||||
void ControllerNormalButton::Reset(wxEvtHandler* destWindow)
|
||||
{
|
||||
this->pressedBox->SetValue(false);
|
||||
wxPostEvent(destWindow, ConstructEvent(wxEVT_CHECKBOX, this->pressedBox));
|
||||
}
|
||||
|
||||
void ControllerPressureButton::Reset(wxEvtHandler* destWindow)
|
||||
{
|
||||
this->pressureSpinner->SetValue(0);
|
||||
wxPostEvent(destWindow, ConstructEvent(wxEVT_SPINCTRL, this->pressureSpinner));
|
||||
}
|
||||
|
||||
void AnalogStick::Reset(wxEvtHandler* destWindow)
|
||||
{
|
||||
this->xVector.slider->SetValue(127);
|
||||
this->yVector.slider->SetValue(127);
|
||||
wxPostEvent(destWindow, ConstructEvent(wxEVT_SLIDER, this->xVector.slider));
|
||||
wxPostEvent(destWindow, ConstructEvent(wxEVT_SLIDER, this->yVector.slider));
|
||||
this->xVector.spinner->SetValue(127);
|
||||
this->xVector.spinner->SetValue(127);
|
||||
wxPostEvent(destWindow, ConstructEvent(wxEVT_SPINCTRL, this->xVector.spinner));
|
||||
wxPostEvent(destWindow, ConstructEvent(wxEVT_SPINCTRL, this->yVector.spinner));
|
||||
}
|
||||
|
||||
bool ControllerNormalButton::UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly)
|
||||
{
|
||||
return this->UpdateButtonData(padDataVal, ignoreRealController, readOnly);
|
||||
}
|
||||
|
||||
bool ControllerPressureButton::UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly)
|
||||
{
|
||||
return this->UpdateButtonData(padDataVal, ignoreRealController, readOnly);
|
||||
}
|
||||
|
||||
bool ControllerButton::UpdateButtonData(bool& padDataVal, bool ignoreRealController, bool readOnly)
|
||||
{
|
||||
ControllerButton& button = *this;
|
||||
if (!ignoreRealController || readOnly)
|
||||
{
|
||||
// If controller is being bypassed and controller's state has changed
|
||||
const bool bypassedWithChangedState = button.isControllerPressBypassed && padDataVal != button.prevPressedVal;
|
||||
if (bypassedWithChangedState)
|
||||
{
|
||||
button.prevPressedVal = padDataVal;
|
||||
button.isControllerPressBypassed = false;
|
||||
}
|
||||
// If we aren't bypassing the controller OR the previous condition was met
|
||||
if (bypassedWithChangedState || !button.isControllerPressBypassed || readOnly)
|
||||
{
|
||||
button.widgetUpdateRequired = button.pressed != padDataVal;
|
||||
button.pressed = padDataVal;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Otherwise, we update the real PadData value, which will in turn be used to update the interrupt's buffer
|
||||
button.prevPressedVal = padDataVal;
|
||||
padDataVal = button.pressed;
|
||||
return button.prevPressedVal != button.pressed;
|
||||
}
|
||||
|
||||
bool ControllerPressureButton::UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly)
|
||||
{
|
||||
ControllerPressureButton& button = *this;
|
||||
if (!ignoreRealController || readOnly)
|
||||
{
|
||||
const bool bypassedWithChangedState = button.isControllerPressureBypassed && padDataVal != button.prevPressureVal;
|
||||
if (bypassedWithChangedState)
|
||||
{
|
||||
button.prevPressureVal = padDataVal;
|
||||
button.isControllerPressureBypassed = false;
|
||||
}
|
||||
if (bypassedWithChangedState || !button.isControllerPressureBypassed || readOnly)
|
||||
{
|
||||
button.widgetUpdateRequired = button.pressure != padDataVal;
|
||||
button.pressure = padDataVal;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
button.prevPressureVal = padDataVal;
|
||||
padDataVal = button.pressure;
|
||||
return button.prevPressureVal != button.pressure;
|
||||
}
|
||||
|
||||
bool AnalogVector::UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly)
|
||||
{
|
||||
AnalogVector& vector = *this;
|
||||
if (!ignoreRealController || readOnly)
|
||||
{
|
||||
const bool bypassedWithChangedState = vector.isControllerBypassed && padDataVal != vector.prevVal;
|
||||
if (bypassedWithChangedState)
|
||||
{
|
||||
vector.prevVal = padDataVal;
|
||||
vector.isControllerBypassed = false;
|
||||
}
|
||||
if (bypassedWithChangedState || !vector.isControllerBypassed || readOnly)
|
||||
{
|
||||
vector.widgetUpdateRequired = vector.val != padDataVal;
|
||||
vector.val = padDataVal;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
vector.prevVal = padDataVal;
|
||||
padDataVal = vector.val;
|
||||
return vector.prevVal != vector.val;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,133 +0,0 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "common/Pcsx2Types.h"
|
||||
#include "wx/bitmap.h"
|
||||
#include "wx/checkbox.h"
|
||||
#include "wx/gdicmn.h"
|
||||
#include "wx/slider.h"
|
||||
#include "wx/spinctrl.h"
|
||||
#include "wx/dcbuffer.h"
|
||||
|
||||
struct ImageFile
|
||||
{
|
||||
wxBitmap image;
|
||||
wxPoint coords;
|
||||
u32 width = 0;
|
||||
u32 height = 0;
|
||||
};
|
||||
|
||||
struct AnalogVector
|
||||
{
|
||||
wxSlider* slider = 0;
|
||||
wxSpinCtrl* spinner = 0;
|
||||
|
||||
u8 val = 127;
|
||||
|
||||
bool isControllerBypassed = false;
|
||||
bool widgetUpdateRequired = false;
|
||||
u8 prevVal = 127;
|
||||
|
||||
bool UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly);
|
||||
};
|
||||
|
||||
|
||||
struct AnalogPosition
|
||||
{
|
||||
wxPoint centerCoords;
|
||||
wxPoint endCoords;
|
||||
|
||||
int lineThickness = 0;
|
||||
int radius = 0;
|
||||
};
|
||||
|
||||
class VirtualPadElement
|
||||
{
|
||||
public:
|
||||
bool currentlyRendered = false;
|
||||
|
||||
wxCommandEvent ConstructEvent(wxEventTypeTag<wxCommandEvent> eventType, wxWindow *obj);
|
||||
wxCommandEvent ConstructEvent(wxEventTypeTag<wxSpinEvent> eventType, wxWindow *obj);
|
||||
|
||||
virtual void EnableWidgets(bool enable) = 0;
|
||||
virtual void Render(wxDC& dc) = 0;
|
||||
virtual void Reset(wxEvtHandler* destWindow) = 0;
|
||||
virtual void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) = 0;
|
||||
};
|
||||
|
||||
class ControllerButton
|
||||
{
|
||||
public:
|
||||
bool isControllerPressBypassed = false;
|
||||
bool pressed = false;
|
||||
bool prevPressedVal = false;
|
||||
bool widgetUpdateRequired = false;
|
||||
|
||||
bool UpdateButtonData(bool& padDataVal, bool ignoreRealController, bool readOnly);
|
||||
};
|
||||
|
||||
class ControllerNormalButton : public ControllerButton, public VirtualPadElement
|
||||
{
|
||||
public:
|
||||
ImageFile icon;
|
||||
wxCheckBox* pressedBox = 0;
|
||||
|
||||
bool UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly);
|
||||
void EnableWidgets(bool enable) override;
|
||||
void Render(wxDC& dc) override;
|
||||
void Reset(wxEvtHandler* destWindow) override;
|
||||
void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override;
|
||||
};
|
||||
|
||||
class ControllerPressureButton : public ControllerButton, public VirtualPadElement
|
||||
{
|
||||
public:
|
||||
ImageFile icon;
|
||||
wxSpinCtrl* pressureSpinner = 0;
|
||||
|
||||
u8 pressure = 0;
|
||||
|
||||
bool isControllerPressureBypassed = false;
|
||||
u8 prevPressureVal = 0;
|
||||
|
||||
bool UpdateData(bool& padDataVal, bool ignoreRealController, bool readOnly);
|
||||
bool UpdateData(u8& padDataVal, bool ignoreRealController, bool readOnly);
|
||||
void EnableWidgets(bool enable) override;
|
||||
void Render(wxDC& dc) override;
|
||||
void Reset(wxEvtHandler* destWindow) override;
|
||||
void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override;
|
||||
};
|
||||
|
||||
class AnalogStick : public VirtualPadElement
|
||||
{
|
||||
public:
|
||||
AnalogVector xVector;
|
||||
AnalogVector yVector;
|
||||
|
||||
AnalogPosition positionGraphic;
|
||||
|
||||
void EnableWidgets(bool enable) override;
|
||||
void Render(wxDC& dc) override;
|
||||
void Reset(wxEvtHandler* destWindow) override;
|
||||
void UpdateGuiElement(std::queue<VirtualPadElement*>& renderQueue, bool& clearScreenRequired) override;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1 +0,0 @@
|
|||
*.h
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
:: Probably self-explanatory: This batch file compiles a single souce image into a
|
||||
:: CPP header file for use by pcsx2.
|
||||
::
|
||||
:: bin2cpp.cmd SrcImage
|
||||
::
|
||||
:: Parameters
|
||||
:: SrcImage - Complete filename with extension.
|
||||
::
|
||||
|
||||
@echo off
|
||||
|
||||
SETLOCAL ENABLEEXTENSIONS
|
||||
|
||||
cd "%~0\..\"
|
||||
"..\..\..\..\tools\bin\bin2cpp.exe" %1
|
||||
|
||||
ENDLOCAL
|
Before Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 121 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 836 B |
Before Width: | Height: | Size: 1017 B |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 302 B |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 1.6 KiB |
|
@ -30,8 +30,6 @@
|
|||
#include "RecentIsoList.h"
|
||||
#include "DriveList.h"
|
||||
|
||||
#include "Recording/NewRecordingFrame.h"
|
||||
|
||||
class DisassemblyDialog;
|
||||
struct HostKeyEvent;
|
||||
|
||||
|
@ -482,13 +480,6 @@ public:
|
|||
MainEmuFrame* GetMainFramePtr() const { return (MainEmuFrame*)wxWindow::FindWindowById(m_id_MainFrame); }
|
||||
DisassemblyDialog* GetDisassemblyPtr() const { return (DisassemblyDialog*)wxWindow::FindWindowById(m_id_Disassembler); }
|
||||
|
||||
#ifndef PCSX2_CORE
|
||||
NewRecordingFrame* GetNewRecordingFramePtr() const
|
||||
{
|
||||
return (NewRecordingFrame*)wxWindow::FindWindowById(m_id_NewRecordingFrame);
|
||||
}
|
||||
#endif
|
||||
|
||||
void enterDebugMode();
|
||||
void leaveDebugMode();
|
||||
void resetDebugger();
|
||||
|
|
|
@ -235,12 +235,8 @@ void Pcsx2App::SysApplySettings()
|
|||
|
||||
void AppCoreThread::OnResumeReady()
|
||||
{
|
||||
if (!g_InputRecordingControls.IsFrameAdvancing())
|
||||
{
|
||||
wxGetApp().SysApplySettings();
|
||||
wxGetApp().PostMethod(AppSaveSettings);
|
||||
}
|
||||
|
||||
wxGetApp().SysApplySettings();
|
||||
wxGetApp().PostMethod(AppSaveSettings);
|
||||
sApp.PostAppMethod(&Pcsx2App::leaveDebugMode);
|
||||
_parent::OnResumeReady();
|
||||
}
|
||||
|
|
|
@ -104,11 +104,6 @@ void Pcsx2App::OpenMainFrame()
|
|||
DisassemblyDialog* disassembly = new DisassemblyDialog(mainFrame);
|
||||
m_id_Disassembler = disassembly->GetId();
|
||||
|
||||
NewRecordingFrame* newRecordingFrame = new NewRecordingFrame(mainFrame);
|
||||
m_id_NewRecordingFrame = newRecordingFrame->GetId();
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
g_InputRecording.InitVirtualPadWindows(mainFrame);
|
||||
|
||||
if (g_Conf->EmuOptions.Debugger.ShowDebuggerOnStart)
|
||||
disassembly->Show();
|
||||
|
||||
|
|
|
@ -450,23 +450,6 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
{
|
||||
try
|
||||
{
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
{
|
||||
if (g_InputRecordingControls.IsPaused())
|
||||
{
|
||||
// When the GSFrame CoreThread is paused, so is the logical VSync
|
||||
// Meaning that we have to grab the user-input through here to potentially
|
||||
// resume emulation.
|
||||
if (const HostKeyEvent* ev = PADkeyEvent() )
|
||||
{
|
||||
if( ev->key != 0 )
|
||||
{
|
||||
PadKeyDispatch( *ev );
|
||||
}
|
||||
}
|
||||
}
|
||||
g_InputRecordingControls.ResumeCoreThreadIfStarted();
|
||||
}
|
||||
(handler->*func)(event);
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -481,9 +464,6 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent&
|
|||
// Saved state load failed prior to the system getting corrupted (ie, file not found
|
||||
// or some zipfile error) -- so log it and resume emulation.
|
||||
Console.Warning( ex.FormatDiagnosticMessage() );
|
||||
if (g_InputRecording.IsInitialLoad())
|
||||
g_InputRecording.FailedSavestate();
|
||||
|
||||
CoreThread.Resume();
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -768,15 +748,6 @@ void Pcsx2App::OpenGsPanel()
|
|||
std::optional<WindowInfo> wi = gsFrame->GetViewport()->GetWindowInfo();
|
||||
pxAssertDev(wi.has_value(), "GS frame has a valid native window");
|
||||
g_gs_window_info = std::move(*wi);
|
||||
|
||||
// Enable New & Play after the first game load of the session
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_New, !g_InputRecording.IsActive());
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_Play, true);
|
||||
|
||||
// Enable recording menu options as the game is now running
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_FrameAdvance, true);
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, true);
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, g_InputRecording.IsActive());
|
||||
}
|
||||
|
||||
|
||||
|
@ -816,11 +787,6 @@ void Pcsx2App::OnGsFrameDestroyed(wxWindowID id)
|
|||
|
||||
m_id_GsFrame = wxID_ANY;
|
||||
g_gs_window_info = {};
|
||||
|
||||
// Disable recording controls that only make sense if the game is running
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_FrameAdvance, false);
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, false);
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, false);
|
||||
}
|
||||
|
||||
void Pcsx2App::OnProgramLogClosed( wxWindowID id )
|
||||
|
@ -834,11 +800,6 @@ void Pcsx2App::OnProgramLogClosed( wxWindowID id )
|
|||
|
||||
void Pcsx2App::OnMainFrameClosed( wxWindowID id )
|
||||
{
|
||||
if (g_InputRecording.IsActive())
|
||||
{
|
||||
g_InputRecording.Stop();
|
||||
}
|
||||
|
||||
// Nothing threaded depends on the mainframe (yet) -- it all passes through the main wxApp
|
||||
// message handler. But that might change in the future.
|
||||
if( m_id_MainFrame != id ) return;
|
||||
|
@ -933,10 +894,6 @@ void Pcsx2App::SysExecute( CDVD_SourceType cdvdsrc, const wxString& elf_override
|
|||
return;
|
||||
|
||||
SysExecutorThread.PostEvent( new SysExecEvent_Execute(cdvdsrc, elf_override) );
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
{
|
||||
g_InputRecording.RecordingReset();
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if there is a "valid" virtual machine state from the user's perspective. This
|
||||
|
|
|
@ -107,76 +107,11 @@ void GSPanel::InitDefaultAccelerators()
|
|||
m_Accels->Map( FULLSCREEN_TOGGLE_ACCELERATOR_GSPANEL, "FullscreenToggle" );
|
||||
}
|
||||
|
||||
void GSPanel::InitRecordingAccelerators()
|
||||
{
|
||||
// Note: these override GlobalAccels ( Pcsx2App::InitDefaultGlobalAccelerators() )
|
||||
// For plain letters or symbols, replace e.g. WXK_F1 with e.g. wxKeyCode('q') or wxKeyCode('-')
|
||||
// For plain letter keys with shift, use e.g. AAC( wxKeyCode('q') ).Shift() and NOT wxKeyCode('Q')
|
||||
// For a symbol with shift (e.g. '_' which is '-' with shift) use AAC( wxKeyCode('-') ).Shift()
|
||||
|
||||
typedef KeyAcceleratorCode AAC;
|
||||
|
||||
if (!m_Accels) m_Accels = std::unique_ptr<AcceleratorDictionary>(new AcceleratorDictionary);
|
||||
|
||||
m_Accels->Map(AAC(WXK_SPACE), "FrameAdvance");
|
||||
m_Accels->Map(AAC(wxKeyCode('p')).Shift(), "TogglePause");
|
||||
m_Accels->Map(AAC(wxKeyCode('r')).Shift(), "InputRecordingModeToggle");
|
||||
m_Accels->Map(AAC(wxKeyCode('l')).Shift(), "GoToFirstFrame");
|
||||
#if defined(__unix__)
|
||||
// Shift+P (80) and Shift+p (112) have two completely different codes
|
||||
// On Linux the former is sometimes fired so define bindings for both
|
||||
m_Accels->Map(AAC(wxKeyCode('P')).Shift(), "TogglePause");
|
||||
m_Accels->Map(AAC(wxKeyCode('R')).Shift(), "InputRecordingModeToggle");
|
||||
m_Accels->Map(AAC(wxKeyCode('L')).Shift(), "GoToFirstFrame");
|
||||
#endif
|
||||
|
||||
m_Accels->Map(AAC(WXK_NUMPAD0).Shift(), "States_SaveSlot0");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD1).Shift(), "States_SaveSlot1");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD2).Shift(), "States_SaveSlot2");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD3).Shift(), "States_SaveSlot3");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD4).Shift(), "States_SaveSlot4");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD5).Shift(), "States_SaveSlot5");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD6).Shift(), "States_SaveSlot6");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD7).Shift(), "States_SaveSlot7");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD8).Shift(), "States_SaveSlot8");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD9).Shift(), "States_SaveSlot9");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD0), "States_LoadSlot0");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD1), "States_LoadSlot1");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD2), "States_LoadSlot2");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD3), "States_LoadSlot3");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD4), "States_LoadSlot4");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD5), "States_LoadSlot5");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD6), "States_LoadSlot6");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD7), "States_LoadSlot7");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD8), "States_LoadSlot8");
|
||||
m_Accels->Map(AAC(WXK_NUMPAD9), "States_LoadSlot9");
|
||||
|
||||
GetMainFramePtr()->initializeRecordingMenuItem(
|
||||
MenuId_Recording_FrameAdvance,
|
||||
GetAssociatedKeyCode("FrameAdvance"));
|
||||
GetMainFramePtr()->initializeRecordingMenuItem(
|
||||
MenuId_Recording_TogglePause,
|
||||
GetAssociatedKeyCode("TogglePause"));
|
||||
GetMainFramePtr()->initializeRecordingMenuItem(
|
||||
MenuId_Recording_ToggleRecordingMode,
|
||||
GetAssociatedKeyCode("InputRecordingModeToggle"),
|
||||
g_InputRecording.IsActive());
|
||||
|
||||
InputRec::consoleLog("Initialized Input Recording Key Bindings");
|
||||
}
|
||||
|
||||
wxString GSPanel::GetAssociatedKeyCode(const char* id)
|
||||
{
|
||||
return m_Accels->findKeycodeWithCommandId(id).toTitleizedString();
|
||||
}
|
||||
|
||||
void GSPanel::RemoveRecordingAccelerators()
|
||||
{
|
||||
m_Accels.reset(new AcceleratorDictionary);
|
||||
InitDefaultAccelerators();
|
||||
recordingConLog("Disabled Input Recording Key Bindings\n");
|
||||
}
|
||||
|
||||
GSPanel::GSPanel( wxWindow* parent )
|
||||
: wxWindow()
|
||||
, m_HideMouseTimer( this )
|
||||
|
@ -192,11 +127,6 @@ GSPanel::GSPanel( wxWindow* parent )
|
|||
|
||||
InitDefaultAccelerators();
|
||||
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
{
|
||||
InitRecordingAccelerators();
|
||||
}
|
||||
|
||||
SetBackgroundColour(wxColour((unsigned long)0));
|
||||
if( g_Conf->GSWindow.AlwaysHideMouse )
|
||||
{
|
||||
|
@ -899,17 +829,7 @@ void GSFrame::OnUpdateTitle( wxTimerEvent& evt )
|
|||
const u64& smode2 = *(u64*)PS2GS_BASE(GS_SMODE2);
|
||||
wxString omodef = (smode2 & 2) ? templates.OutputFrame : templates.OutputField;
|
||||
wxString omodei = (smode2 & 1) ? templates.OutputInterlaced : templates.OutputProgressive;
|
||||
wxString title;
|
||||
wxString movieMode;
|
||||
if (g_InputRecording.IsActive())
|
||||
{
|
||||
title = templates.RecordingTemplate;
|
||||
title.Replace(L"${frame}", pxsFmt(L"%d", g_InputRecording.GetFrameCounter()));
|
||||
title.Replace(L"${maxFrame}", pxsFmt(L"%d", g_InputRecording.GetInputRecordingData().GetTotalFrames()));
|
||||
title.Replace(L"${mode}", g_InputRecording.RecordingModeTitleSegment());
|
||||
} else {
|
||||
title = templates.TitleTemplate;
|
||||
}
|
||||
wxString title = templates.TitleTemplate;
|
||||
|
||||
std::string gsStats;
|
||||
GSgetTitleStats(gsStats);
|
||||
|
|
|
@ -53,8 +53,6 @@ public:
|
|||
void DirectKeyCommand( const KeyAcceleratorCode& kac );
|
||||
void InitDefaultAccelerators();
|
||||
wxString GetAssociatedKeyCode(const char* id);
|
||||
void InitRecordingAccelerators();
|
||||
void RemoveRecordingAccelerators();
|
||||
|
||||
protected:
|
||||
void AppStatusEvent_OnSettingsApplied();
|
||||
|
|
|
@ -305,10 +305,6 @@ namespace Implementations
|
|||
if (g_Conf->GSWindow.CloseOnEsc)
|
||||
{
|
||||
sMainFrame.SetFocus();
|
||||
// Disable recording controls that only make sense if the game is running
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_FrameAdvance, false);
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, false);
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,38 +416,6 @@ namespace Implementations
|
|||
if (GSFrame* gsframe = wxGetApp().GetGsFramePtr())
|
||||
gsframe->ShowFullScreen(!gsframe->IsFullScreen());
|
||||
}
|
||||
void FrameAdvance()
|
||||
{
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
{
|
||||
g_InputRecordingControls.FrameAdvance();
|
||||
}
|
||||
}
|
||||
|
||||
void TogglePause()
|
||||
{
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
{
|
||||
g_InputRecordingControls.TogglePause();
|
||||
}
|
||||
}
|
||||
|
||||
void InputRecordingModeToggle()
|
||||
{
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
{
|
||||
g_InputRecordingControls.RecordModeToggle();
|
||||
}
|
||||
}
|
||||
|
||||
void GoToFirstFrame()
|
||||
{
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools && g_InputRecording.IsActive())
|
||||
{
|
||||
// Assumes that gui is active, as you can't access recording options without it
|
||||
g_InputRecording.GoToFirstFrame(GetMainFramePtr());
|
||||
}
|
||||
}
|
||||
|
||||
void States_SaveSlot(int slot)
|
||||
{
|
||||
|
@ -730,11 +694,6 @@ static const GlobalCommandDescriptor CommandDeclarations[] =
|
|||
false,
|
||||
},
|
||||
|
||||
{"FrameAdvance", Implementations::FrameAdvance, NULL, NULL, false},
|
||||
{"TogglePause", Implementations::TogglePause, NULL, NULL, false},
|
||||
{"InputRecordingModeToggle", Implementations::InputRecordingModeToggle, NULL, NULL, false},
|
||||
{"GoToFirstFrame", Implementations::GoToFirstFrame, NULL, NULL, false},
|
||||
|
||||
{"States_SaveSlot0", Implementations::States_SaveSlot0, NULL, NULL, false},
|
||||
{"States_SaveSlot1", Implementations::States_SaveSlot1, NULL, NULL, false},
|
||||
{"States_SaveSlot2", Implementations::States_SaveSlot2, NULL, NULL, false},
|
||||
|
|
|
@ -69,16 +69,11 @@ void MainEmuFrame::UpdateStatusBar()
|
|||
{
|
||||
wxString temp(wxEmptyString);
|
||||
|
||||
if (g_InputRecording.IsActive() && g_InputRecording.GetInputRecordingData().FromSaveState())
|
||||
temp += "Base Savestate - " + g_InputRecording.GetInputRecordingData().GetFilename() + "_SaveState.p2s";
|
||||
else
|
||||
{
|
||||
if (g_Conf->EnableFastBoot)
|
||||
temp += "Fast Boot - ";
|
||||
if (g_Conf->EnableFastBoot)
|
||||
temp += "Fast Boot - ";
|
||||
|
||||
if (g_Conf->CdvdSource == CDVD_SourceType::Iso)
|
||||
temp += "Load: '" + wxFileName(g_Conf->CurrentIso).GetFullName() + "' ";
|
||||
}
|
||||
if (g_Conf->CdvdSource == CDVD_SourceType::Iso)
|
||||
temp += "Load: '" + wxFileName(g_Conf->CurrentIso).GetFullName() + "' ";
|
||||
|
||||
m_statusbar.SetStatusText(temp, 0);
|
||||
|
||||
|
@ -111,10 +106,7 @@ void MainEmuFrame::UpdateCdvdSrcSelection()
|
|||
jNO_DEFAULT
|
||||
}
|
||||
sMenuBar.Check(cdsrc, true);
|
||||
if (!g_InputRecording.IsActive())
|
||||
{
|
||||
ApplyCDVDStatus();
|
||||
}
|
||||
ApplyCDVDStatus();
|
||||
UpdateStatusBar();
|
||||
}
|
||||
|
||||
|
@ -311,17 +303,6 @@ void MainEmuFrame::ConnectMenus()
|
|||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Video_IncludeAudio_Click, this, MenuId_Capture_Video_IncludeAudio);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_Click, this, MenuId_Capture_Screenshot_Screenshot);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Capture_Screenshot_Screenshot_As_Click, this, MenuId_Capture_Screenshot_Screenshot_As);
|
||||
|
||||
// Recording
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_New_Click, this, MenuId_Recording_New);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_Play_Click, this, MenuId_Recording_Play);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_Stop_Click, this, MenuId_Recording_Stop);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_Config_FrameAdvance, this, MenuId_Recording_Config_FrameAdvance);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_TogglePause_Click, this, MenuId_Recording_TogglePause);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_FrameAdvance_Click, this, MenuId_Recording_FrameAdvance);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_ToggleRecordingMode_Click, this, MenuId_Recording_ToggleRecordingMode);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_VirtualPad_Open_Click, this, MenuId_Recording_VirtualPad_Port0);
|
||||
Bind(wxEVT_MENU, &MainEmuFrame::Menu_Recording_VirtualPad_Open_Click, this, MenuId_Recording_VirtualPad_Port1);
|
||||
}
|
||||
|
||||
void MainEmuFrame::InitLogBoxPosition(AppConfig::ConsoleLogOptions& conf)
|
||||
|
@ -393,7 +374,7 @@ void MainEmuFrame::CreatePcsx2Menu()
|
|||
_("Enabling Widescreen Patches may occasionally cause issues."), wxITEM_CHECK);
|
||||
|
||||
m_GameSettingsSubmenu.Append(MenuId_EnableInputRecording, _("Enable &Input Recording"),
|
||||
_("Input Recording for controller/keyboard presses, tools for automation and playback."), wxITEM_CHECK);
|
||||
_("Input Recording for controller/keyboard presses, tools for automation and playback."), wxITEM_NORMAL);
|
||||
|
||||
m_GameSettingsSubmenu.Append(MenuId_EnableHostFs, _("Enable &Host Filesystem"),
|
||||
wxEmptyString, wxITEM_CHECK);
|
||||
|
@ -583,11 +564,6 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title)
|
|||
|
||||
SetMenuBar(&m_menubar);
|
||||
|
||||
// Append the Recording options if previously enabled and setting has been picked up from ini
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
{
|
||||
m_menubar.Append(&m_menuRecording, _("&Input Record"));
|
||||
}
|
||||
m_menubar.Append(&m_menuHelp, _("&Help"));
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -813,12 +789,6 @@ void MainEmuFrame::ApplyConfigToGui(AppConfig& configToApply, int flags)
|
|||
menubar.Check(MenuId_EnableWideScreenPatches, configToApply.EmuOptions.EnableWideScreenPatches);
|
||||
menubar.Check(MenuId_Capture_Video_IncludeAudio, configToApply.AudioCapture.EnableAudio);
|
||||
|
||||
menubar.Check(MenuId_EnableInputRecording, configToApply.EmuOptions.EnableRecordingTools);
|
||||
wxString frame_advance_label = wxString(_("Configure Frame Advance"));
|
||||
frame_advance_label.Append(wxString::Format(" (%d)", configToApply.inputRecording.m_frame_advance_amount));
|
||||
m_submenu_recording_settings.SetLabel(MenuId_Recording_Config_FrameAdvance, frame_advance_label);
|
||||
g_InputRecordingControls.setFrameAdvanceAmount(configToApply.inputRecording.m_frame_advance_amount);
|
||||
|
||||
menubar.Check(MenuId_EnableHostFs, configToApply.EmuOptions.HostFs);
|
||||
menubar.Check(MenuId_Debug_CreateBlockdump, configToApply.EmuOptions.CdvdDumpBlocks);
|
||||
#if defined(__POSIX__)
|
||||
|
@ -847,18 +817,3 @@ void MainEmuFrame::AppendShortcutToMenuOption(wxMenuItem& item, wxString keyCode
|
|||
const size_t tabPos = text.rfind(L'\t');
|
||||
item.SetItemLabel(text.Mid(0, tabPos) + L"\t" + keyCodeStr);
|
||||
}
|
||||
|
||||
void MainEmuFrame::initializeRecordingMenuItem(MenuIdentifiers menuId, wxString keyCodeStr, bool enable)
|
||||
{
|
||||
wxMenuItem& item = *m_menuRecording.FindChildItem(menuId);
|
||||
wxString text = item.GetItemLabel();
|
||||
const size_t tabPos = text.rfind(L'\t');
|
||||
item.SetItemLabel(text.Mid(0, tabPos) + L"\t" + keyCodeStr);
|
||||
item.Enable(enable);
|
||||
}
|
||||
|
||||
void MainEmuFrame::enableRecordingMenuItem(MenuIdentifiers menuId, bool enable)
|
||||
{
|
||||
wxMenuItem& item = *m_menuRecording.FindChildItem(menuId);
|
||||
item.Enable(enable);
|
||||
}
|
||||
|
|
|
@ -122,11 +122,6 @@ public:
|
|||
void VideoCaptureToggle();
|
||||
bool IsCapturing() const noexcept { return m_capturingVideo; }
|
||||
|
||||
void initializeRecordingMenuItem(MenuIdentifiers menuId, wxString keyCodeStr, bool enable = true);
|
||||
void enableRecordingMenuItem(MenuIdentifiers menuId, bool enable);
|
||||
void StartInputRecording();
|
||||
void StopInputRecording();
|
||||
|
||||
protected:
|
||||
void DoGiveHelp(const wxString& text, bool show);
|
||||
|
||||
|
@ -205,16 +200,6 @@ protected:
|
|||
void Menu_Capture_Screenshot_Screenshot_Click(wxCommandEvent& event);
|
||||
void Menu_Capture_Screenshot_Screenshot_As_Click(wxCommandEvent& event);
|
||||
|
||||
void Menu_Recording_New_Click(wxCommandEvent& event);
|
||||
void Menu_Recording_Play_Click(wxCommandEvent& event);
|
||||
void Menu_Recording_Stop_Click(wxCommandEvent& event);
|
||||
void Menu_Recording_Config_FrameAdvance(wxCommandEvent& event);
|
||||
void ApplyFirstFrameStatus();
|
||||
void Menu_Recording_TogglePause_Click(wxCommandEvent& event);
|
||||
void Menu_Recording_FrameAdvance_Click(wxCommandEvent& event);
|
||||
void Menu_Recording_ToggleRecordingMode_Click(wxCommandEvent& event);
|
||||
void Menu_Recording_VirtualPad_Open_Click(wxCommandEvent& event);
|
||||
|
||||
void _DoBootCdvd();
|
||||
bool _DoSelectIsoBrowser(wxString& dest);
|
||||
bool _DoSelectELFBrowser();
|
||||
|
|
|
@ -38,10 +38,6 @@
|
|||
#include "fmt/core.h"
|
||||
#include "wx/numdlg.h"
|
||||
|
||||
#include "Recording/InputRecording.h"
|
||||
#include "Recording/InputRecordingControls.h"
|
||||
#include "Recording/VirtualPad/VirtualPad.h"
|
||||
|
||||
|
||||
using namespace Dialogs;
|
||||
|
||||
|
@ -165,7 +161,7 @@ void MainEmuFrame::Menu_ResetAllSettings_Click(wxCommandEvent& event)
|
|||
ScopedCoreThreadPopup suspender;
|
||||
if (!Msgbox::OkCancel(pxsFmt(
|
||||
pxE(L"This command clears %s settings and allows you to re-run the First-Time Wizard. You will need to manually restart %s after this operation.\n\nWARNING!! Click OK to delete *ALL* settings for %s and force-close the app, losing any current emulation progress. Are you absolutely sure?"), WX_STR(pxGetAppName()), WX_STR(pxGetAppName()), WX_STR(pxGetAppName())),
|
||||
_("Reset all settings?")))
|
||||
_("Reset all settings?")))
|
||||
{
|
||||
suspender.AllowResume();
|
||||
return;
|
||||
|
@ -205,9 +201,6 @@ wxWindowID SwapOrReset_Iso(wxWindow* owner, IScopedCoreThread& core_control, con
|
|||
dialog += dialog.GetCharHeight();
|
||||
dialog += dialog.Heading(_("Do you want to swap discs or boot the new image (via system reset)?"));
|
||||
|
||||
if (g_InputRecording.IsActive() && g_InputRecording.GetInputRecordingData().FromSaveState())
|
||||
dialog += dialog.Text(_("\n(Warning: The savestate accompanying the active input recording\nmay not be compatible with the new source)"));
|
||||
|
||||
result = pxIssueConfirmation(dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap"));
|
||||
if (result == wxID_CANCEL)
|
||||
{
|
||||
|
@ -264,9 +257,6 @@ wxWindowID SwapOrReset_Disc(wxWindow* owner, IScopedCoreThread& core, const wxSt
|
|||
dialog += dialog.GetCharHeight();
|
||||
dialog += dialog.Heading(_("Do you want to swap discs or boot the new disc (via system reset)?"));
|
||||
|
||||
if (g_InputRecording.IsActive() && g_InputRecording.GetInputRecordingData().FromSaveState())
|
||||
dialog += dialog.Text(_("\n(Warning: The savestate accompanying the active input recording\nmay not be compatible with the new source)"));
|
||||
|
||||
result = pxIssueConfirmation(dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap"));
|
||||
if (result == wxID_CANCEL)
|
||||
{
|
||||
|
@ -309,14 +299,11 @@ wxWindowID SwapOrReset_CdvdSrc(wxWindow* owner, CDVD_SourceType newsrc)
|
|||
|
||||
wxString changeMsg;
|
||||
changeMsg.Printf(_("You've selected to switch the CDVD source from %s to %s."),
|
||||
CDVD_SourceLabels[enum_cast(g_Conf->CdvdSource)], CDVD_SourceLabels[enum_cast(newsrc)]);
|
||||
CDVD_SourceLabels[enum_cast(g_Conf->CdvdSource)], CDVD_SourceLabels[enum_cast(newsrc)]);
|
||||
|
||||
dialog += dialog.Heading(changeMsg + L"\n\n" +
|
||||
_("Do you want to swap discs or boot the new image (system reset)?"));
|
||||
|
||||
if (g_InputRecording.IsActive() && g_InputRecording.GetInputRecordingData().FromSaveState())
|
||||
dialog += dialog.Text(_("\n(Warning: The savestate accompanying the active input recording\nmay not be compatible with the new source)"));
|
||||
|
||||
result = pxIssueConfirmation(dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap"));
|
||||
|
||||
if (result == wxID_CANCEL)
|
||||
|
@ -334,8 +321,8 @@ wxWindowID SwapOrReset_CdvdSrc(wxWindow* owner, CDVD_SourceType newsrc)
|
|||
if (result != wxID_RESET)
|
||||
{
|
||||
Console.Indent().WriteLn("(CdvdSource) HotSwapping CDVD source types from %ls to %ls.",
|
||||
WX_STR(wxString(CDVD_SourceLabels[enum_cast(oldsrc)])),
|
||||
WX_STR(wxString(CDVD_SourceLabels[enum_cast(newsrc)])));
|
||||
WX_STR(wxString(CDVD_SourceLabels[enum_cast(oldsrc)])),
|
||||
WX_STR(wxString(CDVD_SourceLabels[enum_cast(newsrc)])));
|
||||
//CoreThread.ChangeCdvdSource();
|
||||
sMainFrame.UpdateCdvdSrcSelection();
|
||||
core.AllowResume();
|
||||
|
@ -401,7 +388,7 @@ bool MainEmuFrame::_DoSelectIsoBrowser(wxString& result)
|
|||
isoFilterTypes.Add(L"*.*");
|
||||
|
||||
wxFileDialog ctrl(this, _("Select disc image, compressed disc image, or block-dump..."), g_Conf->Folders.RunIso.ToString(), wxEmptyString,
|
||||
JoinString(isoFilterTypes, L"|"), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
JoinString(isoFilterTypes, L"|"), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
|
||||
if (ctrl.ShowModal() != wxID_CANCEL)
|
||||
{
|
||||
|
@ -418,7 +405,7 @@ bool MainEmuFrame::_DoSelectELFBrowser()
|
|||
static const wxChar* elfFilterType = L"ELF Files (.elf)|*.elf;*.ELF";
|
||||
|
||||
wxFileDialog ctrl(this, _("Select ELF file..."), g_Conf->Folders.RunELF.ToString(), wxEmptyString,
|
||||
(wxString)elfFilterType + L"|" + _("All Files (*.*)") + L"|*.*", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
(wxString)elfFilterType + L"|" + _("All Files (*.*)") + L"|*.*", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
|
||||
if (ctrl.ShowModal() != wxID_CANCEL)
|
||||
{
|
||||
|
@ -506,23 +493,13 @@ void MainEmuFrame::Menu_CdvdSource_Click(wxCommandEvent& event)
|
|||
}
|
||||
|
||||
SwapOrReset_CdvdSrc(this, newsrc);
|
||||
if (!g_InputRecording.IsActive())
|
||||
{
|
||||
ApplyCDVDStatus();
|
||||
}
|
||||
ApplyCDVDStatus();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_BootCdvd_Click(wxCommandEvent& event)
|
||||
{
|
||||
if (g_InputRecording.IsActive())
|
||||
{
|
||||
g_InputRecording.GoToFirstFrame(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Conf->EmuOptions.UseBOOT2Injection = g_Conf->EnableFastBoot;
|
||||
_DoBootCdvd();
|
||||
}
|
||||
g_Conf->EmuOptions.UseBOOT2Injection = g_Conf->EnableFastBoot;
|
||||
_DoBootCdvd();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_FastBoot_Click(wxCommandEvent& event)
|
||||
|
@ -681,66 +658,8 @@ void MainEmuFrame::Menu_EnableWideScreenPatches_Click(wxCommandEvent&)
|
|||
|
||||
void MainEmuFrame::Menu_EnableRecordingTools_Click(wxCommandEvent& event)
|
||||
{
|
||||
bool checked = GetMenuBar()->IsChecked(MenuId_EnableInputRecording);
|
||||
// Confirm with User
|
||||
if (checked)
|
||||
{
|
||||
if (!Msgbox::OkCancel(_("Please be aware that PCSX2's input recording features are still very much a work-in-progress.\n"
|
||||
"As a result, there may be unforeseen bugs, performance implications and instability with certain games.\n\n"
|
||||
"These tools are provided as-is and should be enabled under your own discretion."),
|
||||
"Enabling Input Recording"))
|
||||
{
|
||||
checked = false;
|
||||
m_GameSettingsSubmenu.FindChildItem(MenuId_EnableInputRecording)->Check(false);
|
||||
}
|
||||
}
|
||||
|
||||
// If still enabled, add the menu item, else, remove it
|
||||
if (checked)
|
||||
{
|
||||
GetMenuBar()->Insert(TopLevelMenu_InputRecording, &m_menuRecording, _("&Input Record"));
|
||||
g_InputRecording.InitVirtualPadWindows(this);
|
||||
SysConsole.recordingConsole.Enabled = true;
|
||||
// Enable Recording Keybindings
|
||||
if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr())
|
||||
{
|
||||
if (GSPanel* viewport = gsFrame->GetViewport())
|
||||
{
|
||||
viewport->InitRecordingAccelerators();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Properly close any currently loaded recording file before disabling
|
||||
StopInputRecording();
|
||||
GetMenuBar()->Remove(TopLevelMenu_InputRecording);
|
||||
// Always turn controller logs off, but never turn it on by default
|
||||
SysConsole.controlInfo.Enabled = checked;
|
||||
// Return Keybindings Back to Normal
|
||||
if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr())
|
||||
{
|
||||
if (GSPanel* viewport = gsFrame->GetViewport())
|
||||
{
|
||||
viewport->RemoveRecordingAccelerators();
|
||||
}
|
||||
}
|
||||
SysConsole.recordingConsole.Enabled = false;
|
||||
if (g_InputRecordingControls.IsPaused())
|
||||
g_InputRecordingControls.Resume();
|
||||
}
|
||||
|
||||
g_Conf->EmuOptions.EnableRecordingTools = checked;
|
||||
// Update GS Title Frequency
|
||||
if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr())
|
||||
{
|
||||
gsFrame->UpdateTitleUpdateFreq();
|
||||
}
|
||||
// Enable Recording Logs
|
||||
ConsoleLogFrame* progLog = wxGetApp().GetProgramLog();
|
||||
progLog->UpdateLogList();
|
||||
AppApplySettings();
|
||||
AppSaveSettings();
|
||||
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build (before v1.7.3650) or switch to the Qt version!\nOld recordings should still play correctly!");
|
||||
return;
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_EnableHostFs_Click(wxCommandEvent&)
|
||||
|
@ -782,7 +701,7 @@ void MainEmuFrame::Menu_SaveStates_Click(wxCommandEvent& event)
|
|||
void MainEmuFrame::Menu_LoadStateFromFile_Click(wxCommandEvent& event)
|
||||
{
|
||||
wxFileDialog loadStateDialog(this, _("Load State"), L"", L"",
|
||||
L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
|
||||
L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
|
||||
|
||||
if (loadStateDialog.ShowModal() == wxID_CANCEL)
|
||||
{
|
||||
|
@ -796,7 +715,7 @@ void MainEmuFrame::Menu_LoadStateFromFile_Click(wxCommandEvent& event)
|
|||
void MainEmuFrame::Menu_SaveStateToFile_Click(wxCommandEvent& event)
|
||||
{
|
||||
wxFileDialog saveStateDialog(this, _("Save State"), L"", L"",
|
||||
L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
|
||||
L"Savestate files (*.p2s)|*.p2s", wxFD_OPEN);
|
||||
|
||||
if (saveStateDialog.ShowModal() == wxID_CANCEL)
|
||||
{
|
||||
|
@ -825,10 +744,6 @@ protected:
|
|||
if (CoreThread.IsOpen())
|
||||
{
|
||||
CoreThread.Suspend();
|
||||
// Disable recording controls that only make sense if the game is running
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_FrameAdvance, false);
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_TogglePause, false);
|
||||
sMainFrame.enableRecordingMenuItem(MenuId_Recording_ToggleRecordingMode, false);
|
||||
}
|
||||
else
|
||||
CoreThread.Resume();
|
||||
|
@ -849,40 +764,11 @@ void MainEmuFrame::Menu_SuspendResume_Click(wxCommandEvent& event)
|
|||
|
||||
void MainEmuFrame::Menu_SysShutdown_Click(wxCommandEvent& event)
|
||||
{
|
||||
bool doShutdown = true;
|
||||
if (!g_InputRecording.IsActive())
|
||||
{
|
||||
if (g_InputRecordingControls.IsPaused())
|
||||
g_InputRecordingControls.Resume();
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool initiallyPaused = g_InputRecordingControls.IsPaused();
|
||||
if (!initiallyPaused)
|
||||
g_InputRecordingControls.Pause();
|
||||
wxWindowID result = wxID_CANCEL;
|
||||
wxDialogWithHelpers dialog(this, _("Shutdown & Close Input Recording"));
|
||||
dialog += dialog.Heading(L"\nShutting down emulation will close the active input recording file.\nProceed?");
|
||||
result = pxIssueConfirmation(dialog, MsgButtons().Close().Cancel());
|
||||
if (result == wxID_CLOSE)
|
||||
{
|
||||
StopInputRecording();
|
||||
g_InputRecordingControls.Resume();
|
||||
}
|
||||
else if (!initiallyPaused)
|
||||
{
|
||||
g_InputRecordingControls.Resume();
|
||||
doShutdown = false;
|
||||
}
|
||||
}
|
||||
if (doShutdown)
|
||||
{
|
||||
if (m_capturingVideo)
|
||||
VideoCaptureToggle();
|
||||
UI_DisableSysShutdown();
|
||||
Console.SetTitle("PCSX2 Program Log");
|
||||
CoreThread.Reset();
|
||||
}
|
||||
if (m_capturingVideo)
|
||||
VideoCaptureToggle();
|
||||
UI_DisableSysShutdown();
|
||||
Console.SetTitle("PCSX2 Program Log");
|
||||
CoreThread.Reset();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Debug_Open_Click(wxCommandEvent& event)
|
||||
|
@ -1049,151 +935,3 @@ void MainEmuFrame::Menu_Capture_Screenshot_Screenshot_As_Click(wxCommandEvent& e
|
|||
CoreThread.Resume();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Recording_New_Click(wxCommandEvent& event)
|
||||
{
|
||||
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
|
||||
return;
|
||||
const bool emulation_initially_paused = CoreThread.IsPaused();
|
||||
const bool recording_initially_paused = g_InputRecordingControls.IsPaused();
|
||||
|
||||
if (!emulation_initially_paused && !recording_initially_paused)
|
||||
g_InputRecordingControls.PauseImmediately();
|
||||
|
||||
NewRecordingFrame* newRecordingFrame = wxGetApp().GetNewRecordingFramePtr();
|
||||
if (newRecordingFrame)
|
||||
{
|
||||
if (newRecordingFrame->ShowModal(CoreThread.IsOpen()) != wxID_CANCEL)
|
||||
{
|
||||
if (g_InputRecording.Create(newRecordingFrame->GetFile(), newRecordingFrame->GetFrom(), newRecordingFrame->GetAuthor()))
|
||||
{
|
||||
if (!g_InputRecording.GetInputRecordingData().FromSaveState())
|
||||
StartInputRecording();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!emulation_initially_paused && !recording_initially_paused)
|
||||
g_InputRecordingControls.ResumeImmediately();
|
||||
}
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Recording_Play_Click(wxCommandEvent& event)
|
||||
{
|
||||
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
|
||||
return;
|
||||
const bool initiallyPaused = g_InputRecordingControls.IsPaused();
|
||||
|
||||
if (!initiallyPaused)
|
||||
g_InputRecordingControls.PauseImmediately();
|
||||
|
||||
wxFileDialog openFileDialog(this, _("Select P2M2 record file."), L"", L"",
|
||||
L"p2m2 file(*.p2m2)|*.p2m2", wxFD_OPEN);
|
||||
if (openFileDialog.ShowModal() == wxID_CANCEL)
|
||||
{
|
||||
if (!initiallyPaused)
|
||||
g_InputRecordingControls.Resume();
|
||||
return;
|
||||
}
|
||||
|
||||
StopInputRecording();
|
||||
if (!g_InputRecording.Play(this, openFileDialog.GetPath()))
|
||||
{
|
||||
if (!initiallyPaused)
|
||||
g_InputRecordingControls.Resume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_InputRecording.GetInputRecordingData().FromSaveState())
|
||||
StartInputRecording();
|
||||
}
|
||||
|
||||
void MainEmuFrame::ApplyFirstFrameStatus()
|
||||
{
|
||||
wxMenuItem* cdvd_menu = m_menuSys.FindChildItem(MenuId_Boot_CDVD);
|
||||
|
||||
wxString keyCodeStr;
|
||||
if (GSFrame* gsFrame = wxGetApp().GetGsFramePtr())
|
||||
if (GSPanel* viewport = gsFrame->GetViewport())
|
||||
keyCodeStr = '\t' + viewport->GetAssociatedKeyCode(("GoToFirstFrame"));
|
||||
|
||||
cdvd_menu->SetItemLabel(L"Restart Recording" + keyCodeStr);
|
||||
if (g_InputRecording.GetInputRecordingData().FromSaveState())
|
||||
cdvd_menu->SetHelp(L"Loads the savestate that accompanies the active input recording");
|
||||
else
|
||||
cdvd_menu->SetHelp(L"Reboots Emulation");
|
||||
|
||||
UpdateStatusBar();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Recording_Stop_Click(wxCommandEvent& event)
|
||||
{
|
||||
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
|
||||
return;
|
||||
StopInputRecording();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Recording_Config_FrameAdvance(wxCommandEvent& event)
|
||||
{
|
||||
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
|
||||
return;
|
||||
long result = wxGetNumberFromUser(_("Enter the number of frames to advance per advance"), _("Number of Frames"), _("Configure Frame Advance"), g_Conf->inputRecording.m_frame_advance_amount, 1, INT_MAX);
|
||||
if (result != -1)
|
||||
{
|
||||
g_Conf->inputRecording.m_frame_advance_amount = result;
|
||||
g_InputRecordingControls.setFrameAdvanceAmount(result);
|
||||
wxString frame_advance_label = wxString(_("Configure Frame Advance"));
|
||||
frame_advance_label.Append(wxString::Format(" (%ld)", result));
|
||||
m_submenu_recording_settings.SetLabel(MenuId_Recording_Config_FrameAdvance, frame_advance_label);
|
||||
}
|
||||
}
|
||||
|
||||
void MainEmuFrame::StartInputRecording()
|
||||
{
|
||||
m_menuRecording.FindChildItem(MenuId_Recording_New)->Enable(false);
|
||||
m_menuRecording.FindChildItem(MenuId_Recording_Stop)->Enable(true);
|
||||
m_menuRecording.FindChildItem(MenuId_Recording_ToggleRecordingMode)->Enable(true);
|
||||
ApplyFirstFrameStatus();
|
||||
}
|
||||
|
||||
void MainEmuFrame::StopInputRecording()
|
||||
{
|
||||
if (g_InputRecording.IsActive())
|
||||
{
|
||||
g_InputRecording.Stop();
|
||||
m_menuRecording.FindChildItem(MenuId_Recording_New)->Enable(true);
|
||||
m_menuRecording.FindChildItem(MenuId_Recording_Stop)->Enable(false);
|
||||
m_menuRecording.FindChildItem(MenuId_Recording_ToggleRecordingMode)->Enable(false);
|
||||
ApplyCDVDStatus();
|
||||
}
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Recording_TogglePause_Click(wxCommandEvent& event)
|
||||
{
|
||||
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
|
||||
return;
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
g_InputRecordingControls.TogglePause();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Recording_FrameAdvance_Click(wxCommandEvent& event)
|
||||
{
|
||||
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
|
||||
return;
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
g_InputRecordingControls.FrameAdvance();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Recording_ToggleRecordingMode_Click(wxCommandEvent& event)
|
||||
{
|
||||
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
|
||||
return;
|
||||
if (g_Conf->EmuOptions.EnableRecordingTools)
|
||||
g_InputRecordingControls.RecordModeToggle();
|
||||
}
|
||||
|
||||
void MainEmuFrame::Menu_Recording_VirtualPad_Open_Click(wxCommandEvent& event)
|
||||
{
|
||||
Msgbox::Alert("Input Recording has been deprecated from the wxWidgets version.\nUse an older dev build or switch to the Qt version!\nOld recordings should still play correctly!");
|
||||
return;
|
||||
g_InputRecording.ShowVirtualPad(event.GetId() - MenuId_Recording_VirtualPad_Port0);
|
||||
}
|
||||
|
|
|
@ -171,82 +171,6 @@
|
|||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<!-- Generate Recording GUI Image Headers -->
|
||||
<CustomBuild Include="Recording\VirtualPad\img\controllerFull.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\controllerThreeQuarters.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\controllerHalf.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\circlePressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\crossPressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\downPressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\l1Pressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\l2Pressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\l3Pressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\leftPressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\r1Pressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\r2Pressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\r3Pressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\rightPressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\selectPressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\squarePressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\startPressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\trianglePressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\upPressed.png">
|
||||
<Command>cmd.exe /c %(RelativeDir)bin2cpp.cmd %(Filename)%(Extension)</Command>
|
||||
<Outputs>%(RelativeDir)%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CDVD\BlockdumpFileReader.cpp" />
|
||||
|
@ -449,13 +373,9 @@
|
|||
<ClCompile Include="ps2\pgif.cpp" />
|
||||
<ClCompile Include="Dmac.cpp" />
|
||||
<ClCompile Include="Recording\InputRecordingControls.cpp" />
|
||||
<ClCompile Include="Recording\VirtualPad\VirtualPad.cpp" />
|
||||
<ClCompile Include="Recording\VirtualPad\VirtualPadData.cpp" />
|
||||
<ClCompile Include="Recording\VirtualPad\VirtualPadResources.cpp" />
|
||||
<ClCompile Include="ShiftJisToUnicode.cpp" />
|
||||
<ClCompile Include="sif2.cpp" />
|
||||
<ClCompile Include="Recording\InputRecording.cpp" />
|
||||
<ClCompile Include="Recording\NewRecordingFrame.cpp" />
|
||||
<ClCompile Include="Recording\InputRecordingFile.cpp" />
|
||||
<ClCompile Include="Recording\PadData.cpp" />
|
||||
<ClCompile Include="USB\configuration.cpp" />
|
||||
|
@ -963,12 +883,8 @@
|
|||
<ClInclude Include="ps2\pgif.h" />
|
||||
<ClInclude Include="Recording\InputRecording.h" />
|
||||
<ClInclude Include="Recording\InputRecordingControls.h" />
|
||||
<ClInclude Include="Recording\NewRecordingFrame.h" />
|
||||
<ClInclude Include="Recording\InputRecordingFile.h" />
|
||||
<ClInclude Include="Recording\PadData.h" />
|
||||
<ClInclude Include="Recording\VirtualPad\VirtualPad.h" />
|
||||
<ClInclude Include="Recording\VirtualPad\VirtualPadData.h" />
|
||||
<ClInclude Include="Recording\VirtualPad\VirtualPadResources.h" />
|
||||
<ClInclude Include="Recording\Utilities\InputRecordingLogger.h" />
|
||||
<ClInclude Include="USB\configuration.h" />
|
||||
<ClInclude Include="USB\deviceproxy.h" />
|
||||
|
|
|
@ -142,12 +142,6 @@
|
|||
<Filter Include="Recording">
|
||||
<UniqueIdentifier>{7b917318-5a5e-44c0-8463-1dfab67f3b67}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recording\gui">
|
||||
<UniqueIdentifier>{93e36831-627f-4529-b709-1f4bad398512}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recording\VirtualPad">
|
||||
<UniqueIdentifier>{ae88cd9a-f9f2-4196-979c-7a16ed5e455e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="System\Ps2\Iop\CDVD\Windows">
|
||||
<UniqueIdentifier>{be861049-a142-4650-85a5-a2fdd4eef011}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
@ -163,9 +157,6 @@
|
|||
<Filter Include="Recording\Utilities">
|
||||
<UniqueIdentifier>{85c5a0d2-6404-439f-8756-d908a1442b96}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Recording\VirtualPad\Images">
|
||||
<UniqueIdentifier>{ad528458-08eb-49a2-aefa-3c2b86ab8896}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="System\Ps2\DEV9">
|
||||
<UniqueIdentifier>{8d5454f9-590c-4c53-aae1-8391c6465e50}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
@ -1049,24 +1040,12 @@
|
|||
<ClCompile Include="Recording\PadData.cpp">
|
||||
<Filter>Recording</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Recording\NewRecordingFrame.cpp">
|
||||
<Filter>Recording\gui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Recording\VirtualPad\VirtualPad.cpp">
|
||||
<Filter>Recording\VirtualPad</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPU\IPUdither.cpp">
|
||||
<Filter>System\Ps2\IPU</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Recording\InputRecordingControls.cpp">
|
||||
<Filter>Recording</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Recording\VirtualPad\VirtualPadData.cpp">
|
||||
<Filter>Recording\VirtualPad</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Recording\VirtualPad\VirtualPadResources.cpp">
|
||||
<Filter>Recording\VirtualPad</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CDVD\CDVDdiscReader.cpp">
|
||||
<Filter>System\Ps2\Iop\CDVD</Filter>
|
||||
</ClCompile>
|
||||
|
@ -2263,21 +2242,9 @@
|
|||
<ClInclude Include="Recording\PadData.h">
|
||||
<Filter>Recording</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Recording\NewRecordingFrame.h">
|
||||
<Filter>Recording\gui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Recording\VirtualPad\VirtualPad.h">
|
||||
<Filter>Recording\VirtualPad</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Recording\InputRecordingControls.h">
|
||||
<Filter>Recording</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Recording\VirtualPad\VirtualPadData.h">
|
||||
<Filter>Recording\VirtualPad</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Recording\VirtualPad\VirtualPadResources.h">
|
||||
<Filter>Recording\VirtualPad</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CDVD\CDVDdiscReader.h">
|
||||
<Filter>System\Ps2\Iop\CDVD</Filter>
|
||||
</ClInclude>
|
||||
|
@ -3101,67 +3068,10 @@
|
|||
<CustomBuild Include="gui\Resources\Logo.png">
|
||||
<Filter>AppHost\Resources</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\circlePressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\controllerFull.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\controllerHalf.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\controllerThreeQuarters.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\crossPressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\downPressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\l1Pressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\l2Pressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\l3Pressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\leftPressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\startPressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\r1Pressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\r2Pressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\r3Pressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\rightPressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\selectPressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\squarePressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\trianglePressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Recording\VirtualPad\img\upPressed.png">
|
||||
<Filter>Recording\VirtualPad\Images</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="windows\PCSX2.manifest">
|
||||
<Filter>AppHost\Resources</Filter>
|
||||
</Manifest>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|