Skip to content

Commit

Permalink
Merge branch 'master' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
Electronicks committed Jun 2, 2021
2 parents 2893927 + 587cf08 commit 239372f
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 32 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
Most recent updates will appear first.
This is a summary of new features and bugfixes. Read the README to learn how to use the features mentioned here.

## 3.2.0

Jibb added the new GYRO_SPACE setting for more one-size-fits-all gyro aiming. Default behaviour is unchanged, but set to WORLD_TURN to try the new algorithm (or WORLD_LEAN if you prefer to lean your controller side to side to turn the camera). He also added the option for automatic gyro calibration.

### Features

* GYRO_SPACE can be set to LOCAL (default), WORLD_TURN (recommended), or WORLD_LEAN.
* AUTO_CALIBRATE_GYRO can be set to ON to activate automatic calibration, which will try and detect when the controller is held still or put down and recalibrate automatically.

## 3.1.1

Fix linux build (Thanks TauAkiou)
Expand Down
2 changes: 1 addition & 1 deletion JoyShockMapper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ target_link_libraries (
CPMAddPackage (
NAME GamepadMotionHelpers
GITHUB_REPOSITORY JibbSmart/GamepadMotionHelpers
GIT_TAG main
GIT_TAG wip
)

target_link_libraries (
Expand Down
8 changes: 8 additions & 0 deletions JoyShockMapper/include/JoyShockMapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ enum class SettingID
FLICK_DEADZONE_ANGLE,
FLICK_TIME_EXPONENT,
CONTROLLER_ORIENTATION,
GYRO_SPACE,
TRACKBALL_DECAY,
TRIGGER_SKIP_DELAY,
TURBO_PERIOD,
Expand Down Expand Up @@ -274,6 +275,13 @@ constexpr float MAGIC_INSTANT_DURATION = 40.0f; // in milliseconds
constexpr float MAGIC_EXTENDED_TAP_DURATION = 500.0f; // in milliseconds
constexpr int MAGIC_TRIGGER_SMOOTHING = 5; // in samples

enum class GyroSpace
{
LOCAL,
WORLD_TURN,
WORLD_LEAN,
INVALID
};
enum class ControllerOrientation
{
FORWARD,
Expand Down
1 change: 1 addition & 0 deletions JoyShockMapper/include/MotionIf.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class MotionIf
virtual void ResetContinuousCalibration() = 0;
virtual void GetCalibrationOffset(float& xOffset, float& yOffset, float& zOffset) = 0;
virtual void SetCalibrationOffset(float xOffset, float yOffset, float zOffset, int weight) = 0;
virtual void SetAutoCalibration(bool enabled, float gyroThreshold, float accelThreshold) = 0;

void virtual ResetMotion() = 0;
};
14 changes: 14 additions & 0 deletions JoyShockMapper/src/MotionImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ class MotionImpl : public MotionIf
gamepadMotion.SetCalibrationOffset(xOffset, yOffset, zOffset, weight);
}

virtual void SetAutoCalibration(bool enabled, float gyroThreshold, float accelThreshold) override
{
if (enabled)
{
gamepadMotion.SetCalibrationMode(GamepadMotionHelpers::CalibrationMode::Stillness | GamepadMotionHelpers::CalibrationMode::SensorFusion);
gamepadMotion.Settings.StillnessGyroDelta = gyroThreshold;
gamepadMotion.Settings.StillnessAccelDelta = accelThreshold;
}
else
{
gamepadMotion.SetCalibrationMode(GamepadMotionHelpers::CalibrationMode::Manual);
}
}

void virtual ResetMotion() override
{
gamepadMotion.ResetMotion();
Expand Down
155 changes: 131 additions & 24 deletions JoyShockMapper/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ JSMSetting<float> motion_deadzone_inner = JSMSetting<float>(SettingID::MOTION_DE
JSMSetting<float> motion_deadzone_outer = JSMSetting<float>(SettingID::MOTION_DEADZONE_OUTER, 135.f);
JSMSetting<float> lean_threshold = JSMSetting<float>(SettingID::LEAN_THRESHOLD, 15.f);
JSMSetting<ControllerOrientation> controller_orientation = JSMSetting<ControllerOrientation>(SettingID::CONTROLLER_ORIENTATION, ControllerOrientation::FORWARD);
JSMSetting<GyroSpace> gyro_space = JSMSetting<GyroSpace>(SettingID::GYRO_SPACE, GyroSpace::LOCAL);
JSMSetting<float> trackball_decay = JSMSetting<float>(SettingID::TRACKBALL_DECAY, 1.0f);
JSMSetting<float> mouse_ring_radius = JSMSetting<float>(SettingID::MOUSE_RING_RADIUS, 128.0f);
JSMSetting<float> screen_resolution_x = JSMSetting<float>(SettingID::SCREEN_RESOLUTION_X, 1920.0f);
Expand Down Expand Up @@ -115,6 +116,7 @@ JSMVariable<int> left_trigger_offset = JSMVariable<int>(25);
JSMVariable<int> left_trigger_range = JSMVariable<int>(150);
JSMVariable<int> right_trigger_offset = JSMVariable<int>(25);
JSMVariable<int> right_trigger_range = JSMVariable<int>(150);
JSMVariable<Switch> auto_calibrate_gyro = JSMVariable<Switch>(Switch::OFF);

JSMVariable<PathString> currentWorkingDir = JSMVariable<PathString>(PathString());
vector<JSMButton> grid_mappings; // array of virtual buttons on the touchpad grid
Expand Down Expand Up @@ -573,6 +575,9 @@ class JoyShock
}
}
break;
case SettingID::GYRO_SPACE:
opt = GetOptionalSetting<E>(gyro_space, *activeChord);
break;
case SettingID::ZR_MODE:
opt = GetOptionalSetting<E>(zrMode, *activeChord);
break;
Expand Down Expand Up @@ -1370,6 +1375,7 @@ static void resetAllMappings()
aim_x_sign.Reset();
gyro_y_sign.Reset();
gyro_x_sign.Reset();
gyro_space.Reset();
flick_time.Reset();
flick_time_exponent.Reset();
gyro_smooth_time.Reset();
Expand Down Expand Up @@ -2330,16 +2336,21 @@ void joyShockPollCallback(int jcHandle, JOY_SHOCK_STATE state, JOY_SHOCK_STATE l

IMU_STATE imu = jsl->GetIMUState(jc->handle);

if (auto_calibrate_gyro.get() == Switch::ON)
{
motion.SetAutoCalibration(true, 1.2f, 0.015f);
}
else
{
motion.SetAutoCalibration(false, 0.f, 0.f);
}
motion.ProcessMotion(imu.gyroX, imu.gyroY, imu.gyroZ, imu.accelX, imu.accelY, imu.accelZ, deltaTime);

float inGyroX, inGyroY, inGyroZ;
motion.GetCalibratedGyro(inGyroX, inGyroY, inGyroZ);

float inGravX, inGravY, inGravZ;
motion.GetGravity(inGravX, inGravY, inGravZ);
inGravX *= 1.f / 9.8f; // to Gs
inGravY *= 1.f / 9.8f;
inGravZ *= 1.f / 9.8f;

float inQuatW, inQuatX, inQuatY, inQuatZ;
motion.GetOrientation(inQuatW, inQuatX, inQuatY, inQuatZ);
Expand Down Expand Up @@ -2369,32 +2380,122 @@ void joyShockPollCallback(int jcHandle, JOY_SHOCK_STATE state, JOY_SHOCK_STATE l

float gyroX = 0.0;
float gyroY = 0.0;
int mouse_x_flag = (int)jc->getSetting<GyroAxisMask>(SettingID::MOUSE_X_FROM_GYRO_AXIS);
if ((mouse_x_flag & (int)GyroAxisMask::X) > 0)
{
gyroX += inGyroX;
}
if ((mouse_x_flag & (int)GyroAxisMask::Y) > 0)
GyroSpace gyroSpace = jc->getSetting<GyroSpace>(SettingID::GYRO_SPACE);
if (gyroSpace == GyroSpace::LOCAL)
{
gyroX -= inGyroY;
}
if ((mouse_x_flag & (int)GyroAxisMask::Z) > 0)
{
gyroX -= inGyroZ;
int mouse_x_flag = (int)jc->getSetting<GyroAxisMask>(SettingID::MOUSE_X_FROM_GYRO_AXIS);
if ((mouse_x_flag & (int)GyroAxisMask::X) > 0)
{
gyroX += inGyroX;
}
if ((mouse_x_flag & (int)GyroAxisMask::Y) > 0)
{
gyroX -= inGyroY;
}
if ((mouse_x_flag & (int)GyroAxisMask::Z) > 0)
{
gyroX -= inGyroZ;
}
int mouse_y_flag = (int)jc->getSetting<GyroAxisMask>(SettingID::MOUSE_Y_FROM_GYRO_AXIS);
if ((mouse_y_flag & (int)GyroAxisMask::X) > 0)
{
gyroY -= inGyroX;
}
if ((mouse_y_flag & (int)GyroAxisMask::Y) > 0)
{
gyroY += inGyroY;
}
if ((mouse_y_flag & (int)GyroAxisMask::Z) > 0)
{
gyroY += inGyroZ;
}
}
int mouse_y_flag = (int)jc->getSetting<GyroAxisMask>(SettingID::MOUSE_Y_FROM_GYRO_AXIS);
if ((mouse_y_flag & (int)GyroAxisMask::X) > 0)
else if (gyroSpace == GyroSpace::WORLD_TURN || gyroSpace == GyroSpace::WORLD_LEAN)
{
float gravLength = sqrtf(inGravX * inGravX + inGravY * inGravY + inGravZ * inGravZ);
float normGravX = 0.f;
float normGravY = 0.f;
float normGravZ = 0.f;
if (gravLength > 0.f)
{
float gravNormalizer = 1.f / gravLength;
normGravX = inGravX * gravNormalizer;
normGravY = inGravY * gravNormalizer;
normGravZ = inGravZ * gravNormalizer;
}

float flatness = abs(normGravY);
if (flatness > 1.f)
{
flatness = 1.f;
}
float upness = sqrtf(1.f - flatness);
float flatFactor = min(flatness / 0.5f, 1.f);
float upFactor = min(upness / 0.5f, 1.f);
bool flatsideDown = normGravY < 0.f;
bool upsideDown = normGravZ < 0.f;

if (gyroSpace == GyroSpace::WORLD_TURN)
{
if (flatsideDown) inGyroY = -inGyroY;
if (upsideDown) inGyroZ = -inGyroZ;
if (flatness > upness)
{
float gyroSign = inGyroZ < 0.f ? -1.f : 1.f;
float reducedGyro = gyroSign * abs(inGyroY) * min(upness / flatness, abs(inGyroZ / inGyroY));
inGyroZ = reducedGyro + (inGyroZ - reducedGyro) * upFactor;
}
else
{
float gyroSign = inGyroY < 0.f ? -1.f : 1.f;
float reducedGyro = gyroSign * abs(inGyroZ) * min(flatness / upness, abs(inGyroY / inGyroZ));
inGyroY = reducedGyro + (inGyroY - reducedGyro) * flatFactor;
}
}
else // WORLD_LEAN
{
if (!upsideDown) inGyroY = -inGyroY;
if (flatsideDown) inGyroZ = -inGyroZ;
if (flatness > upness)
{
float gyroSign = inGyroZ < 0.f ? -1.f : 1.f;
float reducedGyro = gyroSign * abs(inGyroZ) * min(upness / flatness, abs(inGyroY / inGyroZ));
inGyroY = reducedGyro + (inGyroY - reducedGyro) * flatFactor;
}
else
{
float gyroSign = inGyroY < 0.f ? -1.f : 1.f;
float reducedGyro = gyroSign * abs(inGyroY) * min(flatness / upness, abs(inGyroZ / inGyroY));
inGyroZ = reducedGyro + (inGyroZ - reducedGyro) * upFactor;
}
}
float bigger;
float smaller;
if (abs(inGyroY) > abs(inGyroZ))
{
bigger = inGyroY;
smaller = inGyroZ;
}
else
{
bigger = inGyroZ;
smaller = inGyroY;
}
if (inGyroZ * inGyroY >= 0.f)
{
// same sign (ish)
const float gyroSign = bigger > 0.f ? 1.f : -1.f;
gyroX += gyroSign * sqrtf(bigger * bigger + smaller * smaller);
}
else
{
// opposite sign
const float gyroSign = bigger > 0.f ? 1.f : -1.f;
gyroX += gyroSign * sqrtf(bigger * bigger - smaller * smaller);
}

gyroY -= inGyroX;
}
if ((mouse_y_flag & (int)GyroAxisMask::Y) > 0)
{
gyroY += inGyroY;
}
if ((mouse_y_flag & (int)GyroAxisMask::Z) > 0)
{
gyroY += inGyroZ;
}
float gyroLength = sqrt(gyroX * gyroX + gyroY * gyroY);
// do gyro smoothing
// convert gyro smooth time to number of samples
Expand Down Expand Up @@ -3341,6 +3442,7 @@ int main(int argc, char *argv[])
joycon_gyro_mask.SetFilter(&filterInvalidValue<JoyconMask, JoyconMask::INVALID>);
joycon_motion_mask.SetFilter(&filterInvalidValue<JoyconMask, JoyconMask::INVALID>);
controller_orientation.SetFilter(&filterInvalidValue<ControllerOrientation, ControllerOrientation::INVALID>);
gyro_space.SetFilter(&filterInvalidValue<GyroSpace, GyroSpace::INVALID>);
zlMode.SetFilter(&filterTriggerMode);
zrMode.SetFilter(&filterTriggerMode);
flick_snap_mode.SetFilter(&filterInvalidValue<FlickSnapMode, FlickSnapMode::INVALID>);
Expand Down Expand Up @@ -3412,6 +3514,7 @@ int main(int argc, char *argv[])
left_trigger_offset.SetFilter(&filterClampByte);
right_trigger_range.SetFilter(&filterClampByte);
left_trigger_range.SetFilter(&filterClampByte);
auto_calibrate_gyro.SetFilter(&filterInvalidValue<Switch, Switch::INVALID>);

// light_bar needs no filter or listener. The callback polls and updates the color.
for (int i = argc - 1; i >= 0; --i)
Expand Down Expand Up @@ -3547,6 +3650,8 @@ int main(int argc, char *argv[])
->SetHelp("Pick a gyro axis to operate on the mouse's Y axis. Valid values are the following: X, Y and Z."));
commandRegistry.Add((new JSMAssignment<ControllerOrientation>(controller_orientation))
->SetHelp("Let the stick modes account for how you're holding the controller:\nFORWARD, LEFT, RIGHT, BACKWARD"));
commandRegistry.Add((new JSMAssignment<GyroSpace>(gyro_space))
->SetHelp("How gyro input is converted to 2D input. With LOCAL, your MOUSE_X_FROM_GYRO_AXIS and MOUSE_Y_FROM_GYRO_AXIS settings decide which local angular axis maps to which 2D mouse axis.\nYour other options are WORLD_TURN and WORLD_LEAN. These both take gravity into account to combine your axes more reliably.\n\tUse WORLD_TURN if you like to turn your camera or move your cursor by turning your controller side to side.\n\tUse WORLD_LEAN if you'd rather lean your controller to turn the camera."));
commandRegistry.Add((new JSMAssignment<TriggerMode>(zlMode))
->SetHelp("Controllers with a right analog trigger can use one of the following dual stage trigger modes:\nNO_FULL, NO_SKIP, MAY_SKIP, MUST_SKIP, MAY_SKIP_R, MUST_SKIP_R, NO_SKIP_EXCLUSIVE, X_LT, X_RT, PS_L2, PS_R2"));
commandRegistry.Add((new JSMAssignment<TriggerMode>(zrMode))
Expand Down Expand Up @@ -3627,6 +3732,8 @@ int main(int argc, char *argv[])
commandRegistry.Add((new JSMAssignment<int>(magic_enum::enum_name(SettingID::RIGHT_TRIGGER_OFFSET).data(), right_trigger_offset)));
commandRegistry.Add((new JSMAssignment<int>(magic_enum::enum_name(SettingID::LEFT_TRIGGER_RANGE).data(), left_trigger_range)));
commandRegistry.Add((new JSMAssignment<int>(magic_enum::enum_name(SettingID::RIGHT_TRIGGER_RANGE).data(), right_trigger_range)));
commandRegistry.Add((new JSMAssignment<Switch>("AUTO_CALIBRATE_GYRO", auto_calibrate_gyro))
->SetHelp("Gyro calibration happens automatically when this setting is ON. Otherwise you'll need to calibrate the gyro manually when using gyro aiming."));

bool quit = false;
commandRegistry.Add((new JSMMacro("QUIT"))
Expand Down
Loading

0 comments on commit 239372f

Please sign in to comment.