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()
|
||||
{
|
||||
// NOTE - No multi-tap support, only two controllers
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
padData[i] = new PadData();
|
||||
}
|
||||
padData[CONTROLLER_PORT_ONE] = new PadData();
|
||||
padData[CONTROLLER_PORT_TWO] = new PadData();
|
||||
}
|
||||
|
||||
void InputRecording::setVirtualPadPtr(VirtualPad *ptr, int port)
|
||||
void InputRecording::SetVirtualPadPtr(VirtualPad *ptr, int const port)
|
||||
{
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
|
@ -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 (bufIndex == PadData::END_INDEX_CONTROLLER_BUFFER) {
|
||||
padData[port]->LogPadData(port);
|
||||
// As well as re-render the virtual pad UI, if applicable
|
||||
if (virtualPads[port] && virtualPads[port]->IsShown())
|
||||
{
|
||||
virtualPads[port]->Redraw();
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
// Stop the active input recording
|
||||
void Stop();
|
||||
|
||||
void setVirtualPadPtr(VirtualPad *ptr, int port);
|
||||
void SetVirtualPadPtr(VirtualPad *ptr, int const port);
|
||||
|
||||
private:
|
||||
enum class InputRecordingMode
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
void PadData::UpdateControllerData(u16 bufIndex, u8 const &bufVal)
|
||||
{
|
||||
BufferIndex index = static_cast<BufferIndex>(bufIndex);
|
||||
const BufferIndex index = static_cast<BufferIndex>(bufIndex);
|
||||
switch (index)
|
||||
{
|
||||
case BufferIndex::PressedFlagsGroupOne:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
* 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(wxEVT_ERASE_BACKGROUND, &VirtualPad::OnEraseBackground, this);
|
||||
Bind(wxEVT_MOTION, &VirtualPad::OnMouseEvent, 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.
|
||||
// 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);
|
||||
|
||||
// Finalize layout
|
||||
|
@ -124,18 +121,6 @@ void VirtualPad::OnClose(wxCloseEvent & event)
|
|||
Hide();
|
||||
}
|
||||
|
||||
void VirtualPad::OnMouseEvent(wxMouseEvent &evt)
|
||||
{
|
||||
evt.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
void VirtualPad::OnFocusEvent(wxFocusEvent &evt)
|
||||
{
|
||||
evt.Skip();
|
||||
return;
|
||||
}
|
||||
|
||||
void VirtualPad::OnEraseBackground(wxEraseEvent& event)
|
||||
{
|
||||
// Intentionally Empty
|
||||
|
@ -150,10 +135,6 @@ void VirtualPad::OnPaint(wxPaintEvent &evt)
|
|||
|
||||
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) {
|
||||
Unbind(wxEVT_PAINT, &VirtualPad::OnPaint, this);
|
||||
manualRedrawMode = true;
|
||||
|
@ -165,26 +146,26 @@ void VirtualPad::Redraw()
|
|||
void VirtualPad::Render(wxDC &dc)
|
||||
{
|
||||
// Update GUI Elements and figure out what needs to be rendered
|
||||
virtualPadData.circle.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.cross.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.square.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.triangle.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.down.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.left.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.right.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.up.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.l1.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.l2.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.r1.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.r2.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.circle.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.cross.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.square.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.triangle.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.down.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.left.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.right.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.up.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.l1.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.l2.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.r1.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.r2.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
|
||||
virtualPadData.select.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.start.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.l3.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.r3.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.select.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.start.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.l3.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.r3.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
|
||||
virtualPadData.leftAnalog.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.rightAnalog.UpdateGuiElement(&renderQueue, clearScreenRequired);
|
||||
virtualPadData.leftAnalog.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
virtualPadData.rightAnalog.UpdateGuiElement(renderQueue, clearScreenRequired);
|
||||
|
||||
// Update Graphic Elements off render stack
|
||||
// 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)
|
||||
|
@ -239,7 +256,6 @@ void VirtualPad::OnNormalButtonPress(wxCommandEvent &event)
|
|||
eventBtn->pressed = pressedButton->GetValue();
|
||||
}
|
||||
|
||||
// If the real controller is being bypassed, we move on, otherwise we begin bypassing the controller
|
||||
if (!eventBtn->isControllerPressBypassed) {
|
||||
eventBtn->isControllerPressBypassed = true;
|
||||
}
|
||||
|
|
|
@ -20,8 +20,13 @@
|
|||
|
||||
#include "Pcsx2Types.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"
|
||||
|
@ -29,16 +34,51 @@
|
|||
class VirtualPad : public wxFrame
|
||||
{
|
||||
public:
|
||||
VirtualPad(wxWindow *parent, wxWindowID id, const wxString& title, int controllerPort, const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE);
|
||||
// Updates the VirtualPad if necessary, as well as updates the PadData fields if the VirtualPad is actively overriding them
|
||||
bool UpdateControllerData(u16 const bufIndex, PadData *padData, bool readOnly = false);
|
||||
VirtualPad(wxWindow *parent, wxWindowID id, const wxString& title, int controllerPort,
|
||||
const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE);
|
||||
// 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();
|
||||
|
||||
private:
|
||||
bool manualRedrawMode = 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;
|
||||
|
||||
std::queue<VirtualPadElement *> renderQueue;
|
||||
|
||||
void enablePadElements(bool enable);
|
||||
|
||||
/// GUI Elements
|
||||
wxCheckBox *ignoreRealControllerBox;
|
||||
|
||||
std::map<wxWindowID, ControllerNormalButton *> buttonElements;
|
||||
std::map<wxWindowID, ControllerPressureButton *> pressureElements;
|
||||
std::map<wxWindowID, AnalogVector *> analogElements;
|
||||
|
||||
/// Event Listeners
|
||||
void OnEraseBackground(wxEraseEvent& event);
|
||||
void OnPaint(wxPaintEvent & evt);
|
||||
void Render(wxDC& dc);
|
||||
void OnClose(wxCloseEvent &event);
|
||||
|
||||
void OnNormalButtonPress(wxCommandEvent &event);
|
||||
void OnPressureButtonPressureChange(wxCommandEvent &event);
|
||||
void OnAnalogSliderChange(wxCommandEvent &event);
|
||||
void OnAnalogSpinnerChange(wxCommandEvent &event);
|
||||
void OnIgnoreRealController(wxCommandEvent const &event);
|
||||
|
||||
/// GUI Creation Utility Functions
|
||||
float scalingFactor = 1.0;
|
||||
|
@ -52,34 +92,6 @@ private:
|
|||
|
||||
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
|
||||
wxCheckBox *ignoreRealControllerBox;
|
||||
|
||||
// Data
|
||||
std::map<wxWindowID, ControllerNormalButton*> buttonElements;
|
||||
std::map<wxWindowID, ControllerPressureButton*> pressureElements;
|
||||
std::map<wxWindowID, AnalogVector*> analogElements;
|
||||
|
||||
bool ignoreRealController = false;
|
||||
VirtualPadData virtualPadData;
|
||||
|
||||
bool renderGraphics = false;
|
||||
int imgWrites = 0;
|
||||
int analogWrites = 0;
|
||||
|
||||
// Events
|
||||
void OnEraseBackground(wxEraseEvent& event);
|
||||
void OnPaint(wxPaintEvent & evt);
|
||||
void Render(wxDC& dc);
|
||||
void OnClose(wxCloseEvent &event);
|
||||
void OnMouseEvent(wxMouseEvent &event);
|
||||
void OnFocusEvent(wxFocusEvent &event);
|
||||
|
||||
void OnNormalButtonPress(wxCommandEvent &event);
|
||||
void OnPressureButtonPressureChange(wxCommandEvent &event);
|
||||
void OnAnalogSliderChange(wxCommandEvent &event);
|
||||
void OnAnalogSpinnerChange(wxCommandEvent &event);
|
||||
void OnIgnoreRealController(wxCommandEvent const &event);
|
||||
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
|
||||
|
||||
#include "Pcsx2Types.h"
|
||||
|
||||
#include "Recording/PadData.h"
|
||||
#include "Recording/VirtualPad/VirtualPadResources.h"
|
||||
|
||||
|
@ -48,6 +50,10 @@ public:
|
|||
AnalogStick leftAnalog;
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -20,18 +20,25 @@
|
|||
#include "Recording/VirtualPad/VirtualPadResources.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;
|
||||
// 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);
|
||||
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;
|
||||
|
@ -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;
|
||||
if (button.widgetUpdateRequired)
|
||||
{
|
||||
button.pressureSpinner->SetValue(button.pressure);
|
||||
clearScreenRequired = true;
|
||||
}
|
||||
|
||||
if (button.pressed)
|
||||
{
|
||||
renderQueue->push(this);
|
||||
renderQueue.push(this);
|
||||
}
|
||||
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;
|
||||
// Update the GUI elements that need updating
|
||||
// If either vector has changed, we need to redraw the graphics
|
||||
if (analogStick.xVector.widgetUpdateRequired)
|
||||
{
|
||||
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.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);
|
||||
renderQueue.push(this);
|
||||
}
|
||||
else if (analogStick.currentlyRendered) {
|
||||
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)
|
||||
{
|
||||
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 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
|
||||
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) {
|
||||
newXCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.x) + analogPos.radius / lengthOfLine * newXCoord;
|
||||
newYCoord = ((1 - analogPos.radius / lengthOfLine) * analogPos.centerCoords.y) + analogPos.radius / lengthOfLine * newYCoord;
|
||||
|
@ -124,28 +171,6 @@ void AnalogStick::Render(wxDC &dc)
|
|||
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)
|
||||
{
|
||||
return this->UpdateButtonData(padDataVal, ignoreRealController, readOnly);
|
||||
|
@ -156,16 +181,39 @@ bool ControllerPressureButton::UpdateData(bool &padDataVal, bool ignoreRealContr
|
|||
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) {
|
||||
bool bypassedWithChangedState = button.isControllerPressureBypassed && padDataVal != button.prevPressureVal;
|
||||
if (!ignoreRealController || readOnly) {
|
||||
const bool bypassedWithChangedState = button.isControllerPressureBypassed && padDataVal != button.prevPressureVal;
|
||||
if (bypassedWithChangedState) {
|
||||
button.prevPressureVal = padDataVal;
|
||||
button.isControllerPressureBypassed = false;
|
||||
}
|
||||
if (bypassedWithChangedState || !button.isControllerPressureBypassed) {
|
||||
if (bypassedWithChangedState || !button.isControllerPressureBypassed || readOnly) {
|
||||
button.widgetUpdateRequired = button.pressure != padDataVal;
|
||||
button.pressure = padDataVal;
|
||||
return false;
|
||||
|
@ -179,13 +227,13 @@ bool ControllerPressureButton::UpdateData(u8 &padDataVal, bool ignoreRealControl
|
|||
bool AnalogVector::UpdateData(u8 &padDataVal, bool ignoreRealController, bool readOnly)
|
||||
{
|
||||
AnalogVector &vector = *this;
|
||||
if (!ignoreRealController) {
|
||||
bool bypassedWithChangedState = vector.isControllerBypassed && padDataVal != vector.prevVal;
|
||||
if (!ignoreRealController || readOnly) {
|
||||
const bool bypassedWithChangedState = vector.isControllerBypassed && padDataVal != vector.prevVal;
|
||||
if (bypassedWithChangedState) {
|
||||
vector.prevVal = padDataVal;
|
||||
vector.isControllerBypassed = false;
|
||||
}
|
||||
if (bypassedWithChangedState || !vector.isControllerBypassed) {
|
||||
if (bypassedWithChangedState || !vector.isControllerBypassed || readOnly) {
|
||||
vector.widgetUpdateRequired = vector.val != padDataVal;
|
||||
vector.val = padDataVal;
|
||||
return false;
|
||||
|
|
|
@ -17,6 +17,13 @@
|
|||
|
||||
#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
|
||||
{
|
||||
wxBitmap image;
|
||||
|
@ -27,14 +34,13 @@ struct ImageFile
|
|||
|
||||
struct AnalogVector
|
||||
{
|
||||
// GUI
|
||||
wxSlider *slider = 0;
|
||||
wxSpinCtrl *spinner = 0;
|
||||
|
||||
u8 val = 127;
|
||||
|
||||
bool widgetUpdateRequired = false;
|
||||
bool isControllerBypassed = false;
|
||||
bool widgetUpdateRequired = false;
|
||||
u8 prevVal = 127;
|
||||
|
||||
bool UpdateData(u8 &padDataVal, bool ignoreRealController, bool readOnly);
|
||||
|
@ -55,55 +61,53 @@ class VirtualPadElement
|
|||
public:
|
||||
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 UpdateGuiElement(std::queue<VirtualPadElement *> &renderQueue, bool &clearScreenRequired) = 0;
|
||||
};
|
||||
|
||||
class ControllerButton
|
||||
{
|
||||
public:
|
||||
bool pressed = false;
|
||||
bool widgetUpdateRequired = false;
|
||||
bool isControllerPressBypassed = false;
|
||||
bool pressed = false;
|
||||
bool prevPressedVal = false;
|
||||
bool widgetUpdateRequired = false;
|
||||
|
||||
bool UpdateButtonData(bool &padDataVal, bool ignoreRealController, bool readOnly);
|
||||
};
|
||||
|
||||
class ControllerNormalButton : public ControllerButton, VirtualPadElement
|
||||
class ControllerNormalButton : public ControllerButton, public VirtualPadElement
|
||||
{
|
||||
public:
|
||||
/// GUI
|
||||
ImageFile icon;
|
||||
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);
|
||||
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:
|
||||
/// GUI
|
||||
ImageFile icon;
|
||||
wxSpinCtrl *pressureSpinner = 0;
|
||||
|
||||
u8 pressure = 0;
|
||||
|
||||
/// State Management
|
||||
bool isControllerPressureBypassed = false;
|
||||
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(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:
|
||||
AnalogVector xVector;
|
||||
|
@ -111,6 +115,7 @@ public:
|
|||
|
||||
AnalogPosition positionGraphic;
|
||||
|
||||
void UpdateGuiElement(std::queue<VirtualPadElement *> *renderQueue, bool &clearScreenRequired) override;
|
||||
void EnableWidgets(bool enable) override;
|
||||
void Render(wxDC &dc) override;
|
||||
void UpdateGuiElement(std::queue<VirtualPadElement *> &renderQueue, bool &clearScreenRequired) override;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue