mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-25 22:05:20 -04:00
More mouse improvements (#1348)
* Check `oldlookdir` before disabling `centering` When turning off mouselook/padlook, keep view centering enabled until `oldlookdir` is zero, meaning when the player's view actually appears centered. * Move `viewangleoffset` * Check dead state set by `P_KillMobj()` * Smooth composite/mouse turning transitions Blend interpolated composite input (e.g. keyboard) turning with direct mouse turning to prevent choppy transitions. * Group inputs by composite/gamepad/mouse * Update carry/input calculations This also enables shorttics (lowres_turn) with fast mouse polling. * Add mouse smoothing toggle With mouse smoothing disabled (default), mouse movements are immediately reflected in each frame update, with the game simulation following behind. The higher the framerate, the lower the perceived input lag. With mouse smoothing enabled, mouse movements are delayed by up to one tic (~29 ms) due to interpolation. When recording older format demos with reduced turning resolution (or when using `-shorttics`), interpolation may still be preferred for smoother turning. * Rename "mouse smoothing" to "raw mouse input" * Skip calculations when using interpolation
This commit is contained in:
parent
e0d30bbe6e
commit
1a9d580bd5
@ -174,9 +174,10 @@ int eventhead, eventtail;
|
||||
//
|
||||
void D_PostEvent(event_t *ev)
|
||||
{
|
||||
if (ev->type == ev_mouse && !menuactive && gamestate == GS_LEVEL && !paused)
|
||||
if (ev->type == ev_mouse)
|
||||
{
|
||||
G_MouseMovementResponder(ev);
|
||||
G_PrepTiccmd();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -239,9 +240,9 @@ void D_Display (void)
|
||||
// [AM] Figure out how far into the current tic we're in as a fixed_t.
|
||||
fractionaltic = I_GetFracTime();
|
||||
|
||||
if (window_focused)
|
||||
if (!menuactive && gamestate == GS_LEVEL && !paused && mouse_raw_input)
|
||||
{
|
||||
I_ReadMouse();
|
||||
I_StartDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
|
410
src/g_game.c
410
src/g_game.c
@ -171,19 +171,18 @@ static int mousex;
|
||||
static int mousey;
|
||||
boolean dclick;
|
||||
|
||||
// Skip mouse if using a controller and recording in strict mode (DSDA rule).
|
||||
static boolean skip_mouse = true;
|
||||
|
||||
typedef struct cmd_carry_s
|
||||
typedef struct carry_s
|
||||
{
|
||||
double angle;
|
||||
double pitch;
|
||||
double strafe;
|
||||
double side;
|
||||
double vert;
|
||||
} cmd_carry_t;
|
||||
short lowres;
|
||||
} carry_t;
|
||||
|
||||
static cmd_carry_t cmd_prev_carry;
|
||||
static cmd_carry_t cmd_carry;
|
||||
static carry_t prevcarry;
|
||||
static carry_t carry;
|
||||
static ticcmd_t basecmd;
|
||||
|
||||
boolean joyarray[MAX_JSB+1]; // [FG] support more joystick buttons
|
||||
boolean *joybuttons = &joyarray[1]; // allow [-1]
|
||||
@ -369,93 +368,101 @@ static void G_DemoSkipTics(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int CarryError(double value, double *prev_carry, double *carry)
|
||||
static int CarryError(double value, const double *prevcarry, double *carry)
|
||||
{
|
||||
const double desired = value + *prev_carry;
|
||||
const double desired = value + *prevcarry;
|
||||
const int actual = lround(desired);
|
||||
*carry = desired - actual;
|
||||
return actual;
|
||||
}
|
||||
|
||||
static int CalcMouseAngle(int mousex)
|
||||
static int CarryAngle(double angle)
|
||||
{
|
||||
if (mouseSensitivity_horiz)
|
||||
{
|
||||
const double angle = (I_AccelerateMouse(mousex) *
|
||||
(mouseSensitivity_horiz + 5) * 8 / 10);
|
||||
return CarryError(angle, &cmd_prev_carry.angle, &cmd_carry.angle);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd_prev_carry.angle = 0.0;
|
||||
cmd_carry.angle = 0.0;
|
||||
return 0;
|
||||
}
|
||||
return CarryError(angle, &prevcarry.angle, &carry.angle);
|
||||
}
|
||||
|
||||
static int CalcMousePitch(int mousey)
|
||||
static int CarryMousePitch(double pitch)
|
||||
{
|
||||
if (mouseSensitivity_vert_look)
|
||||
{
|
||||
const double pitch = (I_AccelerateMouse(mouse_y_invert ? -mousey : mousey) *
|
||||
(mouseSensitivity_vert_look + 5) / 10);
|
||||
return CarryError(pitch, &cmd_prev_carry.pitch, &cmd_carry.pitch);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd_prev_carry.pitch = 0.0;
|
||||
cmd_carry.pitch = 0.0;
|
||||
return 0;
|
||||
}
|
||||
return CarryError(pitch, &prevcarry.pitch, &carry.pitch);
|
||||
}
|
||||
|
||||
static int CalcMouseStrafe(int mousex)
|
||||
static int CarryMouseVert(double vert)
|
||||
{
|
||||
if (mouseSensitivity_horiz_strafe)
|
||||
{
|
||||
const double desired = (cmd_prev_carry.strafe + I_AccelerateMouse(mousex) *
|
||||
(mouseSensitivity_horiz_strafe + 5) * 2 / 10);
|
||||
const int actual = lround(desired * 0.5) * 2; // Even values only.
|
||||
cmd_carry.strafe = desired - actual;
|
||||
return actual;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd_prev_carry.strafe = 0.0;
|
||||
cmd_carry.strafe = 0.0;
|
||||
return 0;
|
||||
}
|
||||
return CarryError(vert, &prevcarry.vert, &carry.vert);
|
||||
}
|
||||
|
||||
static int CalcMouseVert(int mousey)
|
||||
static int CarryMouseSide(double side)
|
||||
{
|
||||
if (mouseSensitivity_vert)
|
||||
{
|
||||
const double vert = (I_AccelerateMouse(mousey) *
|
||||
(mouseSensitivity_vert + 5) / 10);
|
||||
return CarryError(vert, &cmd_prev_carry.vert, &cmd_carry.vert);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd_prev_carry.vert = 0.0;
|
||||
cmd_carry.vert = 0.0;
|
||||
return 0;
|
||||
}
|
||||
const double desired = side + prevcarry.side;
|
||||
const int actual = lround(desired * 0.5) * 2; // Even values only.
|
||||
carry.side = desired - actual;
|
||||
return actual;
|
||||
}
|
||||
|
||||
void G_MouseMovementResponder(const event_t *ev)
|
||||
static short CarryLowResAngle(short angle)
|
||||
{
|
||||
if (strictmode && demorecording && skip_mouse)
|
||||
return;
|
||||
const short desired = angle + prevcarry.lowres;
|
||||
// Round to nearest 256 for single byte turning. From Chocolate Doom.
|
||||
const short actual = (desired + 128) & 0xFF00;
|
||||
carry.lowres = desired - actual;
|
||||
return actual;
|
||||
}
|
||||
|
||||
mousex += ev->data2;
|
||||
mousey += ev->data3;
|
||||
static double CalcMouseAngle(int mousex)
|
||||
{
|
||||
if (!mouseSensitivity_horiz)
|
||||
return 0.0;
|
||||
|
||||
return (I_AccelerateMouse(mousex) * (mouseSensitivity_horiz + 5) * 8 / 10);
|
||||
}
|
||||
|
||||
static double CalcMousePitch(int mousey)
|
||||
{
|
||||
if (!mouseSensitivity_vert_look)
|
||||
return 0.0;
|
||||
|
||||
return (I_AccelerateMouse(mousey) * direction[mouse_y_invert] *
|
||||
(mouseSensitivity_vert_look + 5) / 10);
|
||||
}
|
||||
|
||||
static double CalcMouseSide(int mousex)
|
||||
{
|
||||
if (!mouseSensitivity_horiz_strafe)
|
||||
return 0.0;
|
||||
|
||||
return (I_AccelerateMouse(mousex) *
|
||||
(mouseSensitivity_horiz_strafe + 5) * 2 / 10);
|
||||
}
|
||||
|
||||
static double CalcMouseVert(int mousey)
|
||||
{
|
||||
if (!mouseSensitivity_vert)
|
||||
return 0.0;
|
||||
|
||||
return (I_AccelerateMouse(mousey) * (mouseSensitivity_vert + 5) / 10);
|
||||
}
|
||||
|
||||
void G_PrepTiccmd(void)
|
||||
{
|
||||
ticcmd_t *cmd = &basecmd;
|
||||
|
||||
if (!M_InputGameActive(input_strafe))
|
||||
localview.angle = CalcMouseAngle(mousex);
|
||||
{
|
||||
localview.rawangle = -CalcMouseAngle(mousex);
|
||||
cmd->angleturn = CarryAngle(localview.rawangle);
|
||||
if (lowres_turn)
|
||||
{
|
||||
cmd->angleturn = CarryLowResAngle(cmd->angleturn);
|
||||
}
|
||||
localview.angle = cmd->angleturn << 16;
|
||||
}
|
||||
|
||||
if (mouselook)
|
||||
localview.pitch = CalcMousePitch(mousey);
|
||||
{
|
||||
const double pitch = CalcMousePitch(mousey);
|
||||
cmd->lookdir = CarryMousePitch(pitch);
|
||||
localview.pitch = cmd->lookdir;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@ -467,98 +474,67 @@ void G_MouseMovementResponder(const event_t *ev)
|
||||
|
||||
void G_BuildTiccmd(ticcmd_t* cmd)
|
||||
{
|
||||
boolean strafe;
|
||||
int speed;
|
||||
int tspeed;
|
||||
int forward;
|
||||
int side;
|
||||
const boolean strafe = M_InputGameActive(input_strafe);
|
||||
const boolean turnleft = M_InputGameActive(input_turnleft);
|
||||
const boolean turnright = M_InputGameActive(input_turnright);
|
||||
// [FG] speed key inverts autorun
|
||||
const int speed = autorun ^ M_InputGameActive(input_speed); // phares
|
||||
int angle = 0;
|
||||
int pitch = 0;
|
||||
int forward = 0;
|
||||
int side = 0;
|
||||
int newweapon; // phares
|
||||
ticcmd_t *base;
|
||||
|
||||
extern boolean boom_weapon_state_injection;
|
||||
static boolean done_autoswitch = false;
|
||||
|
||||
// Assume localview can be used unless mouse input is interrupted by other
|
||||
// inputs that apply turning or looking up/down (e.g. keyboard or gamepad).
|
||||
localview.useangle = !lowres_turn;
|
||||
// inputs that apply looking up/down (e.g. gamepad).
|
||||
localview.usepitch = true;
|
||||
|
||||
G_DemoSkipTics();
|
||||
|
||||
base = I_BaseTiccmd(); // empty, or external driver
|
||||
memcpy(cmd, base, sizeof *cmd);
|
||||
memcpy(cmd, &basecmd, sizeof(*cmd));
|
||||
memset(&basecmd, 0, sizeof(basecmd));
|
||||
|
||||
cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS];
|
||||
|
||||
strafe = M_InputGameActive(input_strafe);
|
||||
// [FG] speed key inverts autorun
|
||||
speed = autorun ^ M_InputGameActive(input_speed); // phares
|
||||
|
||||
forward = side = 0;
|
||||
|
||||
// use two stage accelerative turning
|
||||
// on the keyboard and joystick
|
||||
if (M_InputGameActive(input_turnleft) ||
|
||||
M_InputGameActive(input_turnright))
|
||||
turnheld += ticdup;
|
||||
else
|
||||
turnheld = 0;
|
||||
|
||||
if (turnheld < SLOWTURNTICS)
|
||||
tspeed = 2; // slow turn
|
||||
else
|
||||
tspeed = speed;
|
||||
// Composite input
|
||||
|
||||
// turn 180 degrees in one keystroke? // phares
|
||||
// |
|
||||
if (STRICTMODE(M_InputGameActive(input_reverse))) // V
|
||||
{
|
||||
cmd->angleturn += (short)QUICKREVERSE; // ^
|
||||
localview.useangle = false;
|
||||
M_InputGameDeactivate(input_reverse); // |
|
||||
} // phares
|
||||
if (STRICTMODE(M_InputGameActive(input_reverse)))
|
||||
{
|
||||
angle += QUICKREVERSE;
|
||||
M_InputGameDeactivate(input_reverse);
|
||||
}
|
||||
|
||||
// let movement keys cancel each other out
|
||||
if (turnleft || turnright)
|
||||
{
|
||||
turnheld += ticdup;
|
||||
|
||||
if (strafe)
|
||||
if (strafe)
|
||||
{
|
||||
if (M_InputGameActive(input_turnright))
|
||||
if (turnright)
|
||||
side += sidemove[speed];
|
||||
if (M_InputGameActive(input_turnleft))
|
||||
if (turnleft)
|
||||
side -= sidemove[speed];
|
||||
|
||||
if (analog_controls && controller_axes[axis_turn])
|
||||
{
|
||||
fixed_t x = axis_move_sens * controller_axes[axis_turn] / 10;
|
||||
x = direction[invert_turn] * x;
|
||||
side += FixedMul(sidemove[speed], x);
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (M_InputGameActive(input_turnright))
|
||||
{
|
||||
cmd->angleturn -= angleturn[tspeed];
|
||||
localview.useangle = false;
|
||||
}
|
||||
if (M_InputGameActive(input_turnleft))
|
||||
{
|
||||
cmd->angleturn += angleturn[tspeed];
|
||||
localview.useangle = false;
|
||||
}
|
||||
// use two stage accelerative turning on the keyboard and joystick
|
||||
const int tspeed = ((turnheld < SLOWTURNTICS) ? 2 : speed);
|
||||
|
||||
if (analog_controls && controller_axes[axis_turn])
|
||||
{
|
||||
fixed_t x = controller_axes[axis_turn];
|
||||
|
||||
// response curve to compensate for lack of near-centered accuracy
|
||||
x = FixedMul(FixedMul(x, x), x);
|
||||
|
||||
x = direction[invert_turn] * axis_turn_sens * x / 10;
|
||||
cmd->angleturn -= FixedMul(angleturn[1], x);
|
||||
localview.useangle = false;
|
||||
}
|
||||
if (turnright)
|
||||
angle -= angleturn[tspeed];
|
||||
if (turnleft)
|
||||
angle += angleturn[tspeed];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
turnheld = 0;
|
||||
}
|
||||
|
||||
if (M_InputGameActive(input_forward))
|
||||
forward += forwardmove[speed];
|
||||
@ -569,14 +545,37 @@ void G_BuildTiccmd(ticcmd_t* cmd)
|
||||
if (M_InputGameActive(input_strafeleft))
|
||||
side -= sidemove[speed];
|
||||
|
||||
// Gamepad
|
||||
|
||||
if (analog_controls)
|
||||
{
|
||||
if (controller_axes[axis_turn])
|
||||
{
|
||||
if (strafe)
|
||||
{
|
||||
fixed_t x = axis_move_sens * controller_axes[axis_turn] / 10;
|
||||
x = direction[invert_turn] * x;
|
||||
side += FixedMul(sidemove[speed], x);
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed_t x = controller_axes[axis_turn];
|
||||
|
||||
// response curve to compensate for lack of near-centered accuracy
|
||||
x = FixedMul(FixedMul(x, x), x);
|
||||
|
||||
x = direction[invert_turn] * axis_turn_sens * x / 10;
|
||||
angle -= FixedMul(angleturn[1], x);
|
||||
}
|
||||
}
|
||||
|
||||
if (controller_axes[axis_forward])
|
||||
{
|
||||
fixed_t y = axis_move_sens * controller_axes[axis_forward] / 10;
|
||||
y = direction[invert_forward] * y;
|
||||
forward -= FixedMul(forwardmove[speed], y);
|
||||
}
|
||||
|
||||
if (controller_axes[axis_strafe])
|
||||
{
|
||||
fixed_t x = axis_move_sens * controller_axes[axis_strafe] / 10;
|
||||
@ -592,12 +591,63 @@ void G_BuildTiccmd(ticcmd_t* cmd)
|
||||
y = FixedMul(FixedMul(y, y), y);
|
||||
|
||||
y = direction[invert_look] * axis_look_sens * y / 10;
|
||||
cmd->lookdir -= FixedMul(lookspeed[0], y);
|
||||
localview.usepitch = false;
|
||||
pitch -= FixedMul(lookspeed[0], y);
|
||||
}
|
||||
}
|
||||
|
||||
// buttons
|
||||
// Mouse
|
||||
|
||||
if (strafe)
|
||||
{
|
||||
const double mouseside = CalcMouseSide(mousex);
|
||||
side += CarryMouseSide(mouseside);
|
||||
}
|
||||
|
||||
if (!mouselook && !novert)
|
||||
{
|
||||
const double mousevert = CalcMouseVert(mousey);
|
||||
forward += CarryMouseVert(mousevert);
|
||||
}
|
||||
|
||||
// Update/reset
|
||||
|
||||
if (angle)
|
||||
{
|
||||
angle = CarryAngle(localview.rawangle + angle);
|
||||
if (lowres_turn)
|
||||
{
|
||||
angle = CarryLowResAngle(angle);
|
||||
}
|
||||
localview.ticangleturn = angle - cmd->angleturn;
|
||||
cmd->angleturn = angle;
|
||||
}
|
||||
|
||||
if (pitch)
|
||||
{
|
||||
cmd->lookdir = pitch;
|
||||
localview.usepitch = false;
|
||||
}
|
||||
|
||||
if (forward > MAXPLMOVE)
|
||||
forward = MAXPLMOVE;
|
||||
else if (forward < -MAXPLMOVE)
|
||||
forward = -MAXPLMOVE;
|
||||
if (side > MAXPLMOVE)
|
||||
side = MAXPLMOVE;
|
||||
else if (side < -MAXPLMOVE)
|
||||
side = -MAXPLMOVE;
|
||||
|
||||
cmd->forwardmove = forward;
|
||||
cmd->sidemove = side;
|
||||
|
||||
mousex = mousey = 0;
|
||||
localview.angle = 0;
|
||||
localview.pitch = 0;
|
||||
localview.rawangle = 0.0;
|
||||
prevcarry = carry;
|
||||
|
||||
// Buttons
|
||||
|
||||
cmd->chatchar = HU_dequeueChatChar();
|
||||
|
||||
if (M_InputGameActive(input_fire))
|
||||
@ -716,33 +766,6 @@ void G_BuildTiccmd(ticcmd_t* cmd)
|
||||
cmd->buttons |= BT_USE;
|
||||
}
|
||||
|
||||
if (strafe)
|
||||
side += CalcMouseStrafe(mousex);
|
||||
else
|
||||
cmd->angleturn -= localview.angle;
|
||||
|
||||
if (mouselook)
|
||||
cmd->lookdir += localview.pitch;
|
||||
else if (!novert)
|
||||
forward += CalcMouseVert(mousey);
|
||||
|
||||
mousex = mousey = 0;
|
||||
localview.angle = 0;
|
||||
localview.pitch = 0;
|
||||
cmd_prev_carry = cmd_carry;
|
||||
|
||||
if (forward > MAXPLMOVE)
|
||||
forward = MAXPLMOVE;
|
||||
else if (forward < -MAXPLMOVE)
|
||||
forward = -MAXPLMOVE;
|
||||
if (side > MAXPLMOVE)
|
||||
side = MAXPLMOVE;
|
||||
else if (side < -MAXPLMOVE)
|
||||
side = -MAXPLMOVE;
|
||||
|
||||
cmd->forwardmove += forward;
|
||||
cmd->sidemove += side;
|
||||
|
||||
// special buttons
|
||||
if (sendpause)
|
||||
{
|
||||
@ -768,26 +791,6 @@ void G_BuildTiccmd(ticcmd_t* cmd)
|
||||
sendjoin = false;
|
||||
cmd->buttons |= BT_JOIN;
|
||||
}
|
||||
|
||||
// low-res turning
|
||||
|
||||
if (lowres_turn)
|
||||
{
|
||||
static signed short carry = 0;
|
||||
signed short desired_angleturn;
|
||||
|
||||
desired_angleturn = cmd->angleturn + carry;
|
||||
|
||||
// round angleturn to the nearest 256 unit boundary
|
||||
// for recording demos with single byte values for turn
|
||||
|
||||
cmd->angleturn = (desired_angleturn + 128) & 0xff00;
|
||||
|
||||
// Carry forward the error from the reduced resolution to the
|
||||
// next tic, so that successive small movements can accumulate.
|
||||
|
||||
carry = desired_angleturn - cmd->angleturn;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@ -898,8 +901,9 @@ static void G_DoLoadLevel(void)
|
||||
memset (gamekeydown, 0, sizeof(gamekeydown));
|
||||
mousex = mousey = 0;
|
||||
memset(&localview, 0, sizeof(localview));
|
||||
memset(&cmd_carry, 0, sizeof(cmd_carry));
|
||||
memset(&cmd_prev_carry, 0, sizeof(cmd_prev_carry));
|
||||
memset(&carry, 0, sizeof(carry));
|
||||
memset(&prevcarry, 0, sizeof(prevcarry));
|
||||
memset(&basecmd, 0, sizeof(basecmd));
|
||||
sendpause = sendsave = paused = false;
|
||||
// [FG] array size!
|
||||
memset (mousearray, 0, sizeof(mousearray));
|
||||
@ -970,7 +974,6 @@ static boolean G_StrictModeSkipEvent(event_t *ev)
|
||||
{
|
||||
first_event = false;
|
||||
enable_mouse = true;
|
||||
skip_mouse = false;
|
||||
}
|
||||
return !enable_mouse;
|
||||
|
||||
@ -991,6 +994,23 @@ static boolean G_StrictModeSkipEvent(event_t *ev)
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean G_MouseMovementResponder(event_t *ev)
|
||||
{
|
||||
if (G_StrictModeSkipEvent(ev))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ev->type == ev_mouse)
|
||||
{
|
||||
mousex += ev->data2;
|
||||
mousey += ev->data3;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// G_Responder
|
||||
// Get info needed to make ticcmd_ts for the players.
|
||||
@ -1105,8 +1125,10 @@ boolean G_Responder(event_t* ev)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (G_StrictModeSkipEvent(ev))
|
||||
if (G_MouseMovementResponder(ev))
|
||||
{
|
||||
return true; // eat events
|
||||
}
|
||||
|
||||
switch (ev->type)
|
||||
{
|
||||
@ -1130,10 +1152,6 @@ boolean G_Responder(event_t* ev)
|
||||
mousebuttons[ev->data1] = false;
|
||||
return true;
|
||||
|
||||
case ev_mouse:
|
||||
G_MouseMovementResponder(ev);
|
||||
return true; // eat events
|
||||
|
||||
case ev_joyb_down:
|
||||
if (ev->data1 < MAX_JSB)
|
||||
joybuttons[ev->data1] = true;
|
||||
|
@ -30,7 +30,8 @@
|
||||
|
||||
#define MBF21_GAME_OPTION_SIZE (21 + MBF21_COMP_TOTAL)
|
||||
|
||||
void G_MouseMovementResponder(const event_t *ev);
|
||||
void G_PrepTiccmd(void);
|
||||
boolean G_MouseMovementResponder(event_t *ev);
|
||||
boolean G_Responder(event_t *ev);
|
||||
boolean G_CheckDemoStatus(void);
|
||||
void G_DeathMatchSpawnPlayer(int playernum);
|
||||
|
@ -403,7 +403,6 @@ void I_ReadMouse(void)
|
||||
int x, y;
|
||||
static event_t ev;
|
||||
|
||||
SDL_PumpEvents();
|
||||
SDL_GetRelativeMouseState(&x, &y);
|
||||
|
||||
if (x != 0 || y != 0)
|
||||
|
@ -45,6 +45,8 @@ void I_StartFrame (void);
|
||||
|
||||
void I_StartTic (void);
|
||||
|
||||
void I_StartDisplay(void);
|
||||
|
||||
// Asynchronous interrupt functions should maintain private queues
|
||||
// that are read by the synchronous functions
|
||||
// to be converted into events.
|
||||
|
@ -418,15 +418,25 @@ static void I_GetEvent(void)
|
||||
//
|
||||
void I_StartTic (void)
|
||||
{
|
||||
I_GetEvent();
|
||||
|
||||
if (window_focused)
|
||||
{
|
||||
I_ReadMouse();
|
||||
}
|
||||
|
||||
I_GetEvent();
|
||||
I_UpdateJoystick();
|
||||
}
|
||||
|
||||
void I_StartDisplay(void)
|
||||
{
|
||||
if (window_focused)
|
||||
{
|
||||
SDL_PumpEvents();
|
||||
I_ReadMouse();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// I_StartFrame
|
||||
//
|
||||
|
@ -3941,6 +3941,7 @@ enum {
|
||||
gen5_mouse3,
|
||||
gen5_mouse_accel,
|
||||
gen5_mouse_accel_threshold,
|
||||
gen5_mouse_raw_input,
|
||||
gen5_end1,
|
||||
|
||||
gen5_title2,
|
||||
@ -4165,6 +4166,9 @@ setup_menu_t gen_settings5[] = { // General Settings screen5
|
||||
{"Mouse threshold", S_NUM, m_null, M_X,
|
||||
M_Y + gen5_mouse_accel_threshold * M_SPC, {"mouse_acceleration_threshold"}},
|
||||
|
||||
{"Raw mouse input", S_YESNO, m_null, M_X,
|
||||
M_Y+ gen5_mouse_raw_input * M_SPC, {"mouse_raw_input"}},
|
||||
|
||||
{"", S_SKIP, m_null, M_X, M_Y + gen5_end1*M_SPC},
|
||||
|
||||
{"Miscellaneous" ,S_SKIP|S_TITLE, m_null, M_X, M_Y + gen5_title2*M_SPC},
|
||||
|
@ -2059,6 +2059,13 @@ default_t defaults[] = {
|
||||
"adjust mouse acceleration threshold"
|
||||
},
|
||||
|
||||
{
|
||||
"mouse_raw_input",
|
||||
(config_t *) &mouse_raw_input, NULL,
|
||||
{1}, {0, 1}, number, ss_none, wad_no,
|
||||
"Raw mouse input for turning/looking (0 = Interpolate, 1 = Raw)"
|
||||
},
|
||||
|
||||
// [FG] invert vertical axis
|
||||
{
|
||||
"mouse_y_invert",
|
||||
|
17
src/p_user.c
17
src/p_user.c
@ -190,6 +190,12 @@ void P_MovePlayer (player_t* player)
|
||||
mo->angle += cmd->angleturn << 16;
|
||||
onground = mo->z <= mo->floorz;
|
||||
|
||||
if (player == &players[consoleplayer])
|
||||
{
|
||||
localview.ticangle += localview.ticangleturn << 16;
|
||||
localview.ticangleturn = 0;
|
||||
}
|
||||
|
||||
// killough 10/98:
|
||||
//
|
||||
// We must apply thrust to the player and bobbing separately, to avoid
|
||||
@ -353,6 +359,11 @@ void P_PlayerThink (player_t* player)
|
||||
player->oldlookdir = player->lookdir;
|
||||
player->oldrecoilpitch = player->recoilpitch;
|
||||
|
||||
if (player == &players[consoleplayer])
|
||||
{
|
||||
localview.oldticangle = localview.ticangle;
|
||||
}
|
||||
|
||||
// killough 2/8/98, 3/21/98:
|
||||
// (this code is necessary despite questions raised elsewhere in a comment)
|
||||
|
||||
@ -386,7 +397,11 @@ void P_PlayerThink (player_t* player)
|
||||
if (abs(player->lookdir) < 8 * MLOOKUNIT)
|
||||
{
|
||||
player->lookdir = 0;
|
||||
player->centering = false;
|
||||
|
||||
if (player->oldlookdir == 0)
|
||||
{
|
||||
player->centering = false;
|
||||
}
|
||||
}
|
||||
|
||||
player->slope = PLAYER_SLOPE(player);
|
||||
|
33
src/r_main.c
33
src/r_main.c
@ -48,6 +48,7 @@ fixed_t projection;
|
||||
fixed_t viewx, viewy, viewz;
|
||||
angle_t viewangle;
|
||||
localview_t localview;
|
||||
boolean mouse_raw_input;
|
||||
fixed_t viewcos, viewsin;
|
||||
player_t *viewplayer;
|
||||
extern lighttable_t **walllights;
|
||||
@ -648,10 +649,12 @@ void R_SetupFrame (player_t *player)
|
||||
leveltime > oldleveltime)
|
||||
{
|
||||
const boolean use_localview = (
|
||||
// Don't use localview when interpolation is preferred.
|
||||
mouse_raw_input &&
|
||||
// Don't use localview if the player is spying.
|
||||
player == &players[consoleplayer] &&
|
||||
// Don't use localview if the player is dead.
|
||||
player->health > 0 &&
|
||||
player->playerstate != PST_DEAD &&
|
||||
// Don't use localview if the player just teleported.
|
||||
!player->mo->reactiontime &&
|
||||
// Don't use localview if a demo is playing.
|
||||
@ -667,12 +670,16 @@ void R_SetupFrame (player_t *player)
|
||||
|
||||
// Use localview unless the player or game is in an invalid state or if
|
||||
// mouse input was interrupted, in which case fall back to interpolation.
|
||||
if (localview.useangle && use_localview)
|
||||
viewangle = player->mo->angle - ((short)localview.angle << FRACBITS) + viewangleoffset;
|
||||
if (use_localview)
|
||||
{
|
||||
viewangle = (player->mo->angle + localview.angle - localview.ticangle +
|
||||
R_InterpolateAngle(localview.oldticangle, localview.ticangle,
|
||||
fractionaltic));
|
||||
}
|
||||
else
|
||||
viewangle = R_InterpolateAngle(player->mo->oldangle, player->mo->angle, fractionaltic) + viewangleoffset;
|
||||
viewangle = R_InterpolateAngle(player->mo->oldangle, player->mo->angle, fractionaltic);
|
||||
|
||||
if (localview.usepitch && use_localview && !player->centering && player->lookdir)
|
||||
if (localview.usepitch && use_localview && !player->centering)
|
||||
pitch = (player->lookdir + localview.pitch) / MLOOKUNIT;
|
||||
else
|
||||
pitch = (player->oldlookdir + (player->lookdir - player->oldlookdir) * FIXED2DOUBLE(fractionaltic)) / MLOOKUNIT;
|
||||
@ -682,13 +689,17 @@ void R_SetupFrame (player_t *player)
|
||||
}
|
||||
else
|
||||
{
|
||||
viewx = player->mo->x;
|
||||
viewy = player->mo->y;
|
||||
viewz = player->viewz; // [FG] moved here
|
||||
viewangle = player->mo->angle + viewangleoffset;
|
||||
// [crispy] pitch is actual lookdir and weapon pitch
|
||||
pitch = player->lookdir / MLOOKUNIT + player->recoilpitch;
|
||||
viewx = player->mo->x;
|
||||
viewy = player->mo->y;
|
||||
viewz = player->viewz; // [FG] moved here
|
||||
viewangle = player->mo->angle;
|
||||
// [crispy] pitch is actual lookdir and weapon pitch
|
||||
pitch = player->lookdir / MLOOKUNIT + player->recoilpitch;
|
||||
}
|
||||
|
||||
// 3-screen display mode.
|
||||
viewangle += viewangleoffset;
|
||||
|
||||
extralight = player->extralight;
|
||||
extralight += STRICTMODE(LIGHTBRIGHT * extra_level_brightness);
|
||||
|
||||
|
@ -81,6 +81,8 @@ extern lighttable_t *fixedcolormap;
|
||||
// range of [0.0, 1.0). Used for interpolation.
|
||||
extern fixed_t fractionaltic;
|
||||
|
||||
extern boolean mouse_raw_input;
|
||||
|
||||
// [AM] Interpolate between two angles.
|
||||
angle_t R_InterpolateAngle(angle_t oangle, angle_t nangle, fixed_t scale);
|
||||
|
||||
|
@ -90,8 +90,11 @@ extern side_t *sides;
|
||||
|
||||
typedef struct localview_s
|
||||
{
|
||||
boolean useangle;
|
||||
boolean usepitch;
|
||||
angle_t oldticangle;
|
||||
angle_t ticangle;
|
||||
int ticangleturn;
|
||||
double rawangle;
|
||||
int angle;
|
||||
int pitch;
|
||||
} localview_t;
|
||||
|
Loading…
x
Reference in New Issue
Block a user