Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions engine/client/in_gyro.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
in_gyro.c - System gyroscope input code
Copyright (C) 2026 Xash3D FWGS contributors

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/

#include "common.h"
#include "input.h"
#include "client.h"

static CVAR_DEFINE_AUTO( gyro_enable, "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enables aiming with built-in device gyroscope" );
static CVAR_DEFINE_AUTO( gyro_available, "0", FCVAR_READ_ONLY, "tells whether system gyroscope hardware is available or not" );
static CVAR_DEFINE_AUTO( gyro_pitch, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity for looking up and down" );
static CVAR_DEFINE_AUTO( gyro_yaw, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity for turning left and right" );
static CVAR_DEFINE_AUTO( gyro_roll, "0.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity when tilting the device sideways" );
static CVAR_DEFINE_AUTO( gyro_pitch_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope pitch axis deadzone (deg/s)" );
static CVAR_DEFINE_AUTO( gyro_yaw_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope yaw axis deadzone (deg/s)" );
static CVAR_DEFINE_AUTO( gyro_roll_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope roll axis deadzone (deg/s)" );

// stores the latest instantaneous rotation rates from built-in gyroscope
static vec3_t gyro_speed;

/*
==============
IN_GyroInit

==============
*/
void IN_GyroInit( void )
{
Cvar_RegisterVariable( &gyro_enable );
Cvar_RegisterVariable( &gyro_available );
Cvar_RegisterVariable( &gyro_pitch );
Cvar_RegisterVariable( &gyro_yaw );
Cvar_RegisterVariable( &gyro_roll );
Cvar_RegisterVariable( &gyro_pitch_deadzone );
Cvar_RegisterVariable( &gyro_yaw_deadzone );
Cvar_RegisterVariable( &gyro_roll_deadzone );
}

/*
==============
IN_GyroCheckAvailability

One-time late check called after startup and configs
==============
*/
void IN_GyroCheckAvailability( void )
{
#if XASH_SDL
if( gyro_available.value )
return;

if( SDLash_GyroIsAvailable() )
{
Cvar_FullSet( "gyro_available", "1", FCVAR_READ_ONLY );
}
#endif
}

/*
=============
IN_GyroEvent

System gyroscope events from platform
=============
*/
void IN_GyroEvent( vec3_t data )
{
VectorCopy( data, gyro_speed );
}

/*
=============
IN_GyroFinalizeMove

Apply gyro movement to view angles
=============
*/
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
{
platform_orientation_t orient;
float orient_scale = 1.0f;

if( !gyro_enable.value || !gyro_available.value )
return;

orient = Platform_GetDisplayOrientation();
if( orient == ORIENTATION_LANDSCAPE_FLIPPED )
orient_scale = -1.0f;

// In Landscape mode axes are swapped relative to natural (Portrait) orientation
Comment thread
Vladislav4KZ marked this conversation as resolved.
// Y axis rotation becomes Pitch (up/down)
// X axis rotation becomes Yaw (left/right)
float pitch_speed = -orient_scale * gyro_speed[1] * ( 180.0f / M_PI );
float yaw_speed = -orient_scale * gyro_speed[0] * ( 180.0f / M_PI );
float roll_speed = orient_scale * gyro_speed[2] * ( 180.0f / M_PI );

if( fabs( pitch_speed ) < gyro_pitch_deadzone.value )
pitch_speed = 0.0f;
if( fabs( yaw_speed ) < gyro_yaw_deadzone.value )
yaw_speed = 0.0f;
if( fabs( roll_speed ) < gyro_roll_deadzone.value )
roll_speed = 0.0f;

*dpitch -= gyro_pitch.value * pitch_speed * host.realframetime;
*dyaw += gyro_yaw.value * yaw_speed * host.realframetime;
*dyaw += gyro_roll.value * roll_speed * host.realframetime;

VectorClear( gyro_speed );
}
3 changes: 3 additions & 0 deletions engine/client/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ void IN_Init( void )
{
IN_StartupMouse( );

IN_GyroInit();

Joy_Init(); // common joystick support init

Touch_Init();
Expand Down Expand Up @@ -560,6 +562,7 @@ static void IN_CollectInput( float *forward, float *side, float *pitch, float *y
#endif
}

IN_GyroFinalizeMove( forward, side, pitch, yaw );
Joy_FinalizeMove( forward, side, pitch, yaw );
Touch_GetMove( forward, side, pitch, yaw );

Expand Down
4 changes: 4 additions & 0 deletions engine/client/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ void IN_DeactivateMouse( void );
void IN_MouseSavePos( void );
void IN_MouseRestorePos( void );
void IN_ToggleClientMouse( int newstate, int oldstate );
void IN_GyroInit( void );
void IN_GyroCheckAvailability( void );
void IN_GyroEvent( vec3_t data );
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw );

uint IN_CollectInputDevices( void );
void IN_LockInputDevices( qboolean lock );
Expand Down
4 changes: 4 additions & 0 deletions engine/common/host.c
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,10 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
Cbuf_ExecStuffCmds(); // execute stuffcmds (commandline)
SCR_CheckStartupVids(); // must be last

#ifndef XASH_DEDICATED
IN_GyroCheckAvailability();
#endif

if( Sys_GetParmFromCmdLine( "-timedemo", demoname ))
Cbuf_AddTextf( "timedemo %s\n", demoname );

Expand Down
12 changes: 12 additions & 0 deletions engine/platform/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ void Platform_MessageBox( const char *title, const char *message, qboolean paren
void Platform_SetStatus( const char *status );
qboolean Platform_DebuggerPresent( void );

typedef enum
{
ORIENTATION_UNKNOWN = 0,
ORIENTATION_LANDSCAPE,
ORIENTATION_LANDSCAPE_FLIPPED,
ORIENTATION_PORTRAIT,
ORIENTATION_PORTRAIT_FLIPPED
} platform_orientation_t;

platform_orientation_t Platform_GetDisplayOrientation( void );

// legacy iOS port functions
#if XASH_IOS
int IOS_GetArgs( char ***argv );
Expand All @@ -64,6 +75,7 @@ char *Posix_Input( void );
void SDLash_Init( void );
void SDLash_Shutdown( void );
void SDLash_NanoSleep( int nsec );
qboolean SDLash_GyroIsAvailable( void );
#endif

#if XASH_ANDROID
Expand Down
5 changes: 5 additions & 0 deletions engine/platform/sdl2/host_sdl2.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ static void SDLash_EventHandler( SDL_Event *event )
#endif
SDLash_HandleGameControllerEvent( event );
break;
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
case SDL_SENSORUPDATE:
SDLash_SensorUpdate( event->sensor );
break;
#endif

case SDL_WINDOWEVENT:
if( event->window.windowID != SDL_GetWindowID( host.hWnd ) )
Expand Down
10 changes: 10 additions & 0 deletions engine/platform/sdl2/platform_sdl2.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,15 @@ void SDLash_FreeCursors( void );
//
void SDLash_HandleGameControllerEvent( SDL_Event *ev );

//
// sensor_sdl2.c
//
void SDLash_InitSensors( void );
void SDLash_ShutdownSensors( void );
qboolean SDLash_GyroIsAvailable( void );
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
void SDLash_SensorUpdate( SDL_SensorEvent sensor );
#endif

#endif // XASH_SDL
#endif // KEYWRAPPER_H
103 changes: 103 additions & 0 deletions engine/platform/sdl2/sensor_sdl2.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
sensor_sdl2.c - SDL2 sensor handling
Copyright (C) 2026 Xash3D FWGS contributors

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/

#include <SDL.h>
#include "common.h"
#include "input.h"
#include "platform_sdl2.h"

#if SDL_VERSION_ATLEAST( 2, 0, 14 )
static SDL_SensorID g_system_gyro_id = -1;
static SDL_Sensor *g_system_gyro;

/*
==============
SDLash_InitSensors

==============
*/
void SDLash_InitSensors( void )
{
if( SDL_InitSubSystem( SDL_INIT_SENSOR ) == 0 )
{
int num_sensors = SDL_NumSensors();

for( int i = 0; i < num_sensors; i++ )
{
if( SDL_SensorGetDeviceType( i ) == SDL_SENSOR_GYRO )
{
g_system_gyro = SDL_SensorOpen( i );
if( g_system_gyro )
{
g_system_gyro_id = SDL_SensorGetInstanceID( g_system_gyro );
Con_Printf( "SDL: Opened built-in gyroscope: %s\n", SDL_SensorGetName( g_system_gyro ) );
break;
}
}
}
}
else
{
Con_Reportf( S_ERROR "Failed to init SDL Sensor subsystem: %s\n", SDL_GetError() );
}
}

/*
==============
SDLash_ShutdownSensors

==============
*/
void SDLash_ShutdownSensors( void )
{
if( g_system_gyro )
{
SDL_SensorClose( g_system_gyro );
g_system_gyro = NULL;
g_system_gyro_id = -1;
}

SDL_QuitSubSystem( SDL_INIT_SENSOR );
}

/*
==============
SDLash_GyroIsAvailable

==============
*/
qboolean SDLash_GyroIsAvailable( void )
{
return ( g_system_gyro != NULL );
}

/*
==============
SDLash_SensorUpdate

==============
*/
void SDLash_SensorUpdate( SDL_SensorEvent sensor )
{
if( sensor.which == g_system_gyro_id )
{
IN_GyroEvent( sensor.data );
Comment thread
Vladislav4KZ marked this conversation as resolved.
}
}
#else
void SDLash_InitSensors( void ) { }
void SDLash_ShutdownSensors( void ) { }
qboolean SDLash_GyroIsAvailable( void ) { return false; }
#endif
2 changes: 2 additions & 0 deletions engine/platform/sdl2/sys_sdl2.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,12 @@ void SDLash_Init( void )
SDL_StopTextInput();

SDLash_InitCursors();
SDLash_InitSensors();
}

void SDLash_Shutdown( void )
{
SDLash_ShutdownSensors();
SDLash_FreeCursors();

SDL_Quit();
Expand Down
26 changes: 26 additions & 0 deletions engine/platform/sdl2/vid_sdl2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1204,3 +1204,29 @@ void VID_Info_f( void )
else
Con_Printf( "Window display mode: " S_RED "fail: " S_DEFAULT "%s\n", SDL_GetError( ));
}

platform_orientation_t Platform_GetDisplayOrientation( void )
{
if( host.hWnd )
{
int display_index = SDL_GetWindowDisplayIndex( host.hWnd );
if( display_index >= 0 )
{
switch( SDL_GetDisplayOrientation( display_index ) )
{
case SDL_ORIENTATION_LANDSCAPE:
return ORIENTATION_LANDSCAPE;
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
return ORIENTATION_LANDSCAPE_FLIPPED;
case SDL_ORIENTATION_PORTRAIT:
return ORIENTATION_PORTRAIT;
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
return ORIENTATION_PORTRAIT_FLIPPED;
default:
return ORIENTATION_UNKNOWN;
}
}
}

return ORIENTATION_UNKNOWN;
}
Loading