|
|
|
|
@@ -24,8 +24,6 @@ GNU General Public License for more details.
|
|
|
|
|
#define SHRT_MAX 0x7FFF
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define MAX_AXES JOY_AXIS_NULL
|
|
|
|
|
|
|
|
|
|
// index - axis num come from event
|
|
|
|
|
// value - inner axis
|
|
|
|
|
static engineAxis_t joyaxesmap[MAX_AXES] =
|
|
|
|
|
@@ -42,7 +40,9 @@ static struct joy_axis_s
|
|
|
|
|
{
|
|
|
|
|
short val;
|
|
|
|
|
short prevval;
|
|
|
|
|
short rawval; // value before deadzone zeroing, for debug display
|
|
|
|
|
} joyaxis[MAX_AXES] = { 0 };
|
|
|
|
|
|
|
|
|
|
static qboolean joy_initialized;
|
|
|
|
|
|
|
|
|
|
static CVAR_DEFINE_AUTO( joy_pitch, "100.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "joystick pitch sensitivity" );
|
|
|
|
|
@@ -65,9 +65,12 @@ static CVAR_DEFINE_AUTO( joy_calibrated, "0", FCVAR_READ_ONLY, "tells whether cu
|
|
|
|
|
static CVAR_DEFINE_AUTO( joy_gyro_pitch, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "gyroscope sensitivity for looking up and down" );
|
|
|
|
|
static CVAR_DEFINE_AUTO( joy_gyro_yaw, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "gyroscope sensitivity for turning left and right" );
|
|
|
|
|
static CVAR_DEFINE_AUTO( joy_gyro_roll, "0.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "gyroscope sensitivity when tilting the device sideways" );
|
|
|
|
|
static CVAR_DEFINE_AUTO( joy_debug, "0", 0, "visualize gamepad axes and buttons" );
|
|
|
|
|
|
|
|
|
|
// stores the latest instantaneous gyroscope rotation rates (in rad/s) from platform input
|
|
|
|
|
static vec3_t joy_gyro_speed;
|
|
|
|
|
// last non-zero gyro speed, retained for debug display after joy_gyro_speed is cleared
|
|
|
|
|
static vec3_t joy_gyro_speed_display;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
============
|
|
|
|
|
@@ -234,6 +237,8 @@ static void Joy_ProcessStick( const engineAxis_t engineAxis, short value )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
joyaxis[engineAxis].rawval = value;
|
|
|
|
|
|
|
|
|
|
if( value < deadzone && value > -deadzone )
|
|
|
|
|
value = 0; // caught new event in deadzone, fill it with zero(no motion)
|
|
|
|
|
|
|
|
|
|
@@ -263,12 +268,12 @@ Axis events
|
|
|
|
|
*/
|
|
|
|
|
void Joy_AxisMotionEvent( engineAxis_t engineAxis, short value )
|
|
|
|
|
{
|
|
|
|
|
if( engineAxis >= JOY_AXIS_NULL )
|
|
|
|
|
if( engineAxis >= MAX_AXES )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
engineAxis = joyaxesmap[engineAxis];
|
|
|
|
|
|
|
|
|
|
if( engineAxis >= JOY_AXIS_NULL )
|
|
|
|
|
if( engineAxis >= MAX_AXES )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if( value == joyaxis[engineAxis].val )
|
|
|
|
|
@@ -290,6 +295,7 @@ Gyroscope events
|
|
|
|
|
void Joy_GyroEvent( vec3_t data )
|
|
|
|
|
{
|
|
|
|
|
VectorCopy( data, joy_gyro_speed );
|
|
|
|
|
VectorCopy( data, joy_gyro_speed_display );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@@ -319,7 +325,7 @@ void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
|
|
|
|
|
case 'p': joyaxesmap[i] = JOY_AXIS_PITCH; break;
|
|
|
|
|
case 'r': joyaxesmap[i] = JOY_AXIS_RT; break;
|
|
|
|
|
case 'l': joyaxesmap[i] = JOY_AXIS_LT; break;
|
|
|
|
|
default : joyaxesmap[i] = JOY_AXIS_NULL; break;
|
|
|
|
|
default : joyaxesmap[i] = MAX_AXES; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -345,6 +351,178 @@ void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
|
|
|
|
|
VectorClear( joy_gyro_speed );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
Joy_DrawDebug
|
|
|
|
|
|
|
|
|
|
Draw gamepad axes and buttons for debugging (joy_debug 1)
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void Joy_DrawDebug( void )
|
|
|
|
|
{
|
|
|
|
|
static const int buttons[] =
|
|
|
|
|
{
|
|
|
|
|
K_A_BUTTON, K_B_BUTTON, K_X_BUTTON, K_Y_BUTTON, 0,
|
|
|
|
|
K_L1_BUTTON, K_R1_BUTTON, 0,
|
|
|
|
|
K_L2_BUTTON, K_R2_BUTTON, 0,
|
|
|
|
|
K_BACK_BUTTON, K_MODE_BUTTON, K_START_BUTTON, 0,
|
|
|
|
|
K_LSTICK, K_RSTICK, 0,
|
|
|
|
|
|
|
|
|
|
// simulated buttons
|
|
|
|
|
K_DPAD_UP, K_DPAD_DOWN, K_DPAD_LEFT, K_DPAD_RIGHT, 0,
|
|
|
|
|
K_LTRIGGER, K_RTRIGGER, 0,
|
|
|
|
|
|
|
|
|
|
// additional buttons
|
|
|
|
|
K_C_BUTTON, K_Z_BUTTON, K_MISC_BUTTON, 0,
|
|
|
|
|
K_PADDLE1_BUTTON, K_PADDLE2_BUTTON, K_PADDLE3_BUTTON, K_PADDLE4_BUTTON, 0
|
|
|
|
|
};
|
|
|
|
|
static const char *const axisnames[MAX_AXES] = { "SIDE", "FWD", "PITCH", "YAW", "RT", "LT" };
|
|
|
|
|
|
|
|
|
|
// deadzone for sticks, threshold for triggers
|
|
|
|
|
static const convar_t *const axis_threshold[MAX_AXES] =
|
|
|
|
|
{
|
|
|
|
|
&joy_side_deadzone,
|
|
|
|
|
&joy_forward_deadzone,
|
|
|
|
|
&joy_pitch_deadzone,
|
|
|
|
|
&joy_yaw_deadzone,
|
|
|
|
|
&joy_rt_threshold,
|
|
|
|
|
&joy_lt_threshold,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cl_font_t *font = Con_GetCurFont();
|
|
|
|
|
|
|
|
|
|
if( !joy_debug.value || !Joy_IsActive( ))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
float x = 8;
|
|
|
|
|
float y = 100;
|
|
|
|
|
const float bar_w = 100;
|
|
|
|
|
const float halfbar_w = bar_w * 0.5f;
|
|
|
|
|
const float bar_h = font->charHeight - 2;
|
|
|
|
|
const float center = x + halfbar_w;
|
|
|
|
|
|
|
|
|
|
const rgba_t bar_backcolor = { 40, 40, 40, 180 };
|
|
|
|
|
const rgba_t bar_fillcolor = { 100, 200, 100, 200 };
|
|
|
|
|
|
|
|
|
|
// draw axes as labeled bars
|
|
|
|
|
for( int i = 0; i < MAX_AXES; i++ )
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
qboolean is_trigger = ( i >= JOY_AXIS_RT );
|
|
|
|
|
float fval = (float)joyaxis[i].val / SHRT_MAX;
|
|
|
|
|
float fprev = (float)joyaxis[i].prevval / SHRT_MAX;
|
|
|
|
|
float fthreshold = axis_threshold[i]->value / SHRT_MAX;
|
|
|
|
|
|
|
|
|
|
CL_DrawString( x, y, axisnames[i], g_color_table[7], font, 0 );
|
|
|
|
|
y += font->charHeight;
|
|
|
|
|
|
|
|
|
|
// background
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, bar_w, bar_h, bar_backcolor[0], bar_backcolor[1], bar_backcolor[2], bar_backcolor[3] );
|
|
|
|
|
|
|
|
|
|
if( is_trigger )
|
|
|
|
|
{
|
|
|
|
|
// fill bar from the left for triggers
|
|
|
|
|
float filled = fval * bar_w;
|
|
|
|
|
|
|
|
|
|
if( filled > 0 )
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, filled, bar_h, bar_fillcolor[0], bar_fillcolor[1], bar_fillcolor[2], bar_fillcolor[3] );
|
|
|
|
|
|
|
|
|
|
// fill threshold with red, and yellow edge marker
|
|
|
|
|
float thresh_x = x + fthreshold * bar_w;
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, thresh_x - x, bar_h, 180, 40, 40, 120 );
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, thresh_x, y, 1, bar_h, 255, 200, 0, 220 );
|
|
|
|
|
|
|
|
|
|
// prevval marker
|
|
|
|
|
float prev_x = x + fprev * bar_w;
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, prev_x, y, 1, bar_h, 200, 200, 200, 180 );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// for sticks bar is filled from the center
|
|
|
|
|
float filled = fval * halfbar_w;
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, center + Q_min( 0, filled ), y, fabs( filled ), bar_h, bar_fillcolor[0], bar_fillcolor[1], bar_fillcolor[2], bar_fillcolor[3] );
|
|
|
|
|
|
|
|
|
|
// fill deadzone with red, and yellow edge marker
|
|
|
|
|
float thresh_x = fthreshold * halfbar_w;
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, center - thresh_x, y, thresh_x * 2, bar_h, 180, 40, 40, 120 );
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, center + thresh_x, y, 1, bar_h, 255, 200, 0, 220 );
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, center - thresh_x, y, 1, bar_h, 255, 200, 0, 220 );
|
|
|
|
|
|
|
|
|
|
// mark the center
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, center, y, 1, bar_h, 180, 180, 180, 220 );
|
|
|
|
|
|
|
|
|
|
// now draw the actual value
|
|
|
|
|
float raw_x = center + ((float)joyaxis[i].rawval / SHRT_MAX * halfbar_w );
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, raw_x, y, 1, bar_h, 255, 255, 100, 200 );
|
|
|
|
|
|
|
|
|
|
// prevval marker
|
|
|
|
|
float prev_x = center + fprev * halfbar_w;
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, prev_x, y, 1, bar_h, 200, 200, 200, 180 );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
y += bar_h + 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// draw gyro if available
|
|
|
|
|
if( joy_have_gyro.value )
|
|
|
|
|
{
|
|
|
|
|
static const char *gyronames[3] = { "GYRO P", "GYRO Y", "GYRO R" };
|
|
|
|
|
|
|
|
|
|
for( int i = 0; i < 3; i++ )
|
|
|
|
|
{
|
|
|
|
|
// clamp to +-5 rad/s for display
|
|
|
|
|
float fval = joy_gyro_speed_display[i] / 5.0f;
|
|
|
|
|
|
|
|
|
|
fval = bound( -1.0f, fval, 1.0f );
|
|
|
|
|
|
|
|
|
|
CL_DrawString( x, y, gyronames[i], g_color_table[7], font, 0 );
|
|
|
|
|
y += font->charHeight;
|
|
|
|
|
|
|
|
|
|
// background
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, x, y, bar_w, bar_h, bar_backcolor[0], bar_backcolor[1], bar_backcolor[2], bar_backcolor[3] );
|
|
|
|
|
|
|
|
|
|
// for gyro bar is filled from the center
|
|
|
|
|
float filled = fval * halfbar_w;
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, center + Q_min( 0, filled ), y, fabs( filled ), bar_h, bar_fillcolor[0], bar_fillcolor[1], bar_fillcolor[2], bar_fillcolor[3] );
|
|
|
|
|
|
|
|
|
|
// mark the center
|
|
|
|
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, center, y, 1, bar_h, 180, 180, 180, 220 );
|
|
|
|
|
|
|
|
|
|
// gyro doesn't have deadzones or prevval like axes
|
|
|
|
|
y += bar_h + 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// draw buttons in a row
|
|
|
|
|
y += 4;
|
|
|
|
|
x = 8;
|
|
|
|
|
for( int i = 0; i < ARRAYSIZE( buttons ); i++ )
|
|
|
|
|
{
|
|
|
|
|
if( !buttons[i] )
|
|
|
|
|
{
|
|
|
|
|
x = 8;
|
|
|
|
|
y += font->charHeight;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qboolean pressed = Key_IsDown( buttons[i] );
|
|
|
|
|
int btn_w = 0;
|
|
|
|
|
rgba_t color;
|
|
|
|
|
string name;
|
|
|
|
|
|
|
|
|
|
Q_strncpy( name, Key_KeynumToString( buttons[i] ), sizeof( name ));
|
|
|
|
|
|
|
|
|
|
char *p = Q_strstr( name, "_BUTTON" );
|
|
|
|
|
if( p )
|
|
|
|
|
*p = 0;
|
|
|
|
|
|
|
|
|
|
MakeRGBA( color, pressed ? 0 : 255, pressed ? 255 : 0, 0, 255 );
|
|
|
|
|
CL_DrawString( x, y, name, color, font, 0 );
|
|
|
|
|
CL_DrawStringLen( font, name, &btn_w, NULL, 0 );
|
|
|
|
|
x += btn_w + 6;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void Joy_CalibrateGyro_f( void )
|
|
|
|
|
{
|
|
|
|
|
if( !joy_have_gyro.value )
|
|
|
|
|
@@ -394,6 +572,7 @@ void Joy_Init( void )
|
|
|
|
|
Cvar_RegisterVariable( &joy_gyro_pitch );
|
|
|
|
|
Cvar_RegisterVariable( &joy_gyro_yaw );
|
|
|
|
|
Cvar_RegisterVariable( &joy_gyro_roll );
|
|
|
|
|
Cvar_RegisterVariable( &joy_debug );
|
|
|
|
|
|
|
|
|
|
// renamed from -nojoy to -noenginejoy to not conflict with
|
|
|
|
|
// client.dll's joystick support
|
|
|
|
|
|