Browse Source

Rotate the sensor axes to match gamepad orientation when using the device sensors for game controllers

Sam Lantinga 1 year ago
parent
commit
8de6ce7e92
2 changed files with 28 additions and 8 deletions
  1. 4 6
      include/SDL3/SDL_sensor.h
  2. 24 2
      src/joystick/SDL_gamepad.c

+ 4 - 6
include/SDL3/SDL_sensor.h

@@ -89,13 +89,12 @@ typedef enum
  * values[1]: Acceleration on the y axis
  * values[2]: Acceleration on the z axis
  *
- * For phones held in portrait mode and game controllers held in front of you,
- * the axes are defined as follows:
+ * For phones and tablets held in natural orientation and game controllers held in front of you, the axes are defined as follows:
  * -X ... +X : left ... right
  * -Y ... +Y : bottom ... top
  * -Z ... +Z : farther ... closer
  *
- * The axis data is not changed when the phone is rotated.
+ * The axis data is not changed when the device is rotated.
  *
  * \sa SDL_GetDisplayOrientation()
  */
@@ -114,13 +113,12 @@ typedef enum
  * values[1]: Angular speed around the y axis (yaw)
  * values[2]: Angular speed around the z axis (roll)
  *
- * For phones held in portrait mode and game controllers held in front of you,
- * the axes are defined as follows:
+ * For phones and tablets held in natural orientation and game controllers held in front of you, the axes are defined as follows:
  * -X ... +X : left ... right
  * -Y ... +Y : bottom ... top
  * -Z ... +Z : farther ... closer
  *
- * The axis data is not changed when the phone or controller is rotated.
+ * The axis data is not changed when the device is rotated.
  *
  * \sa SDL_GetDisplayOrientation()
  */

+ 24 - 2
src/joystick/SDL_gamepad.c

@@ -370,6 +370,24 @@ static void RecenterGamepad(SDL_Gamepad *gamepad)
     }
 }
 
+/* SDL defines sensor orientation for phones relative to the natural
+   orientation, and for gamepads relative to being held in front of you.
+   When a phone is being used as a gamepad, its orientation changes,
+   so adjust sensor axes to match.
+ */
+static void AdjustSensorOrientation(float *src, float *dst)
+{
+    /* When a phone is rotated left and laid flat, the axes change
+       orientation as follows:
+        -X to +X becomes +Z to -Z
+        -Y to +Y becomes +X to -X
+        -Z to +Z becomes -Y to +Y
+    */
+    dst[0] = -src[1];
+    dst[1] = src[2];
+    dst[2] = -src[0];
+}
+
 /*
  * Event filter to fire gamepad events from joystick ones
  */
@@ -449,10 +467,14 @@ static int SDLCALL SDL_GamepadEventWatcher(void *userdata, SDL_Event *event)
         SDL_LockJoysticks();
         for (gamepad = SDL_gamepads; gamepad; gamepad = gamepad->next) {
             if (gamepad->joystick->accel && gamepad->joystick->accel_sensor == event->sensor.which) {
-                SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_ACCEL, event->sensor.sensor_timestamp, event->sensor.data, SDL_arraysize(event->sensor.data));
+                float data[3];
+                AdjustSensorOrientation(event->sensor.data, data);
+                SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_ACCEL, event->sensor.sensor_timestamp, data, SDL_arraysize(data));
             }
             if (gamepad->joystick->gyro && gamepad->joystick->gyro_sensor == event->sensor.which) {
-                SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_GYRO, event->sensor.sensor_timestamp, event->sensor.data, SDL_arraysize(event->sensor.data));
+                float data[3];
+                AdjustSensorOrientation(event->sensor.data, data);
+                SDL_SendJoystickSensor(event->common.timestamp, gamepad->joystick, SDL_SENSOR_GYRO, event->sensor.sensor_timestamp, data, SDL_arraysize(data));
             }
         }
         SDL_UnlockJoysticks();