#include "common.h"
#include "gamepad.h"
#define LOOK_SENS_MULTIPLIER 3000.f
static unsigned long time;
static float delta;
static cvar_t *sensitivity;
static cvar_t *m_yaw;
static cvar_t *m_pitch;
static cvar_t *gp_deadzone;
static cvar_t *gp_sprint;
static cvar_t *gp_run;
static cvar_t *gp_accel;
static float dzStickLength[STICK_COUNT];
static float dzTrigger[TRIGGER_COUNT];
static BOOL buttons[BUTTON_COUNT][2];
static BOOL triggers[TRIGGER_COUNT][2];
static int cmdRightMove;
static int cmdForwardMove;
static BOOL cmdSprint;
static void gamepad_update_deadzone() {
gp_deadzone->modified = FALSE;
float v[STICK_COUNT + TRIGGER_COUNT];
sscanf_s(gp_deadzone->string,"%f %f %f %f", &v[0], &v[1], &v[2], &v[3]);
dzStickLength[STICK_LEFT] = v[0];
dzStickLength[STICK_RIGHT] = v[1];
dzTrigger[TRIGGER_LEFT] = v[2];
dzTrigger[TRIGGER_RIGHT] = v[3];
}
void gamepad_init() {
GamepadInit();
sensitivity = Cvar_Get("sensitivity", "5", CVAR_ARCHIVE);
m_yaw = Cvar_Get("m_yaw", "0.022", CVAR_ARCHIVE);
m_pitch = Cvar_Get("m_pitch", "0.022", CVAR_ARCHIVE);
gp_deadzone = Cvar_Get("gp_deadzone", ".1 .1 .1 .1", CVAR_ARCHIVE);
gp_sprint = Cvar_Get("gp_sprint", "1.0", CVAR_ARCHIVE);
gp_run = Cvar_Get("gp_run", "0.7", CVAR_ARCHIVE);
gp_accel = Cvar_Get("gp_accel", "1.5", CVAR_ARCHIVE);
gamepad_update_deadzone();
}
void gamepad_shutdown() {
GamepadShutdown();
}
static float gamepad_get_length(GAMEPAD_DEVICE device, GAMEPAD_STICK stick) {
float length = GamepadStickLength(device, stick);
if (length < dzStickLength[stick]) {
return .0f;
} else if (dzStickLength[stick] < 1.f) {
length -= dzStickLength[stick];
length *= 1.f / (1.f - dzStickLength[stick]);
}
return length;
}
static void gamepad_get_xy(GAMEPAD_DEVICE device, GAMEPAD_STICK stick, float *x, float *y) {
float angle, length;
angle = GamepadStickAngle(device, stick);
length = gamepad_get_length(device, stick);
*x = length * cosf(angle);
*y = length * sinf(angle);
}
static void gamepad_move(GAMEPAD_DEVICE device) {
float x, y;
int run = gp_run->value == .0f ? 255 : (int) (gp_run->value * 128.f);
gamepad_get_xy(device, STICK_LEFT, &x, &y);
cmdRightMove = (int) (x * 128.f);
cmdForwardMove = (int) (y * 128.f);
if (abs(cmdRightMove) > run) {
cmdRightMove = cmdRightMove > 0 ? 128 : -128;
}
if (abs(cmdForwardMove) > run) {
cmdForwardMove = cmdForwardMove > 0 ? 128 : -128;
}
cmdSprint = gp_sprint->value > .0f && GamepadStickLength(device, STICK_LEFT) >= gp_sprint->value;
}
static inline float gamepad_look_axis(float value, cvar_t *m) {
float multiplier = delta
* sensitivity->value
* m->value
* LOOK_SENS_MULTIPLIER;
if (gp_accel->value > .0f) {
multiplier *= powf(value * gp_accel->value * (value < .0f ? -1.f : 1.f), 2.f);
}
return multiplier * value;
}
static void gamepad_look(GAMEPAD_DEVICE device) {
float x, y;
gamepad_get_xy(device, STICK_RIGHT, &x, &y);
*game.mouseX = (*game.mouseX) - gamepad_look_axis(x, m_yaw);
*game.mouseY = (*game.mouseY) - gamepad_look_axis(y, m_pitch);
}
static void gamepad_buttons(GAMEPAD_DEVICE device) {
for (int i = BUTTON_DPAD_UP; i < BUTTON_COUNT; i++) {
buttons[i][0] = GamepadButtonDown(device, i);
}
for (int i = TRIGGER_LEFT; i < TRIGGER_COUNT; i++) {
triggers[i][0] = GamepadTriggerLength(device, i) > dzTrigger[i];
}
}
void gamepad_frame() {
unsigned long curTime = timeGetTime();
delta = (float) (curTime - time) / 1000;
time = curTime;
if (gp_deadzone->modified) {
gamepad_update_deadzone();
}
if (delta > 1.f || delta <= .0f) {
return;
}
GamepadUpdate();
for (int i = GAMEPAD_0; i < GAMEPAD_COUNT; i++) {
if (!GamepadIsConnected(i)) {
continue;
}
gamepad_move(i);
gamepad_look(i);
gamepad_buttons(i);
}
}
static signed char ClampChar(int i) {
if (i < -128) {
return -128;
}
if (i > 127) {
return 127;
}
return (signed char) i;
}
void gamepad_cmd(usercmd_t *cmd) {
cmd->rightmove = ClampChar(cmd->rightmove + cmdRightMove);
cmd->forwardmove = ClampChar(cmd->forwardmove + cmdForwardMove);
if (cmdSprint) {
cmd->buttons |= BUTTON_SPRINT;
} else if ((cmdRightMove != 0 || cmdForwardMove != 0)
&& abs(cmd->rightmove) < 64
&& abs(cmd->forwardmove) < 64) {
cmd->buttons |= BUTTON_WALKING;
cmd->buttons &= ~BUTTON_SPRINT;
}
if (cmd->buttons & BUTTON_SPRINT) {
if (abs(cmd->rightmove) > 64) {
cmd->rightmove = ClampChar(cmd->rightmove * 2);
}
if (abs(cmd->forwardmove) > 64) {
cmd->forwardmove = ClampChar(cmd->forwardmove * 2);
}
}
}
void gamepad_keys() {
for (int i = BUTTON_DPAD_UP; i < BUTTON_COUNT; i++) {
if (buttons[i][0] != buttons[i][1]) {
game.Sys_QueEvent(0, SE_KEY, K_JOY1 + i, buttons[i][0], 0, NULL);
buttons[i][1] = buttons[i][0];
}
}
for (int i = TRIGGER_LEFT; i < TRIGGER_COUNT; i++) {
if (triggers[i][0] != triggers[i][1]) {
game.Sys_QueEvent(0, SE_KEY, K_MOUSE2 - i, triggers[i][0], 0, NULL);
triggers[i][1] = triggers[i][0];
}
}
}