|
40 | 40 | #include "core/os/thread.h" |
41 | 41 | #endif |
42 | 42 |
|
| 43 | +#include "thirdparty/gamepadmotionhelpers/GamepadMotion.hpp" |
| 44 | + |
| 45 | +#define STANDARD_GRAVITY 9.80665f |
| 46 | + |
43 | 47 | static const char *_joy_buttons[(size_t)JoyButton::SDL_MAX] = { |
44 | 48 | "a", |
45 | 49 | "b", |
@@ -147,6 +151,20 @@ void Input::_bind_methods() { |
147 | 151 | ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer); |
148 | 152 | ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer); |
149 | 153 | ClassDB::bind_method(D_METHOD("get_gyroscope"), &Input::get_gyroscope); |
| 154 | + ClassDB::bind_method(D_METHOD("get_joy_accelerometer", "device"), &Input::get_joy_accelerometer); |
| 155 | + ClassDB::bind_method(D_METHOD("get_joy_gravity", "device"), &Input::get_joy_gravity); |
| 156 | + ClassDB::bind_method(D_METHOD("get_joy_gyroscope", "device"), &Input::get_joy_gyroscope); |
| 157 | + ClassDB::bind_method(D_METHOD("get_joy_motion_sensors_rate", "device"), &Input::get_joy_motion_sensors_rate); |
| 158 | + ClassDB::bind_method(D_METHOD("is_joy_motion_sensors_enabled", "device"), &Input::is_joy_motion_sensors_enabled); |
| 159 | + ClassDB::bind_method(D_METHOD("set_joy_motion_sensors_enabled", "device", "enable"), &Input::set_joy_motion_sensors_enabled); |
| 160 | + ClassDB::bind_method(D_METHOD("has_joy_motion_sensors", "device"), &Input::has_joy_motion_sensors); |
| 161 | + ClassDB::bind_method(D_METHOD("start_joy_motion_sensors_calibration", "device"), &Input::start_joy_motion_sensors_calibration); |
| 162 | + ClassDB::bind_method(D_METHOD("stop_joy_motion_sensors_calibration", "device"), &Input::stop_joy_motion_sensors_calibration); |
| 163 | + ClassDB::bind_method(D_METHOD("clear_joy_motion_sensors_calibration", "device"), &Input::clear_joy_motion_sensors_calibration); |
| 164 | + ClassDB::bind_method(D_METHOD("get_joy_motion_sensors_calibration", "device"), &Input::get_joy_motion_sensors_calibration); |
| 165 | + ClassDB::bind_method(D_METHOD("set_joy_motion_sensors_calibration", "device", "calibration_info"), &Input::set_joy_motion_sensors_calibration); |
| 166 | + ClassDB::bind_method(D_METHOD("is_joy_motion_sensors_calibrated", "device"), &Input::is_joy_motion_sensors_calibrated); |
| 167 | + ClassDB::bind_method(D_METHOD("is_joy_motion_sensors_calibrating", "device"), &Input::is_joy_motion_sensors_calibrating); |
150 | 168 | ClassDB::bind_method(D_METHOD("set_gravity", "value"), &Input::set_gravity); |
151 | 169 | ClassDB::bind_method(D_METHOD("set_accelerometer", "value"), &Input::set_accelerometer); |
152 | 170 | ClassDB::bind_method(D_METHOD("set_magnetometer", "value"), &Input::set_magnetometer); |
@@ -684,6 +702,11 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, const String &p_ |
684 | 702 | for (int i = 0; i < (int)JoyAxis::MAX; i++) { |
685 | 703 | set_joy_axis(p_idx, (JoyAxis)i, 0.0f); |
686 | 704 | } |
| 705 | + MotionInfo *motion = joy_motion.getptr(p_idx); |
| 706 | + if (motion != nullptr && motion->gamepad_motion != nullptr) { |
| 707 | + delete motion->gamepad_motion; |
| 708 | + } |
| 709 | + joy_motion.erase(p_idx); |
687 | 710 | } |
688 | 711 | joy_names[p_idx] = js; |
689 | 712 |
|
@@ -1018,6 +1041,196 @@ bool Input::has_joy_light(int p_device) const { |
1018 | 1041 | return joypad && joypad->has_light; |
1019 | 1042 | } |
1020 | 1043 |
|
| 1044 | +Vector3 Input::get_joy_accelerometer(int p_device) const { |
| 1045 | + _THREAD_SAFE_METHOD_ |
| 1046 | + const MotionInfo *motion = joy_motion.getptr(p_device); |
| 1047 | + if (motion == nullptr) { |
| 1048 | + return Vector3(); |
| 1049 | + } |
| 1050 | + |
| 1051 | + float joy_acceleration_data[3]; |
| 1052 | + motion->gamepad_motion->GetProcessedAcceleration(joy_acceleration_data[0], joy_acceleration_data[1], joy_acceleration_data[2]); |
| 1053 | + Vector3 joy_acceleration(joy_acceleration_data[0], joy_acceleration_data[1], joy_acceleration_data[2]); |
| 1054 | + |
| 1055 | + float joy_gravity_data[3]; |
| 1056 | + motion->gamepad_motion->GetGravity(joy_gravity_data[0], joy_gravity_data[1], joy_gravity_data[2]); |
| 1057 | + Vector3 joy_gravity(joy_gravity_data[0], joy_gravity_data[1], joy_gravity_data[2]); |
| 1058 | + |
| 1059 | + return (-joy_acceleration + joy_gravity) * STANDARD_GRAVITY; |
| 1060 | +} |
| 1061 | + |
| 1062 | +Vector3 Input::get_joy_gravity(int p_device) const { |
| 1063 | + _THREAD_SAFE_METHOD_ |
| 1064 | + const MotionInfo *motion = joy_motion.getptr(p_device); |
| 1065 | + if (motion == nullptr) { |
| 1066 | + return Vector3(); |
| 1067 | + } |
| 1068 | + |
| 1069 | + float joy_gravity_data[3]; |
| 1070 | + motion->gamepad_motion->GetGravity(joy_gravity_data[0], joy_gravity_data[1], joy_gravity_data[2]); |
| 1071 | + Vector3 joy_gravity(joy_gravity_data[0], joy_gravity_data[1], joy_gravity_data[2]); |
| 1072 | + |
| 1073 | + return joy_gravity.normalized() * STANDARD_GRAVITY; |
| 1074 | +} |
| 1075 | + |
| 1076 | +Vector3 Input::get_joy_gyroscope(int p_device) const { |
| 1077 | + _THREAD_SAFE_METHOD_ |
| 1078 | + const MotionInfo *motion = joy_motion.getptr(p_device); |
| 1079 | + if (motion == nullptr) { |
| 1080 | + return Vector3(); |
| 1081 | + } |
| 1082 | + |
| 1083 | + float joy_gyro_data[3]; |
| 1084 | + motion->gamepad_motion->GetCalibratedGyro(joy_gyro_data[0], joy_gyro_data[1], joy_gyro_data[2]); |
| 1085 | + Vector3 joy_gyro(joy_gyro_data[0], joy_gyro_data[1], joy_gyro_data[2]); |
| 1086 | + |
| 1087 | + return joy_gyro * M_PI / 180.0; |
| 1088 | +} |
| 1089 | + |
| 1090 | +void Input::set_joy_motion_sensors_enabled(int p_device, bool p_enable) { |
| 1091 | + _THREAD_SAFE_METHOD_ |
| 1092 | + Joypad *joypad = joy_names.getptr(p_device); |
| 1093 | + if (joypad == nullptr || joypad->features == nullptr) { |
| 1094 | + return; |
| 1095 | + } |
| 1096 | + MotionInfo *motion = joy_motion.getptr(p_device); |
| 1097 | + if (motion == nullptr) { |
| 1098 | + return; |
| 1099 | + } |
| 1100 | + joypad->features->set_joy_motion_sensors_enabled(p_enable); |
| 1101 | + motion->sensors_enabled = p_enable; |
| 1102 | +} |
| 1103 | + |
| 1104 | +bool Input::is_joy_motion_sensors_enabled(int p_device) const { |
| 1105 | + _THREAD_SAFE_METHOD_ |
| 1106 | + const MotionInfo *motion = joy_motion.getptr(p_device); |
| 1107 | + return motion != nullptr && motion->sensors_enabled; |
| 1108 | +} |
| 1109 | + |
| 1110 | +bool Input::has_joy_motion_sensors(int p_device) const { |
| 1111 | + _THREAD_SAFE_METHOD_ |
| 1112 | + return joy_motion.has(p_device); |
| 1113 | +} |
| 1114 | + |
| 1115 | +float Input::get_joy_motion_sensors_rate(int p_device) const { |
| 1116 | + _THREAD_SAFE_METHOD_ |
| 1117 | + const MotionInfo *motion = joy_motion.getptr(p_device); |
| 1118 | + if (motion == nullptr) { |
| 1119 | + return 0.0f; |
| 1120 | + } |
| 1121 | + return motion->sensor_data_rate; |
| 1122 | +} |
| 1123 | + |
| 1124 | +void Input::start_joy_motion_sensors_calibration(int p_device) { |
| 1125 | + _THREAD_SAFE_METHOD_ |
| 1126 | + MotionInfo *motion = joy_motion.getptr(p_device); |
| 1127 | + if (motion == nullptr) { |
| 1128 | + return; |
| 1129 | + } |
| 1130 | + |
| 1131 | + ERR_FAIL_COND_MSG(!motion->sensors_enabled, "Motion sensors are not enabled on the joypad."); |
| 1132 | + ERR_FAIL_COND_MSG(motion->calibrating, "Calibration already in progress."); |
| 1133 | + |
| 1134 | + motion->gamepad_motion->ResetContinuousCalibration(); |
| 1135 | + motion->gamepad_motion->StartContinuousCalibration(); |
| 1136 | + |
| 1137 | + motion->calibrating = true; |
| 1138 | + motion->calibrated = false; |
| 1139 | +} |
| 1140 | + |
| 1141 | +void Input::stop_joy_motion_sensors_calibration(int p_device) { |
| 1142 | + _THREAD_SAFE_METHOD_ |
| 1143 | + MotionInfo *motion = joy_motion.getptr(p_device); |
| 1144 | + if (motion == nullptr) { |
| 1145 | + return; |
| 1146 | + } |
| 1147 | + |
| 1148 | + ERR_FAIL_COND_MSG(!motion->sensors_enabled, "Motion sensors are not enabled on the joypad."); |
| 1149 | + ERR_FAIL_COND_MSG(!motion->calibrating, "Calibration hasn't been started."); |
| 1150 | + |
| 1151 | + motion->gamepad_motion->PauseContinuousCalibration(); |
| 1152 | + |
| 1153 | + motion->calibrating = false; |
| 1154 | + motion->calibrated = true; |
| 1155 | +} |
| 1156 | + |
| 1157 | +void Input::clear_joy_motion_sensors_calibration(int p_device) { |
| 1158 | + _THREAD_SAFE_METHOD_ |
| 1159 | + MotionInfo *motion = joy_motion.getptr(p_device); |
| 1160 | + if (motion == nullptr) { |
| 1161 | + return; |
| 1162 | + } |
| 1163 | + |
| 1164 | + // Calibration might be in progress and the developer or the user might want to reset it, |
| 1165 | + // so no need to stop the calibration. |
| 1166 | + |
| 1167 | + motion->gamepad_motion->ResetContinuousCalibration(); |
| 1168 | +} |
| 1169 | + |
| 1170 | +Dictionary Input::get_joy_motion_sensors_calibration(int p_device) const { |
| 1171 | + _THREAD_SAFE_METHOD_ |
| 1172 | + const MotionInfo *motion = joy_motion.getptr(p_device); |
| 1173 | + if (motion == nullptr) { |
| 1174 | + return Dictionary(); |
| 1175 | + } |
| 1176 | + |
| 1177 | + if (!motion->calibrated) { |
| 1178 | + return Dictionary(); |
| 1179 | + } |
| 1180 | + |
| 1181 | + float joy_gyro_offset_data[3]; |
| 1182 | + motion->gamepad_motion->GetCalibrationOffset(joy_gyro_offset_data[0], joy_gyro_offset_data[1], joy_gyro_offset_data[2]); |
| 1183 | + Vector3 joy_gyro_offset(joy_gyro_offset_data[0], joy_gyro_offset_data[1], joy_gyro_offset_data[2]); |
| 1184 | + |
| 1185 | + Dictionary result; |
| 1186 | + result["gyroscope_offset"] = joy_gyro_offset * M_PI / 180.0; |
| 1187 | + return result; |
| 1188 | +} |
| 1189 | + |
| 1190 | +void Input::set_joy_motion_sensors_calibration(int p_device, const Dictionary &p_calibration_info) { |
| 1191 | + _THREAD_SAFE_METHOD_ |
| 1192 | + MotionInfo *motion = joy_motion.getptr(p_device); |
| 1193 | + if (motion == nullptr) { |
| 1194 | + return; |
| 1195 | + } |
| 1196 | + |
| 1197 | + ERR_FAIL_COND_MSG(motion->calibrating, "Calibration is currently in progress."); |
| 1198 | + |
| 1199 | + Vector3 gyro_offset = p_calibration_info.get("gyroscope_offset", Vector3()).operator Vector3() * 180.0 / M_PI; |
| 1200 | + |
| 1201 | + motion->gamepad_motion->SetCalibrationOffset(gyro_offset.x, gyro_offset.y, gyro_offset.z, 1); |
| 1202 | + motion->calibrating = false; |
| 1203 | + motion->calibrated = true; |
| 1204 | +} |
| 1205 | + |
| 1206 | +bool Input::is_joy_motion_sensors_calibrating(int p_device) const { |
| 1207 | + _THREAD_SAFE_METHOD_ |
| 1208 | + const MotionInfo *motion = joy_motion.getptr(p_device); |
| 1209 | + if (motion == nullptr) { |
| 1210 | + return false; |
| 1211 | + } |
| 1212 | + return motion->calibrating; |
| 1213 | +} |
| 1214 | + |
| 1215 | +bool Input::is_joy_motion_sensors_calibrated(int p_device) const { |
| 1216 | + _THREAD_SAFE_METHOD_ |
| 1217 | + const MotionInfo *motion = joy_motion.getptr(p_device); |
| 1218 | + if (motion == nullptr) { |
| 1219 | + return false; |
| 1220 | + } |
| 1221 | + return motion->calibrated; |
| 1222 | +} |
| 1223 | + |
| 1224 | +void Input::set_joy_motion_sensors_rate(int p_device, float p_rate) { |
| 1225 | + _THREAD_SAFE_METHOD_ |
| 1226 | + MotionInfo *motion = joy_motion.getptr(p_device); |
| 1227 | + if (motion == nullptr) { |
| 1228 | + return; |
| 1229 | + } |
| 1230 | + |
| 1231 | + motion->sensor_data_rate = p_rate; |
| 1232 | +} |
| 1233 | + |
1021 | 1234 | void Input::start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration) { |
1022 | 1235 | _THREAD_SAFE_METHOD_ |
1023 | 1236 | if (p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) { |
@@ -1469,6 +1682,22 @@ void Input::joy_hat(int p_device, BitField<HatMask> p_val) { |
1469 | 1682 | joy_names[p_device].hat_current = (int)p_val; |
1470 | 1683 | } |
1471 | 1684 |
|
| 1685 | +void Input::joy_motion_sensors(int p_device, const Vector3 &p_accelerometer, const Vector3 &p_gyroscope) { |
| 1686 | + _THREAD_SAFE_METHOD_ |
| 1687 | + // TODO: events |
| 1688 | + MotionInfo *motion = joy_motion.getptr(p_device); |
| 1689 | + if (motion == nullptr) { |
| 1690 | + return; |
| 1691 | + } |
| 1692 | + |
| 1693 | + Vector3 gyro_degrees = p_gyroscope * 180.0 / M_PI; |
| 1694 | + Vector3 accel_g = -p_accelerometer / STANDARD_GRAVITY; |
| 1695 | + uint64_t new_timestamp = OS::get_singleton()->get_ticks_msec(); |
| 1696 | + float delta_time = (new_timestamp - motion->last_timestamp) / 1000.0f; |
| 1697 | + motion->last_timestamp = new_timestamp; |
| 1698 | + motion->gamepad_motion->ProcessMotion(gyro_degrees.x, gyro_degrees.y, gyro_degrees.z, accel_g.x, accel_g.y, accel_g.z, delta_time); |
| 1699 | +} |
| 1700 | + |
1472 | 1701 | void Input::_button_event(int p_device, JoyButton p_index, bool p_pressed) { |
1473 | 1702 | Ref<InputEventJoypadButton> ievent; |
1474 | 1703 | ievent.instantiate(); |
@@ -1520,6 +1749,16 @@ void Input::_update_joypad_features(int p_device) { |
1520 | 1749 | if (joypad->features->has_joy_light()) { |
1521 | 1750 | joypad->has_light = true; |
1522 | 1751 | } |
| 1752 | + if (joypad->features->has_joy_motion_sensors()) { |
| 1753 | + MotionInfo &motion = joy_motion[p_device]; |
| 1754 | + |
| 1755 | + if (!motion.gamepad_motion) { |
| 1756 | + motion.gamepad_motion = new GamepadMotion(); |
| 1757 | + } else { |
| 1758 | + motion.gamepad_motion->Reset(); |
| 1759 | + } |
| 1760 | + motion.last_timestamp = OS::get_singleton()->get_ticks_msec(); |
| 1761 | + } |
1523 | 1762 | } |
1524 | 1763 |
|
1525 | 1764 | Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) { |
|
0 commit comments