early-access version 3573
This commit is contained in:
parent
17b9efbffd
commit
8b74a66045
11 changed files with 92 additions and 25 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3571.
|
This is the source code for early-access 3573.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -688,6 +688,12 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage
|
||||||
ReloadInput();
|
ReloadInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmulatedController::StartMotionCalibration() {
|
||||||
|
for (ControllerMotionInfo& motion : controller.motion_values) {
|
||||||
|
motion.emulated.Calibrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index,
|
||||||
Common::UUID uuid) {
|
Common::UUID uuid) {
|
||||||
if (index >= controller.button_values.size()) {
|
if (index >= controller.button_values.size()) {
|
||||||
|
|
|
@ -290,6 +290,9 @@ public:
|
||||||
*/
|
*/
|
||||||
void SetMotionParam(std::size_t index, Common::ParamPackage param);
|
void SetMotionParam(std::size_t index, Common::ParamPackage param);
|
||||||
|
|
||||||
|
/// Auto calibrates the current motion devices
|
||||||
|
void StartMotionCalibration();
|
||||||
|
|
||||||
/// Returns the latest button status from the controller with parameters
|
/// Returns the latest button status from the controller with parameters
|
||||||
ButtonValues GetButtonsValues() const;
|
ButtonValues GetButtonsValues() const;
|
||||||
|
|
||||||
|
|
|
@ -37,11 +37,17 @@ void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) {
|
||||||
gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue);
|
gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue);
|
||||||
gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue);
|
gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue);
|
||||||
|
|
||||||
// Auto adjust drift to minimize drift
|
// Auto adjust gyro_bias to minimize drift
|
||||||
if (!IsMoving(IsAtRestRelaxed)) {
|
if (!IsMoving(IsAtRestRelaxed)) {
|
||||||
gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
|
gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust drift when calibration mode is enabled
|
||||||
|
if (calibration_mode) {
|
||||||
|
gyro_bias = (gyro_bias * 0.99f) + (gyroscope * 0.01f);
|
||||||
|
StopCalibration();
|
||||||
|
}
|
||||||
|
|
||||||
if (gyro.Length() < gyro_threshold * user_gyro_threshold) {
|
if (gyro.Length() < gyro_threshold * user_gyro_threshold) {
|
||||||
gyro = {};
|
gyro = {};
|
||||||
} else {
|
} else {
|
||||||
|
@ -107,6 +113,19 @@ void MotionInput::UpdateRotation(u64 elapsed_time) {
|
||||||
rotations += gyro * sample_period;
|
rotations += gyro * sample_period;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MotionInput::Calibrate() {
|
||||||
|
calibration_mode = true;
|
||||||
|
calibration_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MotionInput::StopCalibration() {
|
||||||
|
if (calibration_counter++ > CalibrationSamples) {
|
||||||
|
calibration_mode = false;
|
||||||
|
ResetQuaternion();
|
||||||
|
ResetRotations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Based on Madgwick's implementation of Mayhony's AHRS algorithm.
|
// Based on Madgwick's implementation of Mayhony's AHRS algorithm.
|
||||||
// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
|
// https://github.com/xioTechnologies/Open-Source-AHRS-With-x-IMU/blob/master/x-IMU%20IMU%20and%20AHRS%20Algorithms/x-IMU%20IMU%20and%20AHRS%20Algorithms/AHRS/MahonyAHRS.cs
|
||||||
void MotionInput::UpdateOrientation(u64 elapsed_time) {
|
void MotionInput::UpdateOrientation(u64 elapsed_time) {
|
||||||
|
|
|
@ -23,6 +23,8 @@ public:
|
||||||
static constexpr float GyroMaxValue = 5.0f;
|
static constexpr float GyroMaxValue = 5.0f;
|
||||||
static constexpr float AccelMaxValue = 7.0f;
|
static constexpr float AccelMaxValue = 7.0f;
|
||||||
|
|
||||||
|
static constexpr std::size_t CalibrationSamples = 300;
|
||||||
|
|
||||||
explicit MotionInput();
|
explicit MotionInput();
|
||||||
|
|
||||||
MotionInput(const MotionInput&) = default;
|
MotionInput(const MotionInput&) = default;
|
||||||
|
@ -49,6 +51,8 @@ public:
|
||||||
void UpdateRotation(u64 elapsed_time);
|
void UpdateRotation(u64 elapsed_time);
|
||||||
void UpdateOrientation(u64 elapsed_time);
|
void UpdateOrientation(u64 elapsed_time);
|
||||||
|
|
||||||
|
void Calibrate();
|
||||||
|
|
||||||
[[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const;
|
[[nodiscard]] std::array<Common::Vec3f, 3> GetOrientation() const;
|
||||||
[[nodiscard]] Common::Vec3f GetAcceleration() const;
|
[[nodiscard]] Common::Vec3f GetAcceleration() const;
|
||||||
[[nodiscard]] Common::Vec3f GetGyroscope() const;
|
[[nodiscard]] Common::Vec3f GetGyroscope() const;
|
||||||
|
@ -61,6 +65,7 @@ public:
|
||||||
[[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
|
[[nodiscard]] bool IsCalibrated(f32 sensitivity) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void StopCalibration();
|
||||||
void ResetOrientation();
|
void ResetOrientation();
|
||||||
void SetOrientationFromAccelerometer();
|
void SetOrientationFromAccelerometer();
|
||||||
|
|
||||||
|
@ -103,6 +108,12 @@ private:
|
||||||
|
|
||||||
// Use accelerometer values to calculate position
|
// Use accelerometer values to calculate position
|
||||||
bool only_accelerometer = true;
|
bool only_accelerometer = true;
|
||||||
|
|
||||||
|
// When enabled it will aggressively adjust for gyro drift
|
||||||
|
bool calibration_mode = false;
|
||||||
|
|
||||||
|
// Used to auto disable calibration mode
|
||||||
|
std::size_t calibration_counter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core::HID
|
} // namespace Core::HID
|
||||||
|
|
|
@ -109,14 +109,37 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RumblePlay(const Common::Input::VibrationStatus vibration) {
|
bool RumblePlay(const Common::Input::VibrationStatus vibration) {
|
||||||
constexpr u32 rumble_max_duration_ms = 1000;
|
constexpr u32 rumble_max_duration_ms = 2000;
|
||||||
|
constexpr f32 low_start_sensitivity_limit = 140.0;
|
||||||
|
constexpr f32 low_width_sensitivity_limit = 400.0;
|
||||||
|
constexpr f32 high_start_sensitivity_limit = 200.0;
|
||||||
|
constexpr f32 high_width_sensitivity_limit = 700.0;
|
||||||
|
// Try to provide some feeling of the frequency by reducing the amplitude depending on it.
|
||||||
|
f32 low_frequency_scale = 1.0;
|
||||||
|
if (vibration.low_frequency > low_start_sensitivity_limit) {
|
||||||
|
low_frequency_scale =
|
||||||
|
std::max(1.0f - (vibration.low_frequency - low_start_sensitivity_limit) /
|
||||||
|
low_width_sensitivity_limit,
|
||||||
|
0.3f);
|
||||||
|
}
|
||||||
|
f32 low_amplitude = vibration.low_amplitude * low_frequency_scale;
|
||||||
|
|
||||||
|
f32 high_frequency_scale = 1.0;
|
||||||
|
if (vibration.high_frequency > high_start_sensitivity_limit) {
|
||||||
|
high_frequency_scale =
|
||||||
|
std::max(1.0f - (vibration.high_frequency - high_start_sensitivity_limit) /
|
||||||
|
high_width_sensitivity_limit,
|
||||||
|
0.3f);
|
||||||
|
}
|
||||||
|
f32 high_amplitude = vibration.high_amplitude * high_frequency_scale;
|
||||||
|
|
||||||
if (sdl_controller) {
|
if (sdl_controller) {
|
||||||
return SDL_GameControllerRumble(
|
return SDL_GameControllerRumble(sdl_controller.get(), static_cast<u16>(low_amplitude),
|
||||||
sdl_controller.get(), static_cast<u16>(vibration.low_amplitude),
|
static_cast<u16>(high_amplitude),
|
||||||
static_cast<u16>(vibration.high_amplitude), rumble_max_duration_ms) != -1;
|
rumble_max_duration_ms) != -1;
|
||||||
} else if (sdl_joystick) {
|
} else if (sdl_joystick) {
|
||||||
return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(vibration.low_amplitude),
|
return SDL_JoystickRumble(sdl_joystick.get(), static_cast<u16>(low_amplitude),
|
||||||
static_cast<u16>(vibration.high_amplitude),
|
static_cast<u16>(high_amplitude),
|
||||||
rumble_max_duration_ms) != -1;
|
rumble_max_duration_ms) != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1284,7 +1284,7 @@ typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu
|
||||||
const VAddr overlap_cpu_addr = overlap.CpuAddr();
|
const VAddr overlap_cpu_addr = overlap.CpuAddr();
|
||||||
const bool expands_left = overlap_cpu_addr < begin;
|
const bool expands_left = overlap_cpu_addr < begin;
|
||||||
if (expands_left) {
|
if (expands_left) {
|
||||||
cpu_addr = begin = overlap_cpu_addr;
|
begin = overlap_cpu_addr;
|
||||||
}
|
}
|
||||||
const VAddr overlap_end = overlap_cpu_addr + overlap.SizeBytes();
|
const VAddr overlap_end = overlap_cpu_addr + overlap.SizeBytes();
|
||||||
const bool expands_right = overlap_end > end;
|
const bool expands_right = overlap_end > end;
|
||||||
|
@ -1297,8 +1297,10 @@ typename BufferCache<P>::OverlapResult BufferCache<P>::ResolveOverlaps(VAddr cpu
|
||||||
// as a stream buffer. Increase the size to skip constantly recreating buffers.
|
// as a stream buffer. Increase the size to skip constantly recreating buffers.
|
||||||
has_stream_leap = true;
|
has_stream_leap = true;
|
||||||
if (expands_right) {
|
if (expands_right) {
|
||||||
begin -= CACHING_PAGESIZE * 256;
|
begin -= YUZU_PAGESIZE * 256;
|
||||||
cpu_addr = begin;
|
// We're about to increment cpu_addr by YUZU_PAGESIZE, but have not yet checked for
|
||||||
|
// a buffer at the new begin.
|
||||||
|
cpu_addr = begin - YUZU_PAGESIZE;
|
||||||
}
|
}
|
||||||
if (expands_left) {
|
if (expands_left) {
|
||||||
end += CACHING_PAGESIZE * 256;
|
end += CACHING_PAGESIZE * 256;
|
||||||
|
@ -1321,7 +1323,7 @@ void BufferCache<P>::JoinOverlap(BufferId new_buffer_id, BufferId overlap_id,
|
||||||
if (accumulate_stream_score) {
|
if (accumulate_stream_score) {
|
||||||
new_buffer.IncreaseStreamScore(overlap.StreamScore() + 1);
|
new_buffer.IncreaseStreamScore(overlap.StreamScore() + 1);
|
||||||
}
|
}
|
||||||
boost::container::small_vector<BufferCopy, 1> copies;
|
boost::container::small_vector<BufferCopy, 10> copies;
|
||||||
const size_t dst_base_offset = overlap.CpuAddr() - new_buffer.CpuAddr();
|
const size_t dst_base_offset = overlap.CpuAddr() - new_buffer.CpuAddr();
|
||||||
copies.push_back(BufferCopy{
|
copies.push_back(BufferCopy{
|
||||||
.src_offset = 0,
|
.src_offset = 0,
|
||||||
|
|
|
@ -12,11 +12,11 @@ ConfigureGraphicsAdvanced::ConfigureGraphicsAdvanced(const Core::System& system_
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
ui->enable_compute_pipelines_checkbox->setVisible(false);
|
|
||||||
|
|
||||||
SetupPerGameUI();
|
SetupPerGameUI();
|
||||||
|
|
||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
|
|
||||||
|
ui->enable_compute_pipelines_checkbox->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
|
ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default;
|
||||||
|
|
|
@ -479,6 +479,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||||
param.Set("threshold", new_threshold / 1000.0f);
|
param.Set("threshold", new_threshold / 1000.0f);
|
||||||
emulated_controller->SetMotionParam(motion_id, param);
|
emulated_controller->SetMotionParam(motion_id, param);
|
||||||
});
|
});
|
||||||
|
context_menu.addAction(tr("Calibrate sensor"), [&] {
|
||||||
|
emulated_controller->StartMotionCalibration();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location));
|
context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location));
|
||||||
});
|
});
|
||||||
|
|
|
@ -582,9 +582,9 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center)
|
||||||
using namespace Settings::NativeMotion;
|
using namespace Settings::NativeMotion;
|
||||||
p.setPen(colors.outline);
|
p.setPen(colors.outline);
|
||||||
p.setBrush(colors.transparent);
|
p.setBrush(colors.transparent);
|
||||||
Draw3dCube(p, center + QPointF(-180, -5),
|
Draw3dCube(p, center + QPointF(-180, 90),
|
||||||
motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f);
|
motion_values[Settings::NativeMotion::MotionLeft].euler, 20.0f);
|
||||||
Draw3dCube(p, center + QPointF(180, -5),
|
Draw3dCube(p, center + QPointF(180, 90),
|
||||||
motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f);
|
motion_values[Settings::NativeMotion::MotionRight].euler, 20.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2926,14 +2926,14 @@ void PlayerControlPreview::DrawArrow(QPainter& p, const QPointF center, const Di
|
||||||
void PlayerControlPreview::Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler,
|
void PlayerControlPreview::Draw3dCube(QPainter& p, QPointF center, const Common::Vec3f& euler,
|
||||||
float size) {
|
float size) {
|
||||||
std::array<Common::Vec3f, 8> cube{
|
std::array<Common::Vec3f, 8> cube{
|
||||||
Common::Vec3f{-1, -1, -1},
|
Common::Vec3f{-0.7f, -1, -0.5f},
|
||||||
{-1, 1, -1},
|
{-0.7f, 1, -0.5f},
|
||||||
{1, 1, -1},
|
{0.7f, 1, -0.5f},
|
||||||
{1, -1, -1},
|
{0.7f, -1, -0.5f},
|
||||||
{-1, -1, 1},
|
{-0.7f, -1, 0.5f},
|
||||||
{-1, 1, 1},
|
{-0.7f, 1, 0.5f},
|
||||||
{1, 1, 1},
|
{0.7f, 1, 0.5f},
|
||||||
{1, -1, 1},
|
{0.7f, -1, 0.5f},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (Common::Vec3f& point : cube) {
|
for (Common::Vec3f& point : cube) {
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
#include "yuzu/qt_common.h"
|
#include "yuzu/qt_common.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#if !defined(WIN32) && !defined(__APPLE__)
|
||||||
#include <qpa/qplatformnativeinterface.h>
|
#include <qpa/qplatformnativeinterface.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue