diff --git a/src/d_main.c b/src/d_main.c index ba884f7f..885e61dd 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -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(); } } diff --git a/src/g_game.c b/src/g_game.c index f3c8554f..08492a19 100644 --- a/src/g_game.c +++ b/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; diff --git a/src/g_game.h b/src/g_game.h index 84e46892..f28529fd 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -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); diff --git a/src/i_input.c b/src/i_input.c index 2a7a4012..1ee33e62 100644 --- a/src/i_input.c +++ b/src/i_input.c @@ -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) diff --git a/src/i_system.h b/src/i_system.h index 0dbd1412..3057a340 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -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. diff --git a/src/i_video.c b/src/i_video.c index 44b3dbf5..40ca2467 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -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 // diff --git a/src/m_menu.c b/src/m_menu.c index 6e128f6c..348610a2 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -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}, diff --git a/src/m_misc.c b/src/m_misc.c index d8114609..fd1da7e0 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -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", diff --git a/src/p_user.c b/src/p_user.c index fba3c56e..06e9c889 100644 --- a/src/p_user.c +++ b/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); diff --git a/src/r_main.c b/src/r_main.c index 2efd3f86..45ce5c9e 100644 --- a/src/r_main.c +++ b/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); diff --git a/src/r_main.h b/src/r_main.h index 20264e9a..6a127223 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -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); diff --git a/src/r_state.h b/src/r_state.h index 4c0401d3..6c14ec3e 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -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;