Skip to content

Commit 874805c

Browse files
committed
engine: client: sdl: add support for built-in device gyroscope using SDL2 Sensor API (Android/iOS)
1 parent 84b7b58 commit 874805c

9 files changed

Lines changed: 245 additions & 0 deletions

File tree

engine/client/in_gyro.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
in_gyro.c - System gyroscope input code
3+
Copyright (C) 2026 Xash3D FWGS contributors
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
*/
15+
16+
#include "common.h"
17+
#include "input.h"
18+
#include "client.h"
19+
20+
static CVAR_DEFINE_AUTO( cl_gyro, "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enables aiming with built-in device gyroscope" );
21+
static CVAR_DEFINE_AUTO( cl_gyro_available, "0", FCVAR_READ_ONLY, "tells whether system gyroscope hardware is available or not" );
22+
static CVAR_DEFINE_AUTO( cl_gyro_pitch, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity for looking up and down" );
23+
static CVAR_DEFINE_AUTO( cl_gyro_yaw, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity for turning left and right" );
24+
static CVAR_DEFINE_AUTO( cl_gyro_roll, "0.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity when tilting the device sideways" );
25+
static CVAR_DEFINE_AUTO( cl_gyro_pitch_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope pitch axis deadzone (deg/s)" );
26+
static CVAR_DEFINE_AUTO( cl_gyro_yaw_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope yaw axis deadzone (deg/s)" );
27+
static CVAR_DEFINE_AUTO( cl_gyro_roll_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope roll axis deadzone (deg/s)" );
28+
29+
// stores the latest instantaneous rotation rates from built-in gyroscope
30+
static vec3_t cl_gyro_speed;
31+
32+
/*
33+
==============
34+
IN_GyroInit
35+
36+
==============
37+
*/
38+
void IN_GyroInit( void )
39+
{
40+
Cvar_RegisterVariable( &cl_gyro );
41+
Cvar_RegisterVariable( &cl_gyro_available );
42+
Cvar_RegisterVariable( &cl_gyro_pitch );
43+
Cvar_RegisterVariable( &cl_gyro_yaw );
44+
Cvar_RegisterVariable( &cl_gyro_roll );
45+
Cvar_RegisterVariable( &cl_gyro_pitch_deadzone );
46+
Cvar_RegisterVariable( &cl_gyro_yaw_deadzone );
47+
Cvar_RegisterVariable( &cl_gyro_roll_deadzone );
48+
}
49+
50+
/*
51+
==============
52+
IN_GyroCheckAvailability
53+
54+
One-time late check called after startup and configs
55+
==============
56+
*/
57+
void IN_GyroCheckAvailability( void )
58+
{
59+
#if XASH_SDL
60+
if( cl_gyro_available.value )
61+
return;
62+
63+
if( SDLash_GyroIsAvailable() )
64+
{
65+
Cvar_FullSet( "cl_gyro_available", "1", FCVAR_READ_ONLY );
66+
}
67+
#endif
68+
}
69+
70+
/*
71+
=============
72+
IN_GyroEvent
73+
74+
System gyroscope events from platform
75+
=============
76+
*/
77+
void IN_GyroEvent( vec3_t data )
78+
{
79+
VectorCopy( data, cl_gyro_speed );
80+
}
81+
82+
/*
83+
=============
84+
IN_GyroFinalizeMove
85+
86+
Apply gyro movement to view angles
87+
=============
88+
*/
89+
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
90+
{
91+
if( !cl_gyro.value || !cl_gyro_available.value )
92+
return;
93+
94+
// In Landscape mode axes are swapped relative to natural (Portrait) orientation
95+
// Y axis rotation becomes Pitch (up/down)
96+
// X axis rotation becomes Yaw (left/right)
97+
float pitch_speed = cl_gyro_speed[1] * ( 180.0f / M_PI );
98+
float yaw_speed = -cl_gyro_speed[0] * ( 180.0f / M_PI );
99+
float roll_speed = cl_gyro_speed[2] * ( 180.0f / M_PI );
100+
101+
if( fabs( pitch_speed ) < cl_gyro_pitch_deadzone.value )
102+
pitch_speed = 0.0f;
103+
if( fabs( yaw_speed ) < cl_gyro_yaw_deadzone.value )
104+
yaw_speed = 0.0f;
105+
if( fabs( roll_speed ) < cl_gyro_roll_deadzone.value )
106+
roll_speed = 0.0f;
107+
108+
*dpitch -= cl_gyro_pitch.value * pitch_speed * host.realframetime;
109+
*dyaw += cl_gyro_yaw.value * yaw_speed * host.realframetime;
110+
*dyaw += cl_gyro_roll.value * roll_speed * host.realframetime;
111+
112+
VectorClear( cl_gyro_speed );
113+
}

engine/client/input.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ void IN_Init( void )
445445
{
446446
IN_StartupMouse( );
447447

448+
IN_GyroInit();
449+
448450
Joy_Init(); // common joystick support init
449451

450452
Touch_Init();
@@ -560,6 +562,7 @@ static void IN_CollectInput( float *forward, float *side, float *pitch, float *y
560562
#endif
561563
}
562564

565+
IN_GyroFinalizeMove( forward, side, pitch, yaw );
563566
Joy_FinalizeMove( forward, side, pitch, yaw );
564567
Touch_GetMove( forward, side, pitch, yaw );
565568

engine/client/input.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ void IN_DeactivateMouse( void );
3939
void IN_MouseSavePos( void );
4040
void IN_MouseRestorePos( void );
4141
void IN_ToggleClientMouse( int newstate, int oldstate );
42+
void IN_GyroInit( void );
43+
void IN_GyroCheckAvailability( void );
44+
void IN_GyroEvent( vec3_t data );
45+
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw );
4246

4347
uint IN_CollectInputDevices( void );
4448
void IN_LockInputDevices( qboolean lock );

engine/common/host.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,6 +1276,10 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
12761276
Cbuf_ExecStuffCmds(); // execute stuffcmds (commandline)
12771277
SCR_CheckStartupVids(); // must be last
12781278

1279+
#ifndef XASH_DEDICATED
1280+
IN_GyroCheckAvailability();
1281+
#endif
1282+
12791283
if( Sys_GetParmFromCmdLine( "-timedemo", demoname ))
12801284
Cbuf_AddTextf( "timedemo %s\n", demoname );
12811285

engine/platform/platform.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ char *Posix_Input( void );
6464
void SDLash_Init( void );
6565
void SDLash_Shutdown( void );
6666
void SDLash_NanoSleep( int nsec );
67+
qboolean SDLash_GyroIsAvailable( void );
6768
#endif
6869

6970
#if XASH_ANDROID

engine/platform/sdl2/host_sdl2.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ static void SDLash_EventHandler( SDL_Event *event )
368368
#endif
369369
SDLash_HandleGameControllerEvent( event );
370370
break;
371+
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
372+
case SDL_SENSORUPDATE:
373+
SDLash_SensorUpdate( event->sensor );
374+
break;
375+
#endif
371376

372377
case SDL_WINDOWEVENT:
373378
if( event->window.windowID != SDL_GetWindowID( host.hWnd ) )

engine/platform/sdl2/platform_sdl2.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,15 @@ void SDLash_FreeCursors( void );
3535
//
3636
void SDLash_HandleGameControllerEvent( SDL_Event *ev );
3737

38+
//
39+
// sensor_sdl2.c
40+
//
41+
void SDLash_InitSensors( void );
42+
void SDLash_ShutdownSensors( void );
43+
qboolean SDLash_GyroIsAvailable( void );
44+
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
45+
void SDLash_SensorUpdate( SDL_SensorEvent sensor );
46+
#endif
47+
3848
#endif // XASH_SDL
3949
#endif // KEYWRAPPER_H

engine/platform/sdl2/sensor_sdl2.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
sensor_sdl2.c - SDL2 sensor handling
3+
Copyright (C) 2026 Xash3D FWGS contributors
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
*/
15+
16+
#include <SDL.h>
17+
#include "common.h"
18+
#include "input.h"
19+
#include "platform_sdl2.h"
20+
21+
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
22+
static SDL_SensorID g_system_gyro_id = -1;
23+
static SDL_Sensor *g_system_gyro;
24+
25+
/*
26+
==============
27+
SDLash_InitSensors
28+
29+
==============
30+
*/
31+
void SDLash_InitSensors( void )
32+
{
33+
if( SDL_InitSubSystem( SDL_INIT_SENSOR ) == 0 )
34+
{
35+
int num_sensors = SDL_NumSensors();
36+
37+
for( int i = 0; i < num_sensors; i++ )
38+
{
39+
if( SDL_SensorGetDeviceType( i ) == SDL_SENSOR_GYRO )
40+
{
41+
g_system_gyro = SDL_SensorOpen( i );
42+
if( g_system_gyro )
43+
{
44+
g_system_gyro_id = SDL_SensorGetInstanceID( g_system_gyro );
45+
Con_Printf( "SDL: Opened built-in gyroscope: %s\n", SDL_SensorGetName( g_system_gyro ) );
46+
break;
47+
}
48+
}
49+
}
50+
}
51+
else
52+
{
53+
Con_Reportf( S_ERROR "Failed to init SDL Sensor subsystem: %s\n", SDL_GetError() );
54+
}
55+
}
56+
57+
/*
58+
==============
59+
SDLash_ShutdownSensors
60+
61+
==============
62+
*/
63+
void SDLash_ShutdownSensors( void )
64+
{
65+
if( g_system_gyro )
66+
{
67+
SDL_SensorClose( g_system_gyro );
68+
g_system_gyro = NULL;
69+
g_system_gyro_id = -1;
70+
}
71+
72+
SDL_QuitSubSystem( SDL_INIT_SENSOR );
73+
}
74+
75+
/*
76+
==============
77+
SDLash_GyroIsAvailable
78+
79+
==============
80+
*/
81+
qboolean SDLash_GyroIsAvailable( void )
82+
{
83+
return ( g_system_gyro != NULL );
84+
}
85+
86+
/*
87+
==============
88+
SDLash_SensorUpdate
89+
90+
==============
91+
*/
92+
void SDLash_SensorUpdate( SDL_SensorEvent sensor )
93+
{
94+
if( sensor.which == g_system_gyro_id )
95+
{
96+
IN_GyroEvent( sensor.data );
97+
}
98+
}
99+
#else
100+
void SDLash_InitSensors( void ) { }
101+
void SDLash_ShutdownSensors( void ) { }
102+
qboolean SDLash_GyroIsAvailable( void ) { return false; }
103+
#endif

engine/platform/sdl2/sys_sdl2.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,12 @@ void SDLash_Init( void )
146146
SDL_StopTextInput();
147147

148148
SDLash_InitCursors();
149+
SDLash_InitSensors();
149150
}
150151

151152
void SDLash_Shutdown( void )
152153
{
154+
SDLash_ShutdownSensors();
153155
SDLash_FreeCursors();
154156

155157
SDL_Quit();

0 commit comments

Comments
 (0)