mirror of https://github.com/PCSX2/pcsx2.git
recording: Disable widgets in replay mode, simplify ControllerInterrupt
recording: Added some comments to the more complex parts
This commit is contained in:
parent
bbc305d2b9
commit
32047c6130
|
@ -54,13 +54,11 @@ InputRecording g_InputRecording;
|
||||||
InputRecording::InputRecording()
|
InputRecording::InputRecording()
|
||||||
{
|
{
|
||||||
// NOTE - No multi-tap support, only two controllers
|
// NOTE - No multi-tap support, only two controllers
|
||||||
for (int i = 0; i < 2; i++)
|
padData[CONTROLLER_PORT_ONE] = new PadData();
|
||||||
{
|
padData[CONTROLLER_PORT_TWO] = new PadData();
|
||||||
padData[i] = new PadData();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputRecording::setVirtualPadPtr(VirtualPad *ptr, int port)
|
void InputRecording::SetVirtualPadPtr(VirtualPad *ptr, int const port)
|
||||||
{
|
{
|
||||||
virtualPads[port] = ptr;
|
virtualPads[port] = ptr;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +145,8 @@ void InputRecording::ControllerInterrupt(u8 &data, u8 &port, u16 &bufCount, u8 b
|
||||||
{
|
{
|
||||||
// If the VirtualPad updated the PadData, we have to update the buffer
|
// If the VirtualPad updated the PadData, we have to update the buffer
|
||||||
// before committing it to the recording / sending it to the game
|
// before committing it to the recording / sending it to the game
|
||||||
if (virtualPads[port]->UpdateControllerData(bufIndex, padData[port]))
|
// - Do not do this if we are in replay mode!
|
||||||
|
if (virtualPads[port]->UpdateControllerData(bufIndex, padData[port]) && state != INPUT_RECORDING_MODE_REPLAY)
|
||||||
{
|
{
|
||||||
bufVal = padData[port]->PollControllerData(bufIndex);
|
bufVal = padData[port]->PollControllerData(bufIndex);
|
||||||
}
|
}
|
||||||
|
@ -156,6 +155,7 @@ void InputRecording::ControllerInterrupt(u8 &data, u8 &port, u16 &bufCount, u8 b
|
||||||
// If we have reached the end of the pad data, log it out
|
// If we have reached the end of the pad data, log it out
|
||||||
if (bufIndex == PadData::END_INDEX_CONTROLLER_BUFFER) {
|
if (bufIndex == PadData::END_INDEX_CONTROLLER_BUFFER) {
|
||||||
padData[port]->LogPadData(port);
|
padData[port]->LogPadData(port);
|
||||||
|
// As well as re-render the virtual pad UI, if applicable
|
||||||
if (virtualPads[port] && virtualPads[port]->IsShown())
|
if (virtualPads[port] && virtualPads[port]->IsShown())
|
||||||
{
|
{
|
||||||
virtualPads[port]->Redraw();
|
virtualPads[port]->Redraw();
|
||||||
|
|
|
@ -86,7 +86,7 @@ public:
|
||||||
// Stop the active input recording
|
// Stop the active input recording
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
void setVirtualPadPtr(VirtualPad *ptr, int port);
|
void SetVirtualPadPtr(VirtualPad *ptr, int const port);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class InputRecordingMode
|
enum class InputRecordingMode
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
void PadData::UpdateControllerData(u16 bufIndex, u8 const &bufVal)
|
void PadData::UpdateControllerData(u16 bufIndex, u8 const &bufVal)
|
||||||
{
|
{
|
||||||
BufferIndex index = static_cast<BufferIndex>(bufIndex);
|
const BufferIndex index = static_cast<BufferIndex>(bufIndex);
|
||||||
switch (index)
|
switch (index)
|
||||||
{
|
{
|
||||||
case BufferIndex::PressedFlagsGroupOne:
|
case BufferIndex::PressedFlagsGroupOne:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
/* PCSX2 - PS2 Emulator for PCs
|
||||||
* Copyright (C) 2002-2019 PCSX2 Dev Team
|
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||||
*
|
*
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
* 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-
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||||
|
@ -97,13 +97,10 @@ VirtualPad::VirtualPad(wxWindow* parent, wxWindowID id, const wxString& title, i
|
||||||
|
|
||||||
// Bind Window Events
|
// Bind Window Events
|
||||||
Bind(wxEVT_ERASE_BACKGROUND, &VirtualPad::OnEraseBackground, this);
|
Bind(wxEVT_ERASE_BACKGROUND, &VirtualPad::OnEraseBackground, this);
|
||||||
Bind(wxEVT_MOTION, &VirtualPad::OnMouseEvent, this);
|
|
||||||
Bind(wxEVT_CLOSE_WINDOW, &VirtualPad::OnClose, this);
|
Bind(wxEVT_CLOSE_WINDOW, &VirtualPad::OnClose, this);
|
||||||
Bind(wxEVT_SET_FOCUS, &VirtualPad::OnFocusEvent, this);
|
|
||||||
Bind(wxEVT_KILL_FOCUS, &VirtualPad::OnFocusEvent, this);
|
|
||||||
// Temporary Paint event handler so the window displays properly before the controller-interrupt routine takes over with manual drawing.
|
// 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
|
// 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
|
// 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);
|
Bind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
|
||||||
|
|
||||||
// Finalize layout
|
// Finalize layout
|
||||||
|
@ -124,18 +121,6 @@ void VirtualPad::OnClose(wxCloseEvent & event)
|
||||||
Hide();
|
Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualPad::OnMouseEvent(wxMouseEvent &evt)
|
|
||||||
{
|
|
||||||
evt.Skip();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VirtualPad::OnFocusEvent(wxFocusEvent &evt)
|
|
||||||
{
|
|
||||||
evt.Skip();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VirtualPad::OnEraseBackground(wxEraseEvent& event)
|
void VirtualPad::OnEraseBackground(wxEraseEvent& event)
|
||||||
{
|
{
|
||||||
// Intentionally Empty
|
// Intentionally Empty
|
||||||
|
@ -150,10 +135,6 @@ void VirtualPad::OnPaint(wxPaintEvent &evt)
|
||||||
|
|
||||||
void VirtualPad::Redraw()
|
void VirtualPad::Redraw()
|
||||||
{
|
{
|
||||||
// This function is called once per frame once we start receiving data from the controller
|
|
||||||
// and there is actually an update that needs to be made.
|
|
||||||
// Once that occurs, we want total control over how often we re-render to minimize flickering
|
|
||||||
// and minimize the performance impact
|
|
||||||
if (!manualRedrawMode) {
|
if (!manualRedrawMode) {
|
||||||
Unbind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
|
Unbind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
|
||||||
manualRedrawMode = true;
|
manualRedrawMode = true;
|
||||||
|
@ -165,26 +146,26 @@ void VirtualPad::Redraw()
|
||||||
void VirtualPad::Render(wxDC &dc)
|
void VirtualPad::Render(wxDC &dc)
|
||||||
{
|
{
|
||||||
// Update GUI Elements and figure out what needs to be rendered
|
// Update GUI Elements and figure out what needs to be rendered
|
||||||
virtualPadData.circle.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.circle.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.cross.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.cross.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.square.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.square.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.triangle.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.triangle.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.down.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.down.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.left.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.left.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.right.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.right.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.up.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.up.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.l1.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.l1.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.l2.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.l2.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.r1.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.r1.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.r2.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.r2.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
|
|
||||||
virtualPadData.select.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.select.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.start.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.start.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.l3.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.l3.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.r3.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.r3.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
|
|
||||||
virtualPadData.leftAnalog.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.leftAnalog.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
virtualPadData.rightAnalog.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
virtualPadData.rightAnalog.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||||
|
|
||||||
// Update Graphic Elements off render stack
|
// Update Graphic Elements off render stack
|
||||||
// Before we start rendering (if we have to) clear and re-draw the background
|
// Before we start rendering (if we have to) clear and re-draw the background
|
||||||
|
@ -215,9 +196,45 @@ void VirtualPad::Render(wxDC &dc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualPad::UpdateControllerData(u16 const bufIndex, PadData *padData, bool readOnly)
|
bool VirtualPad::UpdateControllerData(u16 const bufIndex, PadData *padData)
|
||||||
{
|
{
|
||||||
return virtualPadData.UpdateVirtualPadData(bufIndex, padData, ignoreRealController && !readOnly, readOnly);
|
return virtualPadData.UpdateVirtualPadData(bufIndex, padData, ignoreRealController && !readOnlyMode, readOnlyMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualPad::enablePadElements(bool enable)
|
||||||
|
{
|
||||||
|
virtualPadData.circle.EnableWidgets(enable);
|
||||||
|
virtualPadData.cross.EnableWidgets(enable);
|
||||||
|
virtualPadData.square.EnableWidgets(enable);
|
||||||
|
virtualPadData.triangle.EnableWidgets(enable);
|
||||||
|
virtualPadData.down.EnableWidgets(enable);
|
||||||
|
virtualPadData.left.EnableWidgets(enable);
|
||||||
|
virtualPadData.right.EnableWidgets(enable);
|
||||||
|
virtualPadData.up.EnableWidgets(enable);
|
||||||
|
virtualPadData.l1.EnableWidgets(enable);
|
||||||
|
virtualPadData.l2.EnableWidgets(enable);
|
||||||
|
virtualPadData.r1.EnableWidgets(enable);
|
||||||
|
virtualPadData.r2.EnableWidgets(enable);
|
||||||
|
|
||||||
|
virtualPadData.select.EnableWidgets(enable);
|
||||||
|
virtualPadData.start.EnableWidgets(enable);
|
||||||
|
virtualPadData.l3.EnableWidgets(enable);
|
||||||
|
virtualPadData.r3.EnableWidgets(enable);
|
||||||
|
|
||||||
|
virtualPadData.leftAnalog.EnableWidgets(enable);
|
||||||
|
virtualPadData.rightAnalog.EnableWidgets(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualPad::SetReadOnlyMode()
|
||||||
|
{
|
||||||
|
enablePadElements(true);
|
||||||
|
readOnlyMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualPad::ClearReadOnlyMode()
|
||||||
|
{
|
||||||
|
enablePadElements(false);
|
||||||
|
readOnlyMode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualPad::OnIgnoreRealController(wxCommandEvent const &event)
|
void VirtualPad::OnIgnoreRealController(wxCommandEvent const &event)
|
||||||
|
@ -239,7 +256,6 @@ void VirtualPad::OnNormalButtonPress(wxCommandEvent &event)
|
||||||
eventBtn->pressed = pressedButton->GetValue();
|
eventBtn->pressed = pressedButton->GetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the real controller is being bypassed, we move on, otherwise we begin bypassing the controller
|
|
||||||
if (!eventBtn->isControllerPressBypassed) {
|
if (!eventBtn->isControllerPressBypassed) {
|
||||||
eventBtn->isControllerPressBypassed = true;
|
eventBtn->isControllerPressBypassed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,13 @@
|
||||||
|
|
||||||
#include "Pcsx2Types.h"
|
#include "Pcsx2Types.h"
|
||||||
#include "wx/checkbox.h"
|
#include "wx/checkbox.h"
|
||||||
|
#include "wx/dc.h"
|
||||||
|
#include "wx/event.h"
|
||||||
#include "wx/frame.h"
|
#include "wx/frame.h"
|
||||||
|
#include "wx/gdicmn.h"
|
||||||
|
#include "wx/string.h"
|
||||||
#include "wx/window.h"
|
#include "wx/window.h"
|
||||||
|
#include "wx/windowid.h"
|
||||||
|
|
||||||
#include "Recording/PadData.h"
|
#include "Recording/PadData.h"
|
||||||
#include "Recording/VirtualPad/VirtualPadData.h"
|
#include "Recording/VirtualPad/VirtualPadData.h"
|
||||||
|
@ -29,57 +34,64 @@
|
||||||
class VirtualPad : public wxFrame
|
class VirtualPad : public wxFrame
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VirtualPad(wxWindow *parent, wxWindowID id, const wxString& title, int controllerPort, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE);
|
VirtualPad(wxWindow *parent, wxWindowID id, const wxString& title, int controllerPort,
|
||||||
// Updates the VirtualPad if necessary, as well as updates the PadData fields if the VirtualPad is actively overriding them
|
const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE);
|
||||||
bool UpdateControllerData(u16 const bufIndex, PadData *padData, bool readOnly = false);
|
// 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 ReadOnly mode and disables GUI widgets
|
||||||
|
void SetReadOnlyMode();
|
||||||
|
// Disables ReadOnly mode and re-enables GUI widgets
|
||||||
|
void ClearReadOnlyMode();
|
||||||
|
// To be called at maximum, once per frame to update widget's value and re-render the VirtualPad's graphics
|
||||||
void Redraw();
|
void Redraw();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool manualRedrawMode = false;
|
|
||||||
bool clearScreenRequired = false;
|
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;
|
||||||
|
|
||||||
std::queue<VirtualPadElement*> renderQueue;
|
VirtualPadData virtualPadData;
|
||||||
|
|
||||||
/// GUI Creation Utility Functions
|
std::queue<VirtualPadElement *> renderQueue;
|
||||||
float scalingFactor = 1.0;
|
|
||||||
|
|
||||||
wxSize ScaledSize(int x, int y);
|
void enablePadElements(bool enable);
|
||||||
wxPoint ScaledPoint(wxPoint point, int widgetWidth = 0, bool rightAligned = false);
|
|
||||||
wxPoint ScaledPoint(int x, int y, int widgetWidth = 0, bool rightAligned = false);
|
|
||||||
|
|
||||||
ImageFile NewBitmap(wxImage resource, wxPoint point);
|
|
||||||
ImageFile NewBitmap(float scalingFactor, wxImage resource, wxPoint point);
|
|
||||||
|
|
||||||
void InitPressureButtonGuiElements(ControllerPressureButton &button, ImageFile image, wxWindow *parentWindow, wxPoint point, bool rightAlignedPoint = false);
|
|
||||||
void InitNormalButtonGuiElements(ControllerNormalButton &btn, ImageFile image, wxWindow *parentWindow, wxPoint point);
|
|
||||||
void InitAnalogStickGuiElements(AnalogStick &analog, wxWindow *parentWindow, wxPoint centerPoint, int radius, wxPoint xSliderPoint, wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners = false);
|
|
||||||
|
|
||||||
/// GUI Elements
|
/// GUI Elements
|
||||||
wxCheckBox *ignoreRealControllerBox;
|
wxCheckBox *ignoreRealControllerBox;
|
||||||
|
|
||||||
// Data
|
std::map<wxWindowID, ControllerNormalButton *> buttonElements;
|
||||||
std::map<wxWindowID, ControllerNormalButton*> buttonElements;
|
std::map<wxWindowID, ControllerPressureButton *> pressureElements;
|
||||||
std::map<wxWindowID, ControllerPressureButton*> pressureElements;
|
std::map<wxWindowID, AnalogVector *> analogElements;
|
||||||
std::map<wxWindowID, AnalogVector*> analogElements;
|
|
||||||
|
|
||||||
bool ignoreRealController = false;
|
|
||||||
VirtualPadData virtualPadData;
|
|
||||||
|
|
||||||
bool renderGraphics = false;
|
/// Event Listeners
|
||||||
int imgWrites = 0;
|
|
||||||
int analogWrites = 0;
|
|
||||||
|
|
||||||
// Events
|
|
||||||
void OnEraseBackground(wxEraseEvent& event);
|
void OnEraseBackground(wxEraseEvent& event);
|
||||||
void OnPaint(wxPaintEvent & evt);
|
void OnPaint(wxPaintEvent & evt);
|
||||||
void Render(wxDC& dc);
|
void Render(wxDC& dc);
|
||||||
void OnClose(wxCloseEvent &event);
|
void OnClose(wxCloseEvent &event);
|
||||||
void OnMouseEvent(wxMouseEvent &event);
|
|
||||||
void OnFocusEvent(wxFocusEvent &event);
|
|
||||||
|
|
||||||
void OnNormalButtonPress(wxCommandEvent &event);
|
void OnNormalButtonPress(wxCommandEvent &event);
|
||||||
void OnPressureButtonPressureChange(wxCommandEvent &event);
|
void OnPressureButtonPressureChange(wxCommandEvent &event);
|
||||||
void OnAnalogSliderChange(wxCommandEvent &event);
|
void OnAnalogSliderChange(wxCommandEvent &event);
|
||||||
void OnAnalogSpinnerChange(wxCommandEvent &event);
|
void OnAnalogSpinnerChange(wxCommandEvent &event);
|
||||||
void OnIgnoreRealController(wxCommandEvent const &event);
|
void OnIgnoreRealController(wxCommandEvent const &event);
|
||||||
|
|
||||||
|
/// GUI Creation Utility Functions
|
||||||
|
float scalingFactor = 1.0;
|
||||||
|
|
||||||
|
wxSize ScaledSize(int x, int y);
|
||||||
|
wxPoint ScaledPoint(wxPoint point, int widgetWidth = 0, bool rightAligned = false);
|
||||||
|
wxPoint ScaledPoint(int x, int y, int widgetWidth = 0, bool rightAligned = false);
|
||||||
|
|
||||||
|
ImageFile NewBitmap(wxImage resource, wxPoint point);
|
||||||
|
ImageFile NewBitmap(float scalingFactor, wxImage resource, wxPoint point);
|
||||||
|
|
||||||
|
void InitPressureButtonGuiElements(ControllerPressureButton &button, ImageFile image, wxWindow *parentWindow, wxPoint point, bool rightAlignedPoint = false);
|
||||||
|
void InitNormalButtonGuiElements(ControllerNormalButton &btn, ImageFile image, wxWindow *parentWindow, wxPoint point);
|
||||||
|
void InitAnalogStickGuiElements(AnalogStick &analog, wxWindow *parentWindow, wxPoint centerPoint, int radius, wxPoint xSliderPoint,
|
||||||
|
wxPoint ySliderPoint, bool flipYSlider, wxPoint xSpinnerPoint, wxPoint ySpinnerPoint, bool rightAlignedSpinners = false);
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Pcsx2Types.h"
|
||||||
|
|
||||||
#include "Recording/PadData.h"
|
#include "Recording/PadData.h"
|
||||||
#include "Recording/VirtualPad/VirtualPadResources.h"
|
#include "Recording/VirtualPad/VirtualPadResources.h"
|
||||||
|
|
||||||
|
@ -48,6 +50,10 @@ public:
|
||||||
AnalogStick leftAnalog;
|
AnalogStick leftAnalog;
|
||||||
AnalogStick rightAnalog;
|
AnalogStick rightAnalog;
|
||||||
|
|
||||||
// Given the input buffer and the current index, updates the correct field(s)
|
// 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);
|
bool UpdateVirtualPadData(u16 bufIndex, PadData *padData, bool ignoreRealController = false, bool readOnly = false);
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,18 +20,25 @@
|
||||||
#include "Recording/VirtualPad/VirtualPadResources.h"
|
#include "Recording/VirtualPad/VirtualPadResources.h"
|
||||||
#include "Recording/PadData.h"
|
#include "Recording/PadData.h"
|
||||||
|
|
||||||
void ControllerNormalButton::UpdateGuiElement(std::queue<VirtualPadElement*> *renderQueue, bool &clearScreenRequired)
|
void ControllerNormalButton::UpdateGuiElement(std::queue<VirtualPadElement*> &renderQueue, bool &clearScreenRequired)
|
||||||
{
|
{
|
||||||
ControllerNormalButton &button = *this;
|
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)
|
if (button.widgetUpdateRequired)
|
||||||
{
|
{
|
||||||
button.pressedBox->SetValue(button.pressed);
|
button.pressedBox->SetValue(button.pressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We only render the button if it is pressed
|
||||||
if (button.pressed)
|
if (button.pressed)
|
||||||
{
|
{
|
||||||
renderQueue->push(this);
|
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)
|
else if (button.currentlyRendered)
|
||||||
{
|
{
|
||||||
button.currentlyRendered = false;
|
button.currentlyRendered = false;
|
||||||
|
@ -39,18 +46,17 @@ void ControllerNormalButton::UpdateGuiElement(std::queue<VirtualPadElement*> *re
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControllerPressureButton::UpdateGuiElement(std::queue<VirtualPadElement *> *renderQueue, bool &clearScreenRequired)
|
void ControllerPressureButton::UpdateGuiElement(std::queue<VirtualPadElement *> &renderQueue, bool &clearScreenRequired)
|
||||||
{
|
{
|
||||||
ControllerPressureButton &button = *this;
|
ControllerPressureButton &button = *this;
|
||||||
if (button.widgetUpdateRequired)
|
if (button.widgetUpdateRequired)
|
||||||
{
|
{
|
||||||
button.pressureSpinner->SetValue(button.pressure);
|
button.pressureSpinner->SetValue(button.pressure);
|
||||||
clearScreenRequired = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (button.pressed)
|
if (button.pressed)
|
||||||
{
|
{
|
||||||
renderQueue->push(this);
|
renderQueue.push(this);
|
||||||
}
|
}
|
||||||
else if (button.currentlyRendered)
|
else if (button.currentlyRendered)
|
||||||
{
|
{
|
||||||
|
@ -59,11 +65,9 @@ void ControllerPressureButton::UpdateGuiElement(std::queue<VirtualPadElement *>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalogStick::UpdateGuiElement(std::queue<VirtualPadElement *> *renderQueue, bool &clearScreenRequired)
|
void AnalogStick::UpdateGuiElement(std::queue<VirtualPadElement *> &renderQueue, bool &clearScreenRequired)
|
||||||
{
|
{
|
||||||
AnalogStick &analogStick = *this;
|
AnalogStick &analogStick = *this;
|
||||||
// Update the GUI elements that need updating
|
|
||||||
// If either vector has changed, we need to redraw the graphics
|
|
||||||
if (analogStick.xVector.widgetUpdateRequired)
|
if (analogStick.xVector.widgetUpdateRequired)
|
||||||
{
|
{
|
||||||
analogStick.xVector.slider->SetValue(analogStick.xVector.val);
|
analogStick.xVector.slider->SetValue(analogStick.xVector.val);
|
||||||
|
@ -74,9 +78,11 @@ void AnalogStick::UpdateGuiElement(std::queue<VirtualPadElement *> *renderQueue,
|
||||||
analogStick.yVector.slider->SetValue(analogStick.yVector.val);
|
analogStick.yVector.slider->SetValue(analogStick.yVector.val);
|
||||||
analogStick.yVector.spinner->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))
|
if (!(analogStick.xVector.val == PadData::ANALOG_VECTOR_NEUTRAL && analogStick.yVector.val == PadData::ANALOG_VECTOR_NEUTRAL))
|
||||||
{
|
{
|
||||||
renderQueue->push(this);
|
renderQueue.push(this);
|
||||||
}
|
}
|
||||||
else if (analogStick.currentlyRendered) {
|
else if (analogStick.currentlyRendered) {
|
||||||
analogStick.currentlyRendered = false;
|
analogStick.currentlyRendered = false;
|
||||||
|
@ -84,6 +90,45 @@ void AnalogStick::UpdateGuiElement(std::queue<VirtualPadElement *> *renderQueue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ControllerNormalButton::EnableWidgets(bool enable)
|
||||||
|
{
|
||||||
|
ControllerNormalButton &button = *this;
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
button.pressedBox->Enable();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
button.pressedBox->Disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerPressureButton::EnableWidgets(bool enable)
|
||||||
|
{
|
||||||
|
ControllerPressureButton &button = *this;
|
||||||
|
if (enable) {
|
||||||
|
button.pressureSpinner->Enable();
|
||||||
|
} else {
|
||||||
|
button.pressureSpinner->Disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogStick::EnableWidgets(bool enable)
|
||||||
|
{
|
||||||
|
AnalogStick &analog = *this;
|
||||||
|
if (enable) {
|
||||||
|
analog.xVector.slider->Enable();
|
||||||
|
analog.yVector.slider->Enable();
|
||||||
|
analog.xVector.spinner->Enable();
|
||||||
|
analog.yVector.spinner->Enable();
|
||||||
|
} else {
|
||||||
|
analog.xVector.slider->Disable();
|
||||||
|
analog.yVector.slider->Disable();
|
||||||
|
analog.xVector.spinner->Disable();
|
||||||
|
analog.yVector.spinner->Disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ControllerNormalButton::Render(wxDC &dc)
|
void ControllerNormalButton::Render(wxDC &dc)
|
||||||
{
|
{
|
||||||
ControllerNormalButton &button = *this;
|
ControllerNormalButton &button = *this;
|
||||||
|
@ -109,7 +154,9 @@ void AnalogStick::Render(wxDC &dc)
|
||||||
int newXCoord = analogPos.centerCoords.x + ((analogStick.xVector.val - 127) / 127.0) * analogPos.radius;
|
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;
|
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
|
// We want to ensure the line segment length is capped at the defined radius
|
||||||
float lengthOfLine = sqrt(pow(newXCoord - analogPos.centerCoords.x, 2) + pow(newYCoord - analogPos.centerCoords.y, 2));
|
// NOTE - The conventional way to do this is using arctan2, but the analog values that come out
|
||||||
|
// of the Pad plugins 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) {
|
if (lengthOfLine > analogPos.radius) {
|
||||||
newXCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.x) + analogPos.radius / lengthOfLine * newXCoord;
|
newXCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.x) + analogPos.radius / lengthOfLine * newXCoord;
|
||||||
newYCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.y) + analogPos.radius / lengthOfLine * newYCoord;
|
newYCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.y) + analogPos.radius / lengthOfLine * newYCoord;
|
||||||
|
@ -124,28 +171,6 @@ void AnalogStick::Render(wxDC &dc)
|
||||||
analogStick.currentlyRendered = true;
|
analogStick.currentlyRendered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ControllerButton::UpdateButtonData(bool &padDataVal, bool ignoreRealController, bool readOnly)
|
|
||||||
{
|
|
||||||
ControllerButton &button = *this;
|
|
||||||
if (!ignoreRealController) {
|
|
||||||
// If controller is being bypassed and controller's state has changed
|
|
||||||
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) {
|
|
||||||
button.widgetUpdateRequired = button.pressed != padDataVal;
|
|
||||||
button.pressed = padDataVal;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
button.prevPressedVal = padDataVal;
|
|
||||||
padDataVal = button.pressed;
|
|
||||||
return button.prevPressedVal != button.pressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ControllerNormalButton::UpdateData(bool &padDataVal, bool ignoreRealController, bool readOnly)
|
bool ControllerNormalButton::UpdateData(bool &padDataVal, bool ignoreRealController, bool readOnly)
|
||||||
{
|
{
|
||||||
return this->UpdateButtonData(padDataVal, ignoreRealController, readOnly);
|
return this->UpdateButtonData(padDataVal, ignoreRealController, readOnly);
|
||||||
|
@ -156,16 +181,39 @@ bool ControllerPressureButton::UpdateData(bool &padDataVal, bool ignoreRealContr
|
||||||
return this->UpdateButtonData(padDataVal, ignoreRealController, 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)
|
bool ControllerPressureButton::UpdateData(u8 &padDataVal, bool ignoreRealController, bool readOnly)
|
||||||
{
|
{
|
||||||
ControllerPressureButton &button = *this;
|
ControllerPressureButton &button = *this;
|
||||||
if (!ignoreRealController) {
|
if (!ignoreRealController || readOnly) {
|
||||||
bool bypassedWithChangedState = button.isControllerPressureBypassed && padDataVal != button.prevPressureVal;
|
const bool bypassedWithChangedState = button.isControllerPressureBypassed && padDataVal != button.prevPressureVal;
|
||||||
if (bypassedWithChangedState) {
|
if (bypassedWithChangedState) {
|
||||||
button.prevPressureVal = padDataVal;
|
button.prevPressureVal = padDataVal;
|
||||||
button.isControllerPressureBypassed = false;
|
button.isControllerPressureBypassed = false;
|
||||||
}
|
}
|
||||||
if (bypassedWithChangedState || !button.isControllerPressureBypassed) {
|
if (bypassedWithChangedState || !button.isControllerPressureBypassed || readOnly) {
|
||||||
button.widgetUpdateRequired = button.pressure != padDataVal;
|
button.widgetUpdateRequired = button.pressure != padDataVal;
|
||||||
button.pressure = padDataVal;
|
button.pressure = padDataVal;
|
||||||
return false;
|
return false;
|
||||||
|
@ -179,13 +227,13 @@ bool ControllerPressureButton::UpdateData(u8 &padDataVal, bool ignoreRealControl
|
||||||
bool AnalogVector::UpdateData(u8 &padDataVal, bool ignoreRealController, bool readOnly)
|
bool AnalogVector::UpdateData(u8 &padDataVal, bool ignoreRealController, bool readOnly)
|
||||||
{
|
{
|
||||||
AnalogVector &vector = *this;
|
AnalogVector &vector = *this;
|
||||||
if (!ignoreRealController) {
|
if (!ignoreRealController || readOnly) {
|
||||||
bool bypassedWithChangedState = vector.isControllerBypassed && padDataVal != vector.prevVal;
|
const bool bypassedWithChangedState = vector.isControllerBypassed && padDataVal != vector.prevVal;
|
||||||
if (bypassedWithChangedState) {
|
if (bypassedWithChangedState) {
|
||||||
vector.prevVal = padDataVal;
|
vector.prevVal = padDataVal;
|
||||||
vector.isControllerBypassed = false;
|
vector.isControllerBypassed = false;
|
||||||
}
|
}
|
||||||
if (bypassedWithChangedState || !vector.isControllerBypassed) {
|
if (bypassedWithChangedState || !vector.isControllerBypassed || readOnly) {
|
||||||
vector.widgetUpdateRequired = vector.val != padDataVal;
|
vector.widgetUpdateRequired = vector.val != padDataVal;
|
||||||
vector.val = padDataVal;
|
vector.val = padDataVal;
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -17,6 +17,13 @@
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
#include "Pcsx2Types.h"
|
||||||
|
#include "wx/bitmap.h"
|
||||||
|
#include "wx/checkbox.h"
|
||||||
|
#include "wx/gdicmn.h"
|
||||||
|
#include "wx/slider.h"
|
||||||
|
#include "wx/spinctrl.h"
|
||||||
|
|
||||||
struct ImageFile
|
struct ImageFile
|
||||||
{
|
{
|
||||||
wxBitmap image;
|
wxBitmap image;
|
||||||
|
@ -27,14 +34,13 @@ struct ImageFile
|
||||||
|
|
||||||
struct AnalogVector
|
struct AnalogVector
|
||||||
{
|
{
|
||||||
// GUI
|
|
||||||
wxSlider *slider = 0;
|
wxSlider *slider = 0;
|
||||||
wxSpinCtrl *spinner = 0;
|
wxSpinCtrl *spinner = 0;
|
||||||
|
|
||||||
u8 val = 127;
|
u8 val = 127;
|
||||||
|
|
||||||
bool widgetUpdateRequired = false;
|
|
||||||
bool isControllerBypassed = false;
|
bool isControllerBypassed = false;
|
||||||
|
bool widgetUpdateRequired = false;
|
||||||
u8 prevVal = 127;
|
u8 prevVal = 127;
|
||||||
|
|
||||||
bool UpdateData(u8 &padDataVal, bool ignoreRealController, bool readOnly);
|
bool UpdateData(u8 &padDataVal, bool ignoreRealController, bool readOnly);
|
||||||
|
@ -55,55 +61,53 @@ class VirtualPadElement
|
||||||
public:
|
public:
|
||||||
bool currentlyRendered = false;
|
bool currentlyRendered = false;
|
||||||
|
|
||||||
virtual void UpdateGuiElement(std::queue<VirtualPadElement *> *renderQueue, bool &clearScreenRequired) = 0;
|
virtual void EnableWidgets(bool enable) = 0;
|
||||||
virtual void Render(wxDC &dc) = 0;
|
virtual void Render(wxDC &dc) = 0;
|
||||||
|
virtual void UpdateGuiElement(std::queue<VirtualPadElement *> &renderQueue, bool &clearScreenRequired) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ControllerButton
|
class ControllerButton
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool pressed = false;
|
|
||||||
bool widgetUpdateRequired = false;
|
|
||||||
bool isControllerPressBypassed = false;
|
bool isControllerPressBypassed = false;
|
||||||
|
bool pressed = false;
|
||||||
bool prevPressedVal = false;
|
bool prevPressedVal = false;
|
||||||
|
bool widgetUpdateRequired = false;
|
||||||
|
|
||||||
bool UpdateButtonData(bool &padDataVal, bool ignoreRealController, bool readOnly);
|
bool UpdateButtonData(bool &padDataVal, bool ignoreRealController, bool readOnly);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ControllerNormalButton : public ControllerButton, VirtualPadElement
|
class ControllerNormalButton : public ControllerButton, public VirtualPadElement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// GUI
|
|
||||||
ImageFile icon;
|
ImageFile icon;
|
||||||
wxCheckBox *pressedBox = 0;
|
wxCheckBox *pressedBox = 0;
|
||||||
|
|
||||||
/// State
|
|
||||||
|
|
||||||
void UpdateGuiElement(std::queue<VirtualPadElement *> *renderQueue, bool &clearScreenRequired) override;
|
|
||||||
void Render(wxDC &dc) override;
|
|
||||||
bool UpdateData(bool &padDataVal, bool ignoreRealController, bool readOnly);
|
bool UpdateData(bool &padDataVal, bool ignoreRealController, bool readOnly);
|
||||||
|
void EnableWidgets(bool enable) override;
|
||||||
|
void Render(wxDC &dc) override;
|
||||||
|
void UpdateGuiElement(std::queue<VirtualPadElement *> &renderQueue, bool &clearScreenRequired) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ControllerPressureButton : public ControllerButton, VirtualPadElement
|
class ControllerPressureButton : public ControllerButton, public VirtualPadElement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// GUI
|
|
||||||
ImageFile icon;
|
ImageFile icon;
|
||||||
wxSpinCtrl *pressureSpinner = 0;
|
wxSpinCtrl *pressureSpinner = 0;
|
||||||
|
|
||||||
u8 pressure = 0;
|
u8 pressure = 0;
|
||||||
|
|
||||||
/// State Management
|
|
||||||
bool isControllerPressureBypassed = false;
|
bool isControllerPressureBypassed = false;
|
||||||
u8 prevPressureVal = 0;
|
u8 prevPressureVal = 0;
|
||||||
|
|
||||||
void UpdateGuiElement(std::queue<VirtualPadElement *> *renderQueue, bool &clearScreenRequired) override;
|
|
||||||
void Render(wxDC &dc) override;
|
|
||||||
bool UpdateData(bool &padDataVal, bool ignoreRealController, bool readOnly);
|
bool UpdateData(bool &padDataVal, bool ignoreRealController, bool readOnly);
|
||||||
bool UpdateData(u8 &padDataVal, bool ignoreRealController, bool readOnly);
|
bool UpdateData(u8 &padDataVal, bool ignoreRealController, bool readOnly);
|
||||||
|
void EnableWidgets(bool enable) override;
|
||||||
|
void Render(wxDC &dc) override;
|
||||||
|
void UpdateGuiElement(std::queue<VirtualPadElement *> &renderQueue, bool &clearScreenRequired) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AnalogStick : VirtualPadElement
|
class AnalogStick : public VirtualPadElement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AnalogVector xVector;
|
AnalogVector xVector;
|
||||||
|
@ -111,6 +115,7 @@ public:
|
||||||
|
|
||||||
AnalogPosition positionGraphic;
|
AnalogPosition positionGraphic;
|
||||||
|
|
||||||
void UpdateGuiElement(std::queue<VirtualPadElement *> *renderQueue, bool &clearScreenRequired) override;
|
void EnableWidgets(bool enable) override;
|
||||||
void Render(wxDC &dc) override;
|
void Render(wxDC &dc) override;
|
||||||
|
void UpdateGuiElement(std::queue<VirtualPadElement *> &renderQueue, bool &clearScreenRequired) override;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue