From b625076c8789d0692f5ae721396914766e577255 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sun, 6 Oct 2019 17:40:52 -0500 Subject: [PATCH 001/137] Implement interpolation at the renderer level Instead of interpolating thinkers, we interpolate mobjs inside the renderer. Further interpolation is TBI. --- src/Makefile.d/versions.mk | 2 +- src/Sourcefile | 1 + src/android/i_system.c | 6 ++ src/d_clisrv.c | 1 + src/d_main.c | 21 ++++- src/d_main.h | 1 + src/dummy/i_system.c | 2 +- src/g_game.c | 10 +- src/hardware/hw_main.c | 72 ++++++++++++--- src/i_system.h | 4 + src/p_mobj.c | 25 +++++ src/p_mobj.h | 2 + src/p_tick.c | 1 + src/r_fps.c | 169 ++++++++++++++++++++++++++++++++++ src/r_fps.h | 59 ++++++++++++ src/r_main.c | 182 +++++++++++++++++-------------------- src/r_main.h | 6 ++ src/r_things.c | 83 +++++++++++++---- src/sdl/i_system.c | 27 ++++-- src/win32/win_sys.c | 6 ++ 20 files changed, 537 insertions(+), 143 deletions(-) create mode 100644 src/r_fps.c create mode 100644 src/r_fps.h diff --git a/src/Makefile.d/versions.mk b/src/Makefile.d/versions.mk index f0b59658e..d2877b374 100644 --- a/src/Makefile.d/versions.mk +++ b/src/Makefile.d/versions.mk @@ -156,7 +156,7 @@ ifdef DEBUGMODE ifdef GCC48 opts+=-Og else -opts+=O0 +opts+=-O0 endif endif diff --git a/src/Sourcefile b/src/Sourcefile index 983dadaf0..ef9fbdc13 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -55,6 +55,7 @@ tables.c r_bsp.c r_data.c r_draw.c +r_fps.c r_main.c r_plane.c r_segs.c diff --git a/src/android/i_system.c b/src/android/i_system.c index 752e9f6c6..7256bac34 100644 --- a/src/android/i_system.c +++ b/src/android/i_system.c @@ -88,6 +88,12 @@ tic_t I_GetTime(void) return (since_start*TICRATE)/1000000; } +fixed_t I_GetTimeFrac(void) +{ + //stub + return 0; +} + void I_Sleep(void){} void I_GetEvent(void){} diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ac8bba608..70e283bba 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5270,6 +5270,7 @@ void TryRunTics(tic_t realtics) boolean update_stats = !(paused || P_AutoPause()); DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); + prev_tics = I_GetTime(); if (update_stats) PS_START_TIMING(ps_tictime); diff --git a/src/d_main.c b/src/d_main.c index fa9e21337..0281ef86c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -64,6 +64,7 @@ #include "deh_tables.h" // Dehacked list test #include "m_cond.h" // condition initialization #include "fastcmp.h" +#include "r_fps.h" // Frame interpolation/uncapped #include "keys.h" #include "filesrch.h" // refreshdirmenu #include "g_input.h" // tutorial mode control scheming @@ -147,6 +148,7 @@ event_t events[MAXEVENTS]; INT32 eventhead, eventtail; boolean dedicated = false; +boolean tic_happened = false; // Frame interpolation/uncapped // // D_PostEvent @@ -764,7 +766,7 @@ void D_SRB2Loop(void) debugload--; #endif - if (!realtics && !singletics) + if (!realtics && !singletics && cv_frameinterpolation.value != 1) { I_Sleep(); continue; @@ -780,15 +782,27 @@ void D_SRB2Loop(void) realtics = 1; // process tics (but maybe not if realtic == 0) + tic_happened = realtics ? true : false; TryRunTics(realtics); + if (cv_frameinterpolation.value == 1) + rendertimefrac = I_GetTimeFrac(); + else + rendertimefrac = FRACUNIT; + + if (cv_frameinterpolation.value == 1) + { + D_Display(); + } + if (lastdraw || singletics || gametic > rendergametic) { rendergametic = gametic; rendertimeout = entertic+TICRATE/17; // Update display, next frame, with current state. - D_Display(); + // (Only display if not already done for frame interp) + cv_frameinterpolation.value == 0 ? D_Display() : 0; if (moviemode) M_SaveFrame(); @@ -805,7 +819,8 @@ void D_SRB2Loop(void) if (camera.chase) P_MoveChaseCamera(&players[displayplayer], &camera, false); } - D_Display(); + // (Only display if not already done for frame interp) + cv_frameinterpolation.value == 0 ? D_Display() : 0; if (moviemode) M_SaveFrame(); diff --git a/src/d_main.h b/src/d_main.h index 8189a9f2b..a06334b6e 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -26,6 +26,7 @@ extern char srb2home[256]; //Alam: My Home extern boolean usehome; //Alam: which path? extern const char *pandf; //Alam: how to path? extern char srb2path[256]; //Alam: SRB2's Home +extern boolean tic_happened; // Frame interpolation/uncapped // the infinite loop of D_SRB2Loop() called from win_main for windows version void D_SRB2Loop(void) FUNCNORETURN; diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c index 4a657ed19..f3d0bc5e8 100644 --- a/src/dummy/i_system.c +++ b/src/dummy/i_system.c @@ -16,7 +16,7 @@ tic_t I_GetTime(void) return 0; } -int I_GetTimeMicros(void) +fixed_t I_GetTimeFrac(void) { return 0; } diff --git a/src/g_game.c b/src/g_game.c index 39d003056..fb1c0d522 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -46,6 +46,7 @@ #include "b_bot.h" #include "m_cond.h" // condition sets #include "lua_script.h" +#include "r_fps.h" // frame interpolation/uncapped #include "lua_hud.h" @@ -2362,6 +2363,8 @@ void G_Ticker(boolean run) F_TextPromptTicker(); AM_Ticker(); HU_Ticker(); + R_UpdateViewInterpolation(); + break; case GS_INTERMISSION: @@ -2414,7 +2417,12 @@ void G_Ticker(boolean run) break; case GS_TITLESCREEN: - if (titlemapinaction) P_Ticker(run); // then intentionally fall through + if (titlemapinaction) + { + P_Ticker(run); + R_UpdateViewInterpolation(); + // then intentionally fall through + } /* FALLTHRU */ case GS_WAITINGPLAYERS: F_MenuPresTicker(run); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index fd8a23013..968ebc54e 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -38,6 +38,7 @@ #include "../m_cheat.h" #include "../f_finale.h" #include "../r_things.h" // R_GetShadowZ +#include "../d_main.h" #include "../p_slopes.h" #include "hw_md2.h" @@ -5050,6 +5051,12 @@ static void HWR_ProjectSprite(mobj_t *thing) INT32 rollangle = 0; #endif + // uncapped/interpolation + fixed_t interpx; + fixed_t interpy; + fixed_t interpz; + angle_t interpangle; + if (!thing) return; @@ -5071,13 +5078,26 @@ static void HWR_ProjectSprite(mobj_t *thing) dispoffset = thing->info->dispoffset; + interpx = thing->x; + interpy = thing->y; + interpz = thing->z; + interpangle = mobjangle; + + if (cv_frameinterpolation.value == 1 && !paused) + { + interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); + interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); + interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); + interpangle = mobjangle; + } + this_scale = FIXED_TO_FLOAT(thing->scale); spritexscale = FIXED_TO_FLOAT(thing->spritexscale); spriteyscale = FIXED_TO_FLOAT(thing->spriteyscale); // transform the origin point - tr_x = FIXED_TO_FLOAT(thing->x) - gl_viewx; - tr_y = FIXED_TO_FLOAT(thing->y) - gl_viewy; + tr_x = FIXED_TO_FLOAT(interpx) - gl_viewx; + tr_y = FIXED_TO_FLOAT(interpy) - gl_viewy; // rotation around vertical axis tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin); @@ -5100,8 +5120,8 @@ static void HWR_ProjectSprite(mobj_t *thing) } // The above can stay as it works for cutting sprites that are too close - tr_x = FIXED_TO_FLOAT(thing->x); - tr_y = FIXED_TO_FLOAT(thing->y); + tr_x = FIXED_TO_FLOAT(interpx); + tr_y = FIXED_TO_FLOAT(interpy); // decide which patch to use for sprite relative to player #ifdef RANGECHECK @@ -5149,7 +5169,7 @@ static void HWR_ProjectSprite(mobj_t *thing) I_Error("sprframes NULL for sprite %d\n", thing->sprite); #endif - ang = R_PointToAngle (thing->x, thing->y) - mobjangle; + ang = R_PointToAngle (interpx, interpy) - interpangle; if (mirrored) ang = InvAngle(ang); @@ -5295,12 +5315,12 @@ static void HWR_ProjectSprite(mobj_t *thing) if (vflip) { - gz = FIXED_TO_FLOAT(thing->z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gz = FIXED_TO_FLOAT(interpz + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale); } else { - gzt = FIXED_TO_FLOAT(thing->z) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gzt = FIXED_TO_FLOAT(interpz) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); gz = gzt - (FIXED_TO_FLOAT(spr_height) * this_yscale); } @@ -5461,6 +5481,9 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) unsigned rot = 0; UINT8 flip; + if (!thing) + return; + // Visibility check by the blend mode. if (thing->frame & FF_TRANSMASK) { @@ -5468,9 +5491,22 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) return; } + // uncapped/interpolation + fixed_t interpx = thing->x; + fixed_t interpy = thing->y; + fixed_t interpz = thing->z; + + // do interpolation + if (cv_frameinterpolation.value == 1 && !paused) + { + interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); + interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); + interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); + } + // transform the origin point - tr_x = FIXED_TO_FLOAT(thing->x) - gl_viewx; - tr_y = FIXED_TO_FLOAT(thing->y) - gl_viewy; + tr_x = FIXED_TO_FLOAT(interpx) - gl_viewx; + tr_y = FIXED_TO_FLOAT(interpy) - gl_viewy; // rotation around vertical axis tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin); @@ -5479,8 +5515,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) if (tz < ZCLIP_PLANE) return; - tr_x = FIXED_TO_FLOAT(thing->x); - tr_y = FIXED_TO_FLOAT(thing->y); + tr_x = FIXED_TO_FLOAT(interpx); + tr_y = FIXED_TO_FLOAT(interpy); // decide which patch to use for sprite relative to player if ((unsigned)thing->sprite >= numsprites) @@ -5542,7 +5578,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->colormap = NULL; // set top/bottom coords - vis->gzt = FIXED_TO_FLOAT(thing->z + spritecachedinfo[lumpoff].topoffset); + vis->gzt = FIXED_TO_FLOAT(interpz + spritecachedinfo[lumpoff].topoffset); vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height); vis->precip = true; @@ -6678,6 +6714,8 @@ void HWR_DoPostProcessor(player_t *player) // 10 by 10 grid. 2 coordinates (xy) float v[SCREENVERTS][SCREENVERTS][2]; static double disStart = 0; + static float last_fractime = 0; + UINT8 x, y; INT32 WAVELENGTH; INT32 AMPLITUDE; @@ -6709,6 +6747,16 @@ void HWR_DoPostProcessor(player_t *player) HWD.pfnPostImgRedraw(v); if (!(paused || P_AutoPause())) disStart += 1; + fixed_t fractime = I_GetTimeFrac(); + if (tic_happened) + { + disStart = disStart - last_fractime + 1 + FIXED_TO_FLOAT(fractime); + } + else + { + disStart = disStart - last_fractime + FIXED_TO_FLOAT(fractime); + } + last_fractime = fractime; // Capture the screen again for screen waving on the intermission if(gamestate != GS_INTERMISSION) diff --git a/src/i_system.h b/src/i_system.h index 27fcdeb3f..0cdc7db85 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -46,6 +46,10 @@ UINT32 I_GetFreeMem(UINT32 *total); */ tic_t I_GetTime(void); +/** \brief Get the current time as a fraction of a tic since the last tic. +*/ +fixed_t I_GetTimeFrac(void); + /** \brief Returns precise time value for performance measurement. */ precise_t I_GetPreciseTime(void); diff --git a/src/p_mobj.c b/src/p_mobj.c index e88cd4b9f..b52b9734f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4027,6 +4027,11 @@ void P_NullPrecipThinker(precipmobj_t *mobj) void P_SnowThinker(precipmobj_t *mobj) { + // reset old state (for interpolation) + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; + P_CycleStateAnimation((mobj_t *)mobj); // adjust height @@ -4036,6 +4041,11 @@ void P_SnowThinker(precipmobj_t *mobj) void P_RainThinker(precipmobj_t *mobj) { + // reset old state (for interpolation) + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; + P_CycleStateAnimation((mobj_t *)mobj); if (mobj->state != &states[S_RAIN1]) @@ -10032,6 +10042,11 @@ void P_MobjThinker(mobj_t *mobj) I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); + // Set old position (for interpolation) + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; + if (mobj->flags & MF_NOTHINK) return; @@ -10897,6 +10912,11 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if (CheckForReverseGravity && !(mobj->flags & MF_NOBLOCKMAP)) P_CheckGravity(mobj, false); + // set old state too (for interpolation) + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; + return mobj; } @@ -10944,6 +10964,11 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype || mobj->subsector->sector->floorpic == skyflatnum) mobj->precipflags |= PCF_PIT; + // set initial old positions (for interpolation) + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; + return mobj; } diff --git a/src/p_mobj.h b/src/p_mobj.h index b1b79fd82..998baa19e 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -281,6 +281,7 @@ typedef struct mobj_s // Info for drawing: position. fixed_t x, y, z; + fixed_t old_x, old_y, old_z; // position interpolation // More list: links in sector (if needed) struct mobj_s *snext; @@ -408,6 +409,7 @@ typedef struct precipmobj_s // Info for drawing: position. fixed_t x, y, z; + fixed_t old_x, old_y, old_z; // position interpolation // More list: links in sector (if needed) struct precipmobj_s *snext; diff --git a/src/p_tick.c b/src/p_tick.c index 28ace9288..ca70fb926 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -23,6 +23,7 @@ #include "lua_hook.h" #include "m_perfstats.h" #include "i_system.h" // I_GetPreciseTime +#include "r_fps.h" // Object place #include "m_cheat.h" diff --git a/src/r_fps.c b/src/r_fps.c new file mode 100644 index 000000000..519288bab --- /dev/null +++ b/src/r_fps.c @@ -0,0 +1,169 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2000 by Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko (prboom) +// Copyright (C) 1999-2019 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_fps.h +/// \brief Uncapped framerate stuff. + +#include "r_fps.h" + +#include "r_main.h" +#include "g_game.h" +#include "i_video.h" +#include "r_plane.h" +#include "p_spec.h" +#include "r_state.h" +#ifdef HWRENDER +#include "hardware/hw_main.h" // for cv_glshearing +#endif + +static viewvars_t p1view_old; +static viewvars_t p1view_new; +static viewvars_t p2view_old; +static viewvars_t p2view_new; +static viewvars_t sky1view_old; +static viewvars_t sky1view_new; +static viewvars_t sky2view_old; +static viewvars_t sky2view_new; + +static viewvars_t *oldview = &p1view_old; +viewvars_t *newview = &p1view_new; + + +enum viewcontext_e viewcontext = VIEWCONTEXT_PLAYER1; + +// recalc necessary stuff for mouseaiming +// slopes are already calculated for the full possible view (which is 4*viewheight). +// 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) +static void R_SetupFreelook(player_t *player, boolean skybox) +{ +#ifndef HWRENDER + (void)player; + (void)skybox; +#endif + + // clip it in the case we are looking a hardware 90 degrees full aiming + // (lmps, network and use F12...) + if (rendermode == render_soft +#ifdef HWRENDER + || (rendermode == render_opengl + && (cv_glshearing.value == 1 + || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))) +#endif + ) + { + G_SoftwareClipAimingPitch((INT32 *)&aimingangle); + } + + centeryfrac = (viewheight/2)<x + R_LerpFixed(oldview->x, newview->x, frac); + viewy = oldview->y + R_LerpFixed(oldview->y, newview->y, frac); + viewz = oldview->z + R_LerpFixed(oldview->z, newview->z, frac); + + viewangle = oldview->angle + R_LerpAngle(oldview->angle, newview->angle, frac); + aimingangle = oldview->aim + R_LerpAngle(oldview->aim, newview->aim, frac); + + viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); + viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); + + // this is gonna create some interesting visual errors for long distance teleports... + // might want to recalculate the view sector every frame instead... + if (frac >= FRACUNIT) + { + viewplayer = newview->player; + viewsector = newview->sector; + } + else + { + viewplayer = oldview->player; + viewsector = oldview->sector; + } + + // well, this ain't pretty + if (newview == &sky1view_new || newview == &sky2view_new) + { + skybox = 1; + } + + R_SetupFreelook(newview->player, skybox); +} + +void R_UpdateViewInterpolation(void) +{ + p1view_old = p1view_new; + p2view_old = p2view_new; + sky1view_old = sky1view_new; + sky2view_old = sky2view_new; +} + +void R_SetViewContext(enum viewcontext_e _viewcontext) +{ + I_Assert(_viewcontext == VIEWCONTEXT_PLAYER1 + || _viewcontext == VIEWCONTEXT_PLAYER2 + || _viewcontext == VIEWCONTEXT_SKY1 + || _viewcontext == VIEWCONTEXT_SKY2); + viewcontext = _viewcontext; + + switch (viewcontext) + { + case VIEWCONTEXT_PLAYER1: + oldview = &p1view_old; + newview = &p1view_new; + break; + case VIEWCONTEXT_PLAYER2: + oldview = &p2view_old; + newview = &p2view_new; + break; + case VIEWCONTEXT_SKY1: + oldview = &sky1view_old; + newview = &sky1view_new; + break; + case VIEWCONTEXT_SKY2: + oldview = &sky2view_old; + newview = &sky2view_new; + break; + default: + I_Error("viewcontext value is invalid: we should never get here without an assert!!"); + break; + } +} + +fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac) +{ + return FixedMul(frac, to - from); +} + +INT32 R_LerpInt32(INT32 from, INT32 to, fixed_t frac) +{ + return FixedInt(FixedMul(frac, (to*FRACUNIT) - (from*FRACUNIT))); +} + +angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac) +{ + return FixedMul(frac, to - from); +} diff --git a/src/r_fps.h b/src/r_fps.h new file mode 100644 index 000000000..f9ee6f0de --- /dev/null +++ b/src/r_fps.h @@ -0,0 +1,59 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2000 by Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko (prboom) +// Copyright (C) 1999-2019 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_fps.h +/// \brief Uncapped framerate stuff. + +#ifndef __R_FPS_H__ +#define __R_FPS_H__ + +#include "m_fixed.h" +#include "p_local.h" +#include "r_state.h" + +enum viewcontext_e +{ + VIEWCONTEXT_PLAYER1 = 0, + VIEWCONTEXT_PLAYER2, + VIEWCONTEXT_SKY1, + VIEWCONTEXT_SKY2 +}; + +typedef struct { + fixed_t x; + fixed_t y; + fixed_t z; + boolean sky; + sector_t *sector; + player_t *player; + + angle_t angle; + angle_t aim; + fixed_t cos; + fixed_t sin; + mobj_t *mobj; +} viewvars_t; + +extern viewvars_t *newview; + +// Interpolates the current view variables (r_state.h) against the selected view context in R_SetViewContext +void R_InterpolateView(fixed_t frac); +// Buffer the current new views into the old views. Call once after each real tic. +void R_UpdateViewInterpolation(void); +// Set the current view context (the viewvars pointed to by newview) +void R_SetViewContext(enum viewcontext_e _viewcontext); + +fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac); +INT32 R_LerpInt32(INT32 from, INT32 to, fixed_t frac); +UINT32 R_LerpUInt32(UINT32 from, UINT32 to, fixed_t frac); +angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac); + +#endif diff --git a/src/r_main.c b/src/r_main.c index 13d2413fa..fe5daa00b 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -35,6 +35,7 @@ #include "r_portal.h" #include "r_main.h" #include "i_system.h" // I_GetPreciseTime +#include "r_fps.h" // Frame interpolation/uncapped #ifdef HWRENDER #include "hardware/hw_main.h" @@ -75,6 +76,8 @@ sector_t *viewsector; player_t *viewplayer; mobj_t *r_viewmobj; +fixed_t rendertimefrac; + // // precalculated math tables // @@ -96,6 +99,9 @@ lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE]; lighttable_t *scalelightfixed[MAXLIGHTSCALE]; lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; +// Frame interpolation/uncapped +tic_t prev_tics; + // Hack to support extra boom colormaps. extracolormap_t *extra_colormaps = NULL; @@ -164,6 +170,9 @@ consvar_t cv_drawdist_precip = CVAR_INIT ("drawdist_precip", "1024", CV_SAVE, dr //consvar_t cv_precipdensity = CVAR_INIT ("precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL); consvar_t cv_fov = CVAR_INIT ("fov", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange); +// Frame interpolation/uncapped +consvar_t cv_frameinterpolation = {"frameinterpolation", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + // Okay, whoever said homremoval causes a performance hit should be shot. consvar_t cv_homremoval = CVAR_INIT ("homremoval", "No", CV_SAVE, homremoval_cons_t, NULL); @@ -1084,41 +1093,6 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y) // // R_SetupFrame // - -// recalc necessary stuff for mouseaiming -// slopes are already calculated for the full possible view (which is 4*viewheight). -// 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) -static void R_SetupFreelook(player_t *player, boolean skybox) -{ -#ifndef HWRENDER - (void)player; - (void)skybox; -#endif - - // clip it in the case we are looking a hardware 90 degrees full aiming - // (lmps, network and use F12...) - if (rendermode == render_soft -#ifdef HWRENDER - || (rendermode == render_opengl - && (cv_glshearing.value == 1 - || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))) -#endif - ) - { - G_SoftwareClipAimingPitch((INT32 *)&aimingangle); - } - - centeryfrac = (viewheight/2)<climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode) @@ -1149,81 +1125,83 @@ void R_SetupFrame(player_t *player) else if (!chasecam) thiscam->chase = false; + newview->sky = false; + if (player->awayviewtics) { // cut-away view stuff r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN I_Assert(r_viewmobj != NULL); - viewz = r_viewmobj->z + 20*FRACUNIT; - aimingangle = player->awayviewaiming; - viewangle = r_viewmobj->angle; + newview->z = r_viewmobj->z + 20*FRACUNIT; + newview->aim = player->awayviewaiming; + newview->angle = r_viewmobj->angle; } else if (!player->spectator && chasecam) // use outside cam view { r_viewmobj = NULL; - viewz = thiscam->z + (thiscam->height>>1); - aimingangle = thiscam->aiming; - viewangle = thiscam->angle; + newview->z = thiscam->z + (thiscam->height>>1); + newview->aim = thiscam->aiming; + newview->angle = thiscam->angle; } else // use the player's eyes view { - viewz = player->viewz; + newview->z = player->viewz; r_viewmobj = player->mo; I_Assert(r_viewmobj != NULL); - aimingangle = player->aiming; - viewangle = r_viewmobj->angle; + newview->aim = player->aiming; + newview->angle = r_viewmobj->angle; if (!demoplayback && player->playerstate != PST_DEAD) { if (player == &players[consoleplayer]) { - viewangle = localangle; // WARNING: camera uses this - aimingangle = localaiming; + newview->angle = localangle; // WARNING: camera uses this + newview->aim = localaiming; } else if (player == &players[secondarydisplayplayer]) { - viewangle = localangle2; - aimingangle = localaiming2; + newview->angle = localangle2; + newview->aim = localaiming2; } } } - viewz += quake.z; + newview->z += quake.z; - viewplayer = player; + newview->player = player; if (chasecam && !player->awayviewtics && !player->spectator) { - viewx = thiscam->x; - viewy = thiscam->y; - viewx += quake.x; - viewy += quake.y; + newview->x = thiscam->x; + newview->y = thiscam->y; + newview->x += quake.x; + newview->y += quake.y; if (thiscam->subsector) - viewsector = thiscam->subsector->sector; + newview->sector = thiscam->subsector->sector; else - viewsector = R_PointInSubsector(viewx, viewy)->sector; + newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; } else { - viewx = r_viewmobj->x; - viewy = r_viewmobj->y; - viewx += quake.x; - viewy += quake.y; + newview->x = r_viewmobj->x; + newview->y = r_viewmobj->y; + newview->x += quake.x; + newview->y += quake.y; if (r_viewmobj->subsector) - viewsector = r_viewmobj->subsector->sector; + newview->sector = r_viewmobj->subsector->sector; else - viewsector = R_PointInSubsector(viewx, viewy)->sector; + newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; } - viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); - viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); + // newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT); + // newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - R_SetupFreelook(player, false); + R_InterpolateView(cv_frameinterpolation.value == 1 ? rendertimefrac : FRACUNIT); } void R_SkyboxFrame(player_t *player) @@ -1232,11 +1210,18 @@ void R_SkyboxFrame(player_t *player) if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer]) + { thiscam = &camera2; + R_SetViewContext(VIEWCONTEXT_SKY2); + } else + { thiscam = &camera; + R_SetViewContext(VIEWCONTEXT_SKY1); + } // cut-away view stuff + newview->sky = true; r_viewmobj = skyboxmo[0]; #ifdef PARANOIA if (!r_viewmobj) @@ -1247,39 +1232,39 @@ void R_SkyboxFrame(player_t *player) #endif if (player->awayviewtics) { - aimingangle = player->awayviewaiming; - viewangle = player->awayviewmobj->angle; + newview->aim = player->awayviewaiming; + newview->angle = player->awayviewmobj->angle; } else if (thiscam->chase) { - aimingangle = thiscam->aiming; - viewangle = thiscam->angle; + newview->aim = thiscam->aiming; + newview->angle = thiscam->angle; } else { - aimingangle = player->aiming; - viewangle = player->mo->angle; + newview->aim = player->aiming; + newview->angle = player->mo->angle; if (!demoplayback && player->playerstate != PST_DEAD) { if (player == &players[consoleplayer]) { - viewangle = localangle; // WARNING: camera uses this - aimingangle = localaiming; + newview->angle = localangle; // WARNING: camera uses this + newview->aim = localaiming; } else if (player == &players[secondarydisplayplayer]) { - viewangle = localangle2; - aimingangle = localaiming2; + newview->angle = localangle2; + newview->aim = localaiming2; } } } - viewangle += r_viewmobj->angle; + newview->angle += r_viewmobj->angle; - viewplayer = player; + newview->player = player; - viewx = r_viewmobj->x; - viewy = r_viewmobj->y; - viewz = r_viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle! + newview->x = r_viewmobj->x; + newview->y = r_viewmobj->y; + newview->z = r_viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle! if (mapheaderinfo[gamemap-1]) { @@ -1321,46 +1306,46 @@ void R_SkyboxFrame(player_t *player) if (r_viewmobj->angle == 0) { - viewx += x; - viewy += y; + newview->x += x; + newview->y += y; } else if (r_viewmobj->angle == ANGLE_90) { - viewx -= y; - viewy += x; + newview->x -= y; + newview->y += x; } else if (r_viewmobj->angle == ANGLE_180) { - viewx -= x; - viewy -= y; + newview->x -= x; + newview->y -= y; } else if (r_viewmobj->angle == ANGLE_270) { - viewx += y; - viewy -= x; + newview->x += y; + newview->y -= x; } else { angle_t ang = r_viewmobj->angle>>ANGLETOFINESHIFT; - viewx += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang)); - viewy += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang)); + newview->x += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang)); + newview->y += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang)); } } if (mh->skybox_scalez > 0) - viewz += campos.z / mh->skybox_scalez; + newview->z += campos.z / mh->skybox_scalez; else if (mh->skybox_scalez < 0) - viewz += campos.z * -mh->skybox_scalez; + newview->z += campos.z * -mh->skybox_scalez; } if (r_viewmobj->subsector) - viewsector = r_viewmobj->subsector->sector; + newview->sector = r_viewmobj->subsector->sector; else - viewsector = R_PointInSubsector(viewx, viewy)->sector; + newview->sector = R_PointInSubsector(newview->x, newview->y)->sector; - viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); - viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); + // newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT); + // newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - R_SetupFreelook(player, true); + R_InterpolateView(cv_frameinterpolation.value == 1 ? rendertimefrac : FRACUNIT); } boolean R_ViewpointHasChasecam(player_t *player) @@ -1642,4 +1627,7 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_maxportals); CV_RegisterVar(&cv_movebob); + + // Frame interpolation/uncapped + CV_RegisterVar(&cv_frameinterpolation); } diff --git a/src/r_main.h b/src/r_main.h index c0edb31b3..860bfa920 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -35,6 +35,8 @@ extern fixed_t fovtan; extern size_t validcount, linecount, loopcount, framecount; +extern fixed_t rendertimefrac; + // // Lighting LUT. // Used for z-depth cuing per column/row, @@ -114,6 +116,10 @@ extern consvar_t cv_fov; extern consvar_t cv_skybox; extern consvar_t cv_tailspickup; +// Frame interpolation (uncapped framerate) +extern tic_t prev_tics; +extern consvar_t cv_frameinterpolation; + // Called by startup code. void R_Init(void); diff --git a/src/r_things.c b/src/r_things.c index db4263a6a..55e84d6b7 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1480,9 +1480,34 @@ static void R_ProjectSprite(mobj_t *thing) INT32 rollangle = 0; #endif + // uncapped/interpolation + fixed_t interpx = thing->x; + fixed_t interpy = thing->y; + fixed_t interpz = thing->z; + angle_t interpangle = thing->angle; + + // use player drawangle if player + if (thing->player) interpangle = thing->player->drawangle; + + // do interpolation + if (cv_frameinterpolation.value == 1 && !paused) + { + interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); + interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); + interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); + if (thing->player) + { + interpangle = thing->player->drawangle; + } + else + { + interpangle = thing->angle; + } + } + // transform the origin point - tr_x = thing->x - viewx; - tr_y = thing->y - viewy; + tr_x = interpx - viewx; + tr_y = interpy - viewy; basetz = tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance @@ -1559,7 +1584,7 @@ static void R_ProjectSprite(mobj_t *thing) if (sprframe->rotate != SRF_SINGLE || papersprite) { - ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle); + ang = R_PointToAngle (interpx, interpy) - interpangle; if (mirrored) ang = InvAngle(ang); } @@ -1574,7 +1599,7 @@ static void R_ProjectSprite(mobj_t *thing) else { // choose a different rotation based on player view - //ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + //ang = R_PointToAngle (interpx, interpy) - interpangle; if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right rot = 6; // F7 slot @@ -1791,12 +1816,17 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t linkscale; thing = thing->tracer; + if (cv_frameinterpolation.value == 1 && !paused) + { + interpx = thing->old_x + FixedMul(thing->x - thing->old_x, rendertimefrac); + interpy = thing->old_y + FixedMul(thing->y - thing->old_y, rendertimefrac); + } if (! R_ThingVisible(thing)) return; - tr_x = (thing->x + sort_x) - viewx; - tr_y = (thing->y + sort_y) - viewy; + tr_x = (interpx + sort_x) - viewx; + tr_y = (interpy + sort_y) - viewy; tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); linkscale = FixedDiv(projectiony, tz); @@ -1832,7 +1862,7 @@ static void R_ProjectSprite(mobj_t *thing) if (x2 < portalclipstart || x1 >= portalclipend) return; - if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0) + if (P_PointOnLineSide(interpx, interpy, portalclipline) != 0) return; } @@ -1921,12 +1951,12 @@ static void R_ProjectSprite(mobj_t *thing) // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned. // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course. // remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes! - gz = oldthing->z + oldthing->height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); + gz = interpz + oldthing->height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); gzt = gz + FixedMul(spr_height, FixedMul(spriteyscale, this_scale)); } else { - gzt = oldthing->z + FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); + gzt = interpz + FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); gz = gzt - FixedMul(spr_height, FixedMul(spriteyscale, this_scale)); } } @@ -1945,7 +1975,7 @@ static void R_ProjectSprite(mobj_t *thing) // R_GetPlaneLight won't work on sloped lights! for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { - fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); + fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interpx, interpy); if (h <= top) { light = lightnum - 1; break; @@ -1995,12 +2025,12 @@ static void R_ProjectSprite(mobj_t *thing) vis->sortscale = sortscale; vis->sortsplat = sortsplat; vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15 - vis->gx = thing->x; - vis->gy = thing->y; + vis->gx = interpx; + vis->gy = interpy; vis->gz = gz; vis->gzt = gzt; vis->thingheight = thing->height; - vis->pz = thing->z; + vis->pz = interpz; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = FixedDiv(gzt - viewz, spriteyscale); vis->scalestep = scalestep; @@ -2139,9 +2169,22 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) //SoM: 3/17/2000 fixed_t gz, gzt; + // uncapped/interpolation + fixed_t interpx = thing->x; + fixed_t interpy = thing->y; + fixed_t interpz = thing->z; + + // do interpolation + if (cv_frameinterpolation.value == 1 && !paused) + { + interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); + interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); + interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); + } + // transform the origin point - tr_x = thing->x - viewx; - tr_y = thing->y - viewy; + tr_x = interpx - viewx; + tr_y = interpy - viewy; tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance @@ -2205,13 +2248,13 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) if (x2 < portalclipstart || x1 >= portalclipend) return; - if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0) + if (P_PointOnLineSide(interpx, interpy, portalclipline) != 0) return; } //SoM: 3/17/2000: Disregard sprites that are out of view.. - gzt = thing->z + spritecachedinfo[lump].topoffset; + gzt = interpz + spritecachedinfo[lump].topoffset; gz = gzt - spritecachedinfo[lump].height; if (thing->subsector->sector->cullheight) @@ -2224,12 +2267,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis = R_NewVisSprite(); vis->scale = vis->sortscale = yscale; //<dispoffset = 0; // Monster Iestyn: 23/11/15 - vis->gx = thing->x; - vis->gy = thing->y; + vis->gx = interpx; + vis->gy = interpy; vis->gz = gz; vis->gzt = gzt; vis->thingheight = 4*FRACUNIT; - vis->pz = thing->z; + vis->pz = interpz; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; vis->scalestep = 0; diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 9de632734..2d99f5c1f 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -185,7 +185,7 @@ static char returnWadPath[256]; #include "../m_argv.h" -#include "../m_menu.h" +#include "../r_main.h" // Frame interpolation/uncapped #ifdef MAC_ALERT #include "macosx/mac_alert.h" @@ -2144,17 +2144,27 @@ static Uint64 timer_frequency; static double tic_frequency; static Uint64 tic_epoch; +static double elapsed_tics; + +static void UpdateElapsedTics(void) +{ + const Uint64 now = SDL_GetPerformanceCounter(); + + elapsed_tics += (now - tic_epoch) / tic_frequency; + tic_epoch = now; // moving epoch +} tic_t I_GetTime(void) { - static double elapsed; + UpdateElapsedTics(); + return (tic_t) floor(elapsed_tics); +} - const Uint64 now = SDL_GetPerformanceCounter(); - - elapsed += (now - tic_epoch) / tic_frequency; - tic_epoch = now; // moving epoch - - return (tic_t)elapsed; +fixed_t I_GetTimeFrac(void) +{ + UpdateElapsedTics(); + + return FLOAT_TO_FIXED((float) (elapsed_tics - floor(elapsed_tics))); } precise_t I_GetPreciseTime(void) @@ -2182,6 +2192,7 @@ void I_StartupTimer(void) tic_epoch = SDL_GetPerformanceCounter(); tic_frequency = timer_frequency / (double)NEWTICRATE; + elapsed_tics = 0.0; } void I_Sleep(void) diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index ff443935f..393b913da 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -45,6 +45,7 @@ #include "../d_main.h" #include "../m_argv.h" +#include "../m_fixed.h" #include "../w_wad.h" #include "../z_zone.h" @@ -261,6 +262,11 @@ tic_t I_GetTime(void) return newtics; } +fixed_t I_GetTimeFrac(void) +{ + return 0; +} + void I_Sleep(void) { if (cv_sleep.value != -1) From 722b04518df094dd82de4e107fbf00757c19362f Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 21 Dec 2019 12:43:24 -0600 Subject: [PATCH 002/137] Place Frame Interpolation in "Experimental" video options header This seems like an appropriate way to describe the feature for now. --- src/m_menu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/m_menu.c b/src/m_menu.c index 48ee6850d..ce38f81af 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1387,6 +1387,9 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_HEADER, NULL, "Renderer", NULL, 208}, {IT_CALL | IT_STRING, NULL, "OpenGL Options...", M_OpenGLOptionsMenu, 214}, #endif + + {IT_HEADER, NULL, "Experimental", NULL, 222}, + {IT_STRING | IT_CVAR, NULL, "Frame Interpolation", &cv_frameinterpolation, 228}, }; static menuitem_t OP_VideoModeMenu[] = From 61efef2fa9020c7fb657a689c29162f74b3dd34d Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 21 Dec 2019 15:26:30 -0600 Subject: [PATCH 003/137] Add smooth level platter under interpolation, `renderdeltatics` `renderdeltatics` can be used as a standard delta time in any place, allowing for smooth menus. It will always be equal to `realtics` when frame interpolation is turned off, producing consistent framerate behavior everywhere it is used. --- src/d_main.c | 17 ++++++++++++--- src/d_main.h | 1 - src/hardware/hw_main.c | 11 +++++----- src/m_menu.c | 49 ++++++++++++++++++++++++++---------------- src/r_main.c | 1 + src/r_main.h | 3 +++ 6 files changed, 54 insertions(+), 28 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 0281ef86c..126fc60de 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -148,7 +148,6 @@ event_t events[MAXEVENTS]; INT32 eventhead, eventtail; boolean dedicated = false; -boolean tic_happened = false; // Frame interpolation/uncapped // // D_PostEvent @@ -782,13 +781,25 @@ void D_SRB2Loop(void) realtics = 1; // process tics (but maybe not if realtic == 0) - tic_happened = realtics ? true : false; TryRunTics(realtics); if (cv_frameinterpolation.value == 1) - rendertimefrac = I_GetTimeFrac(); + { + fixed_t entertimefrac = I_GetTimeFrac(); + // renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based + renderdeltatics = realtics * FRACUNIT; + if (entertimefrac > rendertimefrac) + renderdeltatics += entertimefrac - rendertimefrac; + else + renderdeltatics -= rendertimefrac - entertimefrac; + + rendertimefrac = entertimefrac; + } else + { rendertimefrac = FRACUNIT; + renderdeltatics = realtics * FRACUNIT; + } if (cv_frameinterpolation.value == 1) { diff --git a/src/d_main.h b/src/d_main.h index a06334b6e..8189a9f2b 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -26,7 +26,6 @@ extern char srb2home[256]; //Alam: My Home extern boolean usehome; //Alam: which path? extern const char *pandf; //Alam: how to path? extern char srb2path[256]; //Alam: SRB2's Home -extern boolean tic_happened; // Frame interpolation/uncapped // the infinite loop of D_SRB2Loop() called from win_main for windows version void D_SRB2Loop(void) FUNCNORETURN; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 968ebc54e..d9c32d46b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6714,7 +6714,7 @@ void HWR_DoPostProcessor(player_t *player) // 10 by 10 grid. 2 coordinates (xy) float v[SCREENVERTS][SCREENVERTS][2]; static double disStart = 0; - static float last_fractime = 0; + static fixed_t last_fractime = 0; UINT8 x, y; INT32 WAVELENGTH; @@ -6747,16 +6747,15 @@ void HWR_DoPostProcessor(player_t *player) HWD.pfnPostImgRedraw(v); if (!(paused || P_AutoPause())) disStart += 1; - fixed_t fractime = I_GetTimeFrac(); - if (tic_happened) + if (renderdeltatics > FRACUNIT) { - disStart = disStart - last_fractime + 1 + FIXED_TO_FLOAT(fractime); + disStart = disStart - FIXED_TO_FLOAT(last_fractime) + 1 + FIXED_TO_FLOAT(rendertimefrac); } else { - disStart = disStart - last_fractime + FIXED_TO_FLOAT(fractime); + disStart = disStart - FIXED_TO_FLOAT(last_fractime) + FIXED_TO_FLOAT(rendertimefrac); } - last_fractime = fractime; + last_fractime = rendertimefrac; // Capture the screen again for screen waving on the intermission if(gamestate != GS_INTERMISSION) diff --git a/src/m_menu.c b/src/m_menu.c index ce38f81af..52c49ecba 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -207,17 +207,17 @@ menu_t SPauseDef; static levelselect_t levelselect = {0, NULL}; static UINT8 levelselectselect[3]; static patch_t *levselp[2][3]; -static INT32 lsoffs[2]; +static fixed_t lsoffs[2]; #define lsrow levelselectselect[0] #define lscol levelselectselect[1] #define lshli levelselectselect[2] #define lshseperation 101 -#define lsbasevseperation (62*vid.height)/(BASEVIDHEIGHT*vid.dupy) //62 +#define lsbasevseperation ((62*vid.height)/(BASEVIDHEIGHT*vid.dupy)) //62 #define lsheadingheight 16 #define getheadingoffset(row) (levelselect.rows[row].header[0] ? lsheadingheight : 0) -#define lsvseperation(row) lsbasevseperation + getheadingoffset(row) +#define lsvseperation(row) (lsbasevseperation + getheadingoffset(row)) #define lswide(row) levelselect.rows[row].mapavailable[3] #define lsbasex 19 @@ -5504,7 +5504,7 @@ static void M_HandleLevelPlatter(INT32 choice) { if (!lsoffs[0]) // prevent sound spam { - lsoffs[0] = -8; + lsoffs[0] = -8 * FRACUNIT; S_StartSound(NULL,sfx_s3kb7); } return; @@ -5513,7 +5513,7 @@ static void M_HandleLevelPlatter(INT32 choice) } lsrow++; - lsoffs[0] = lsvseperation(lsrow); + lsoffs[0] = lsvseperation(lsrow) * FRACUNIT; if (levelselect.rows[lsrow].header[0]) lshli = lsrow; @@ -5532,7 +5532,7 @@ static void M_HandleLevelPlatter(INT32 choice) { if (!lsoffs[0]) // prevent sound spam { - lsoffs[0] = 8; + lsoffs[0] = 8 * FRACUNIT; S_StartSound(NULL,sfx_s3kb7); } return; @@ -5541,7 +5541,7 @@ static void M_HandleLevelPlatter(INT32 choice) } lsrow--; - lsoffs[0] = -lsvseperation(iter); + lsoffs[0] = -lsvseperation(iter) * FRACUNIT; if (levelselect.rows[lsrow].header[0]) lshli = lsrow; @@ -5582,7 +5582,7 @@ static void M_HandleLevelPlatter(INT32 choice) } else if (!lsoffs[0]) // prevent sound spam { - lsoffs[0] = -8; + lsoffs[0] = -8 * FRACUNIT; S_StartSound(NULL,sfx_s3kb2); } break; @@ -5608,14 +5608,14 @@ static void M_HandleLevelPlatter(INT32 choice) { lscol++; - lsoffs[1] = (lswide(lsrow) ? 8 : -lshseperation); + lsoffs[1] = (lswide(lsrow) ? 8 : -lshseperation) * FRACUNIT; S_StartSound(NULL,sfx_s3kb7); ifselectvalnextmap(lscol) else ifselectvalnextmap(0) } else if (!lsoffs[1]) // prevent sound spam { - lsoffs[1] = 8; + lsoffs[1] = 8 * FRACUNIT; S_StartSound(NULL,sfx_s3kb7); } break; @@ -5640,14 +5640,14 @@ static void M_HandleLevelPlatter(INT32 choice) { lscol--; - lsoffs[1] = (lswide(lsrow) ? -8 : lshseperation); + lsoffs[1] = (lswide(lsrow) ? -8 : lshseperation) * FRACUNIT; S_StartSound(NULL,sfx_s3kb7); ifselectvalnextmap(lscol) else ifselectvalnextmap(0) } else if (!lsoffs[1]) // prevent sound spam { - lsoffs[1] = -8; + lsoffs[1] = -8 * FRACUNIT; S_StartSound(NULL,sfx_s3kb7); } break; @@ -5946,7 +5946,7 @@ static void M_DrawNightsAttackSuperSonic(void) static void M_DrawLevelPlatterMenu(void) { UINT8 iter = lsrow, sizeselect = (lswide(lsrow) ? 1 : 0); - INT32 y = lsbasey + lsoffs[0] - getheadingoffset(lsrow); + INT32 y = lsbasey + FixedInt(lsoffs[0]) - getheadingoffset(lsrow); const INT32 cursorx = (sizeselect ? 0 : (lscol*lshseperation)); if (currentMenu->prevMenu == &SP_TimeAttackDef) @@ -6014,7 +6014,7 @@ static void M_DrawLevelPlatterMenu(void) // draw cursor box if (levellistmode != LLM_CREATESERVER || lsrow) - V_DrawSmallScaledPatch(lsbasex + cursorx + lsoffs[1], lsbasey+lsoffs[0], 0, (levselp[sizeselect][((skullAnimCounter/4) ? 1 : 0)])); + V_DrawSmallScaledPatch(lsbasex + cursorx + FixedInt(lsoffs[1]), lsbasey+FixedInt(lsoffs[0]), 0, (levselp[sizeselect][((skullAnimCounter/4) ? 1 : 0)])); #if 0 if (levelselect.rows[lsrow].maplist[lscol] > 0) @@ -6022,13 +6022,26 @@ static void M_DrawLevelPlatterMenu(void) #endif // handle movement of cursor box - if (lsoffs[0] > 1 || lsoffs[0] < -1) - lsoffs[0] = 2*lsoffs[0]/3; + fixed_t cursormovefrac = FixedDiv(2, 3); + if (lsoffs[0] > FRACUNIT || lsoffs[0] < -FRACUNIT) + { + fixed_t offs = lsoffs[0]; + fixed_t newoffs = FixedMul(offs, cursormovefrac); + fixed_t deltaoffs = newoffs - offs; + newoffs = offs + FixedMul(deltaoffs, renderdeltatics); + lsoffs[0] = newoffs; + } else lsoffs[0] = 0; - if (lsoffs[1] > 1 || lsoffs[1] < -1) - lsoffs[1] = 2*lsoffs[1]/3; + if (lsoffs[1] > FRACUNIT || lsoffs[1] < -FRACUNIT) + { + fixed_t offs = lsoffs[1]; + fixed_t newoffs = FixedMul(offs, cursormovefrac); + fixed_t deltaoffs = newoffs - offs; + newoffs = offs + FixedMul(deltaoffs, renderdeltatics); + lsoffs[1] = newoffs; + } else lsoffs[1] = 0; diff --git a/src/r_main.c b/src/r_main.c index fe5daa00b..249607480 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -77,6 +77,7 @@ player_t *viewplayer; mobj_t *r_viewmobj; fixed_t rendertimefrac; +fixed_t renderdeltatics; // // precalculated math tables diff --git a/src/r_main.h b/src/r_main.h index 860bfa920..45254f6c4 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -35,7 +35,10 @@ extern fixed_t fovtan; extern size_t validcount, linecount, loopcount, framecount; +// The fraction of a tic being drawn (for interpolation between two tics) extern fixed_t rendertimefrac; +// Evaluated delta tics for this frame (how many tics since the last frame) +extern fixed_t renderdeltatics;; // // Lighting LUT. From c330c0571828a80d206ad59f35a2a5741c9cb155 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 21 Dec 2019 15:42:28 -0600 Subject: [PATCH 004/137] Add smooth rendering to save select screen --- src/m_menu.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 52c49ecba..246d3c79e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8350,8 +8350,8 @@ static void M_StartTutorial(INT32 choice) // ============== static INT32 saveSlotSelected = 1; -static INT32 loadgamescroll = 0; -static UINT8 loadgameoffset = 0; +static fixed_t loadgamescroll = 0; +static fixed_t loadgameoffset = 0; static void M_CacheLoadGameData(void) { @@ -8376,14 +8376,14 @@ static void M_DrawLoadGameData(void) { prev_i = i; savetodraw = (saveSlotSelected + i + numsaves)%numsaves; - x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*hsep); + x = (BASEVIDWIDTH/2 - 42 + FixedInt(loadgamescroll)) + (i*hsep); y = 33 + 9; { INT32 diff = x - (BASEVIDWIDTH/2 - 42); if (diff < 0) diff = -diff; - diff = (42 - diff)/3 - loadgameoffset; + diff = (42 - diff)/3 - FixedInt(loadgameoffset); if (diff < 0) diff = 0; y -= diff; @@ -8668,14 +8668,23 @@ skiplife: static void M_DrawLoad(void) { M_DrawMenuTitle(); + fixed_t scrollfrac = FixedDiv(2, 3); - if (loadgamescroll > 1 || loadgamescroll < -1) - loadgamescroll = 2*loadgamescroll/3; + if (loadgamescroll > FRACUNIT || loadgamescroll < -FRACUNIT) + { + fixed_t newscroll = FixedMul(loadgamescroll, scrollfrac); + fixed_t deltascroll = FixedMul(newscroll - loadgamescroll, renderdeltatics); + loadgamescroll += deltascroll; + } else loadgamescroll = 0; - if (loadgameoffset > 1) - loadgameoffset = 2*loadgameoffset/3; + if (loadgameoffset > FRACUNIT) + { + fixed_t newoffs = FixedMul(loadgameoffset, scrollfrac); + fixed_t deltaoffs = FixedMul(newoffs - loadgameoffset, renderdeltatics); + loadgameoffset += deltaoffs; + } else loadgameoffset = 0; @@ -8884,7 +8893,7 @@ static void M_ReadSaveStrings(void) UINT8 lastseen = 0; loadgamescroll = 0; - loadgameoffset = 14; + loadgameoffset = 14 * FRACUNIT; for (i = 1; (i < MAXSAVEGAMES); i++) // slot 0 is no save { @@ -8975,7 +8984,7 @@ static void M_HandleLoadSave(INT32 choice) ++saveSlotSelected; if (saveSlotSelected >= numsaves) saveSlotSelected -= numsaves; - loadgamescroll = 90; + loadgamescroll = 90 * FRACUNIT; break; case KEY_LEFTARROW: @@ -8983,7 +8992,7 @@ static void M_HandleLoadSave(INT32 choice) --saveSlotSelected; if (saveSlotSelected < 0) saveSlotSelected += numsaves; - loadgamescroll = -90; + loadgamescroll = -90 * FRACUNIT; break; case KEY_ENTER: @@ -9008,7 +9017,7 @@ static void M_HandleLoadSave(INT32 choice) else if (!loadgameoffset) { S_StartSound(NULL, sfx_lose); - loadgameoffset = 14; + loadgameoffset = 14 * FRACUNIT; } break; @@ -9034,7 +9043,7 @@ static void M_HandleLoadSave(INT32 choice) } else S_StartSound(NULL, sfx_lose); - loadgameoffset = 14; + loadgameoffset = 14 * FRACUNIT; } break; } @@ -9094,13 +9103,13 @@ static void M_LoadGame(INT32 choice) // void M_ForceSaveSlotSelected(INT32 sslot) { - loadgameoffset = 14; + loadgameoffset = 14 * FRACUNIT; // Already there? Whatever, then! if (sslot == saveSlotSelected) return; - loadgamescroll = 90; + loadgamescroll = 90 * FRACUNIT; if (saveSlotSelected <= numsaves/2) loadgamescroll = -loadgamescroll; From 056abd0461a5523c5c177bf3bdd7a838407f69c1 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 21 Dec 2019 16:26:22 -0600 Subject: [PATCH 005/137] Add smooth rendering to Record/NiGHTS Attack, F_SkyScroll --- src/f_finale.c | 12 ++++++------ src/m_menu.c | 30 ++++++++++++++++-------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index b5715b863..2c45aecc9 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -62,8 +62,6 @@ static tic_t stoptimer; static boolean keypressed = false; // (no longer) De-Demo'd Title Screen -static tic_t xscrolltimer; -static tic_t yscrolltimer; static INT32 menuanimtimer; // Title screen: background animation timing mobj_t *titlemapcameraref = NULL; @@ -2320,6 +2318,7 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) INT32 pw, ph; // scaled by dupz patch_t *pat; INT32 i, j; + fixed_t fracmenuanimtimer, xscrolltimer, yscrolltimer; if (rendermode == render_none) return; @@ -2346,12 +2345,13 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname) tilex = max(FixedCeil(FixedDiv(vid.width, pw)) >> FRACBITS, 1)+2; // one tile on both sides of center tiley = max(FixedCeil(FixedDiv(vid.height, ph)) >> FRACBITS, 1)+2; - xscrolltimer = ((menuanimtimer*scrollxspeed)/16 + patwidth*xneg) % (patwidth); - yscrolltimer = ((menuanimtimer*scrollyspeed)/16 + patheight*yneg) % (patheight); + fracmenuanimtimer = (menuanimtimer * FRACUNIT) - (FRACUNIT - rendertimefrac); + xscrolltimer = ((fracmenuanimtimer*scrollxspeed)/16 + patwidth*xneg*FRACUNIT) % (patwidth * FRACUNIT); + yscrolltimer = ((fracmenuanimtimer*scrollyspeed)/16 + patheight*yneg*FRACUNIT) % (patheight * FRACUNIT); // coordinate offsets - xscrolled = xscrolltimer * dupz; - yscrolled = yscrolltimer * dupz; + xscrolled = FixedInt(xscrolltimer * dupz); + yscrolled = FixedInt(yscrolltimer * dupz); for (x = (xispos) ? -pw*(tilex-1)+pw : 0, i = 0; i < tilex; diff --git a/src/m_menu.c b/src/m_menu.c index 246d3c79e..368e7778e 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -171,8 +171,8 @@ static INT32 vidm_nummodes; static INT32 vidm_column_size; // new menus -static tic_t recatkdrawtimer = 0; -static tic_t ntsatkdrawtimer = 0; +static fixed_t recatkdrawtimer = 0; +static fixed_t ntsatkdrawtimer = 0; static tic_t charseltimer = 0; static fixed_t char_scroll = 0; @@ -5810,7 +5810,7 @@ static void M_DrawRecordAttackForeground(void) for (i = -12; i < (BASEVIDHEIGHT/height) + 12; i++) { - INT32 y = ((i*height) - (height - ((recatkdrawtimer*2)%height))); + INT32 y = ((i*height) - (height - ((FixedInt(recatkdrawtimer*2))%height))); // don't draw above the screen { INT32 sy = FixedMul(y, dupz<> FRACBITS; @@ -5827,17 +5827,18 @@ static void M_DrawRecordAttackForeground(void) } // draw clock - fa = (FixedAngle(((recatkdrawtimer * 4) % 360)<>ANGLETOFINESHIFT) & FINEMASK; + fa = (FixedAngle(((FixedInt(recatkdrawtimer * 4)) % 360)<>ANGLETOFINESHIFT) & FINEMASK; V_DrawSciencePatch(160<width; @@ -5853,7 +5854,7 @@ static void M_DrawNightsAttackMountains(void) if (x < BASEVIDWIDTH) V_DrawScaledPatch(x, y, V_SNAPTOLEFT, background); - bgscrollx += (FRACUNIT/2); + bgscrollx += FixedMul(FRACUNIT/2, renderdeltatics); if (bgscrollx > w<>ANGLETOFINESHIFT) & FINEMASK; + INT32 timer = FixedInt(ntsatkdrawtimer/4) % 2; + angle_t fa = (FixedAngle((FixedInt(ntsatkdrawtimer * 4) % 360)<>ANGLETOFINESHIFT) & FINEMASK; V_DrawFixedPatch(235< Date: Sun, 22 Dec 2019 01:16:57 -0600 Subject: [PATCH 006/137] Ensure viewsector is accurate to viewx/viewy This fixes a potential crash in OpenGL when changing between levels. --- src/r_fps.c | 39 ++++++++++++++------------------------- src/r_fps.h | 5 ----- 2 files changed, 14 insertions(+), 30 deletions(-) diff --git a/src/r_fps.c b/src/r_fps.c index 519288bab..ce30fd48e 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -39,6 +39,16 @@ viewvars_t *newview = &p1view_new; enum viewcontext_e viewcontext = VIEWCONTEXT_PLAYER1; +static fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac) +{ + return FixedMul(frac, to - from); +} + +static angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac) +{ + return FixedMul(frac, to - from); +} + // recalc necessary stuff for mouseaiming // slopes are already calculated for the full possible view (which is 4*viewheight). // 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) @@ -80,6 +90,8 @@ void R_InterpolateView(fixed_t frac) boolean skybox = 0; if (FIXED_TO_FLOAT(frac) < 0) frac = 0; + if (frac > FRACUNIT) + frac = FRACUNIT; viewx = oldview->x + R_LerpFixed(oldview->x, newview->x, frac); viewy = oldview->y + R_LerpFixed(oldview->y, newview->y, frac); @@ -93,16 +105,8 @@ void R_InterpolateView(fixed_t frac) // this is gonna create some interesting visual errors for long distance teleports... // might want to recalculate the view sector every frame instead... - if (frac >= FRACUNIT) - { - viewplayer = newview->player; - viewsector = newview->sector; - } - else - { - viewplayer = oldview->player; - viewsector = oldview->sector; - } + viewplayer = newview->player; + viewsector = R_PointInSubsector(viewx, viewy)->sector; // well, this ain't pretty if (newview == &sky1view_new || newview == &sky2view_new) @@ -152,18 +156,3 @@ void R_SetViewContext(enum viewcontext_e _viewcontext) break; } } - -fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac) -{ - return FixedMul(frac, to - from); -} - -INT32 R_LerpInt32(INT32 from, INT32 to, fixed_t frac) -{ - return FixedInt(FixedMul(frac, (to*FRACUNIT) - (from*FRACUNIT))); -} - -angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac) -{ - return FixedMul(frac, to - from); -} diff --git a/src/r_fps.h b/src/r_fps.h index f9ee6f0de..6e3ff3adb 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -51,9 +51,4 @@ void R_UpdateViewInterpolation(void); // Set the current view context (the viewvars pointed to by newview) void R_SetViewContext(enum viewcontext_e _viewcontext); -fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac); -INT32 R_LerpInt32(INT32 from, INT32 to, fixed_t frac); -UINT32 R_LerpUInt32(UINT32 from, UINT32 to, fixed_t frac); -angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac); - #endif From bc9251e13be1923096a875c15ff4610bec54d749 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 25 Dec 2019 20:00:21 -0600 Subject: [PATCH 007/137] Ensure + commands get executed before map start --- src/d_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/d_main.c b/src/d_main.c index 126fc60de..00ede9aec 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1609,6 +1609,8 @@ void D_SRB2Main(void) // as having been modified for the first game. M_PushSpecialParameters(); // push all "+" parameter at the command buffer + COM_BufExecute(); // ensure the command buffer gets executed before the map starts (+skin) + if (M_CheckParm("-gametype") && M_IsNextParm()) { // from Command_Map_f From 996f35b59200c77df5654294f6fe1e3088260bd3 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 30 Jun 2021 03:38:16 -0500 Subject: [PATCH 008/137] Always have precise_t defined --- src/doomtype.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/doomtype.h b/src/doomtype.h index 5ddd9ae44..b8f602c64 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -392,8 +392,6 @@ unset_bit_array (bitarray_t * const array, const int value) array[value >> 3] &= ~(1<<(value & 7)); } -#ifdef HAVE_SDL typedef UINT64 precise_t; -#endif #endif //__DOOMTYPE__ From 7c9e133eb4b1cbdfe791c25ed395faf373d2bf7c Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sun, 10 Apr 2022 22:29:52 -0500 Subject: [PATCH 009/137] Fix misc dropshadow issues --- src/d_clisrv.c | 1 - src/hardware/hw_main.c | 17 +++++++++++++++-- src/r_main.c | 3 --- src/r_main.h | 1 - src/r_things.c | 40 ++++++++++++++++++++++++++++++++++++---- 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 70e283bba..ac8bba608 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5270,7 +5270,6 @@ void TryRunTics(tic_t realtics) boolean update_stats = !(paused || P_AutoPause()); DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); - prev_tics = I_GetTime(); if (update_stats) PS_START_TIMING(ps_tictime); diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index d9c32d46b..5402b4a8d 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3644,6 +3644,19 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) fixed_t slopez; pslope_t *groundslope; + // uncapped/interpolation + fixed_t interpx; + fixed_t interpy; + + interpx = thing->x; + interpy = thing->y; + + if (cv_frameinterpolation.value == 1 && !paused) + { + interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); + interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); + } + groundz = R_GetShadowZ(thing, &groundslope); heightsec = thing->subsector->sector->heightsec; @@ -3678,8 +3691,8 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height); fscale = FIXED_TO_FLOAT(scalemul); - fx = FIXED_TO_FLOAT(thing->x); - fy = FIXED_TO_FLOAT(thing->y); + fx = FIXED_TO_FLOAT(interpx); + fy = FIXED_TO_FLOAT(interpy); // 3--2 // | /| diff --git a/src/r_main.c b/src/r_main.c index 249607480..e7f567b58 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -100,9 +100,6 @@ lighttable_t *scalelight[LIGHTLEVELS][MAXLIGHTSCALE]; lighttable_t *scalelightfixed[MAXLIGHTSCALE]; lighttable_t *zlight[LIGHTLEVELS][MAXLIGHTZ]; -// Frame interpolation/uncapped -tic_t prev_tics; - // Hack to support extra boom colormaps. extracolormap_t *extra_colormaps = NULL; diff --git a/src/r_main.h b/src/r_main.h index 45254f6c4..08654a694 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -120,7 +120,6 @@ extern consvar_t cv_skybox; extern consvar_t cv_tailspickup; // Frame interpolation (uncapped framerate) -extern tic_t prev_tics; extern consvar_t cv_frameinterpolation; // Called by startup code. diff --git a/src/r_things.c b/src/r_things.c index 55e84d6b7..553e1607f 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1140,7 +1140,24 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) msecnode_t *node; sector_t *sector; ffloor_t *rover; -#define CHECKZ (isflipped ? z > thing->z+thing->height/2 && z < groundz : z < thing->z+thing->height/2 && z > groundz) + + // for frame interpolation + fixed_t interpx; + fixed_t interpy; + fixed_t interpz; + + interpx = thing->x; + interpy = thing->y; + interpz = thing->z; + + if (cv_frameinterpolation.value == 1 && !paused) + { + interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); + interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); + interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); + } + +#define CHECKZ (isflipped ? z > interpz+thing->height/2 && z < groundz : z < interpz+thing->height/2 && z > groundz) for (node = thing->touching_sectorlist; node; node = node->m_sectorlist_next) { @@ -1151,7 +1168,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) if (sector->heightsec != -1) z = isflipped ? sectors[sector->heightsec].ceilingheight : sectors[sector->heightsec].floorheight; else - z = isflipped ? P_GetSectorCeilingZAt(sector, thing->x, thing->y) : P_GetSectorFloorZAt(sector, thing->x, thing->y); + z = isflipped ? P_GetSectorCeilingZAt(sector, interpx, interpy) : P_GetSectorFloorZAt(sector, interpx, interpy); if CHECKZ { @@ -1165,7 +1182,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES) || (rover->alpha < 90 && !(rover->flags & FF_SWIMMABLE))) continue; - z = isflipped ? P_GetFFloorBottomZAt(rover, thing->x, thing->y) : P_GetFFloorTopZAt(rover, thing->x, thing->y); + z = isflipped ? P_GetFFloorBottomZAt(rover, interpx, interpy) : P_GetFFloorTopZAt(rover, interpx, interpy); if CHECKZ { groundz = z; @@ -1252,9 +1269,24 @@ static void R_SkewShadowSprite( fixed_t groundz, INT32 spriteheight, fixed_t scalemul, fixed_t *shadowyscale, fixed_t *shadowskew) { + // haha let's try some dumb stuff fixed_t xslope, zslope; - angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - groundslope->xydirection) >> ANGLETOFINESHIFT; + angle_t sloperelang; + + // for frame interpolation + fixed_t interpx; + fixed_t interpy; + + interpx = thing->x; + interpy = thing->y; + + if (cv_frameinterpolation.value == 1 && !paused) + { + interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); + interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); + } + sloperelang = (R_PointToAngle(interpx, interpy) - groundslope->xydirection) >> ANGLETOFINESHIFT; xslope = FixedMul(FINESINE(sloperelang), groundslope->zdelta); zslope = FixedMul(FINECOSINE(sloperelang), groundslope->zdelta); From d34ec2ef067596dad022da9b559fb6e87d9d3024 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 11 Apr 2022 11:22:54 -0500 Subject: [PATCH 010/137] Reset view interpolation on level load --- src/p_setup.c | 6 ++++++ src/r_fps.c | 24 +++++++++++++++++++----- src/r_fps.h | 2 ++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index b4675b27d..547ad4575 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -33,6 +33,7 @@ #include "r_picformats.h" #include "r_sky.h" #include "r_draw.h" +#include "r_fps.h" // R_ResetViewInterpolation in level load #include "s_sound.h" #include "st_stuff.h" @@ -4479,6 +4480,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_MapEnd(); // tmthing is no longer needed from this point onwards + if (rendermode != render_none) + { + R_ResetViewInterpolation(); + } + // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap... if (!titlemapinaction) { diff --git a/src/r_fps.c b/src/r_fps.c index ce30fd48e..f9f1d60c0 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -34,6 +34,7 @@ static viewvars_t sky2view_old; static viewvars_t sky2view_new; static viewvars_t *oldview = &p1view_old; +static BOOL oldview_valid = FALSE; viewvars_t *newview = &p1view_new; @@ -87,18 +88,25 @@ static void R_SetupFreelook(player_t *player, boolean skybox) void R_InterpolateView(fixed_t frac) { + viewvars_t* prevview = oldview; boolean skybox = 0; if (FIXED_TO_FLOAT(frac) < 0) frac = 0; if (frac > FRACUNIT) frac = FRACUNIT; - viewx = oldview->x + R_LerpFixed(oldview->x, newview->x, frac); - viewy = oldview->y + R_LerpFixed(oldview->y, newview->y, frac); - viewz = oldview->z + R_LerpFixed(oldview->z, newview->z, frac); + if (oldview_valid == FALSE) + { + // interpolate from newview to newview + prevview = newview; + } - viewangle = oldview->angle + R_LerpAngle(oldview->angle, newview->angle, frac); - aimingangle = oldview->aim + R_LerpAngle(oldview->aim, newview->aim, frac); + viewx = prevview->x + R_LerpFixed(prevview->x, newview->x, frac); + viewy = prevview->y + R_LerpFixed(prevview->y, newview->y, frac); + viewz = prevview->z + R_LerpFixed(prevview->z, newview->z, frac); + + viewangle = prevview->angle + R_LerpAngle(prevview->angle, newview->angle, frac); + aimingangle = prevview->aim + R_LerpAngle(prevview->aim, newview->aim, frac); viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); @@ -123,6 +131,12 @@ void R_UpdateViewInterpolation(void) p2view_old = p2view_new; sky1view_old = sky1view_new; sky2view_old = sky2view_new; + oldview_valid = TRUE; +} + +void R_ResetViewInterpolation(void) +{ + oldview_valid = FALSE; } void R_SetViewContext(enum viewcontext_e _viewcontext) diff --git a/src/r_fps.h b/src/r_fps.h index 6e3ff3adb..831ffbdc8 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -48,6 +48,8 @@ extern viewvars_t *newview; void R_InterpolateView(fixed_t frac); // Buffer the current new views into the old views. Call once after each real tic. void R_UpdateViewInterpolation(void); +// Reset the view states (e.g. after level load) so R_InterpolateView doesn't interpolate invalid data +void R_ResetViewInterpolation(void); // Set the current view context (the viewvars pointed to by newview) void R_SetViewContext(enum viewcontext_e _viewcontext); From 4ee6027180db84b32a6f8551d665af8732e20b0f Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 11 Apr 2022 18:49:50 -0500 Subject: [PATCH 011/137] Remove unnecessary precipmobj thinker hack --- src/hardware/hw_main.c | 10 ---------- src/p_mobj.c | 7 +++---- src/p_mobj.h | 2 -- src/r_things.c | 13 +------------ 4 files changed, 4 insertions(+), 28 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 5402b4a8d..9155da201 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5595,16 +5595,6 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height); vis->precip = true; - - // okay... this is a hack, but weather isn't networked, so it should be ok - if (!(thing->precipflags & PCF_THUNK)) - { - if (thing->precipflags & PCF_RAIN) - P_RainThinker(thing); - else - P_SnowThinker(thing); - thing->precipflags |= PCF_THUNK; - } } #endif diff --git a/src/p_mobj.c b/src/p_mobj.c index b52b9734f..0ec069471 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4021,8 +4021,7 @@ void P_RecalcPrecipInSector(sector_t *sector) // void P_NullPrecipThinker(precipmobj_t *mobj) { - //(void)mobj; - mobj->precipflags &= ~PCF_THUNK; + (void)mobj; } void P_SnowThinker(precipmobj_t *mobj) @@ -10976,14 +10975,14 @@ static inline precipmobj_t *P_SpawnRainMobj(fixed_t x, fixed_t y, fixed_t z, mob { precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); mo->precipflags |= PCF_RAIN; - //mo->thinker.function.acp1 = (actionf_p1)P_RainThinker; + mo->thinker.function.acp1 = (actionf_p1)P_RainThinker; return mo; } static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); - //mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker; + mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker; return mo; } diff --git a/src/p_mobj.h b/src/p_mobj.h index 998baa19e..702fd4047 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -269,8 +269,6 @@ typedef enum { PCF_MOVINGFOF = 8, // Is rain. PCF_RAIN = 16, - // Ran the thinker this tic. - PCF_THUNK = 32, } precipflag_t; // Map Object definition. diff --git a/src/r_things.c b/src/r_things.c index 553e1607f..c8cdf6e62 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2292,7 +2292,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) if (thing->subsector->sector->cullheight) { if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) - goto weatherthink; + return; } // store information in a vissprite @@ -2346,17 +2346,6 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // Fullbright vis->colormap = colormaps; - -weatherthink: - // okay... this is a hack, but weather isn't networked, so it should be ok - if (!(thing->precipflags & PCF_THUNK)) - { - if (thing->precipflags & PCF_RAIN) - P_RainThinker(thing); - else - P_SnowThinker(thing); - thing->precipflags |= PCF_THUNK; - } } // R_AddSprites From f2a881f3859a00878b51f3d6b11eefba24d71c1c Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 11 Apr 2022 19:16:06 -0500 Subject: [PATCH 012/137] Add reset interpolation state functions --- src/p_mobj.c | 49 +++++++++++++++++++++++++++++-------------------- src/p_mobj.h | 2 ++ 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 0ec069471..a20f5e1c3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -892,6 +892,30 @@ void P_EmeraldManager(void) emeraldspawndelay = 0; } +// +// P_ResetInterpolationState +// +// Reset the rendering interpolation state of the mobj. +// +void P_ResetInterpolationState(mobj_t *mobj) +{ + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; +} + +// +// P_ResetPrecipitationInterpolationState +// +// Reset the rendering interpolation state of the precipmobj. +// +void P_ResetPrecipitationInterpolationState(precipmobj_t *mobj) +{ + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; +} + // // P_ExplodeMissile // @@ -4026,10 +4050,7 @@ void P_NullPrecipThinker(precipmobj_t *mobj) void P_SnowThinker(precipmobj_t *mobj) { - // reset old state (for interpolation) - mobj->old_x = mobj->x; - mobj->old_y = mobj->y; - mobj->old_z = mobj->z; + P_ResetPrecipitationInterpolationState(mobj); P_CycleStateAnimation((mobj_t *)mobj); @@ -4040,10 +4061,7 @@ void P_SnowThinker(precipmobj_t *mobj) void P_RainThinker(precipmobj_t *mobj) { - // reset old state (for interpolation) - mobj->old_x = mobj->x; - mobj->old_y = mobj->y; - mobj->old_z = mobj->z; + P_ResetPrecipitationInterpolationState(mobj); P_CycleStateAnimation((mobj_t *)mobj); @@ -10041,10 +10059,7 @@ void P_MobjThinker(mobj_t *mobj) I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); - // Set old position (for interpolation) - mobj->old_x = mobj->x; - mobj->old_y = mobj->y; - mobj->old_z = mobj->z; + P_ResetInterpolationState(mobj); if (mobj->flags & MF_NOTHINK) return; @@ -10911,10 +10926,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if (CheckForReverseGravity && !(mobj->flags & MF_NOBLOCKMAP)) P_CheckGravity(mobj, false); - // set old state too (for interpolation) - mobj->old_x = mobj->x; - mobj->old_y = mobj->y; - mobj->old_z = mobj->z; + P_ResetInterpolationState(mobj); return mobj; } @@ -10963,10 +10975,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype || mobj->subsector->sector->floorpic == skyflatnum) mobj->precipflags |= PCF_PIT; - // set initial old positions (for interpolation) - mobj->old_x = mobj->x; - mobj->old_y = mobj->y; - mobj->old_z = mobj->z; + P_ResetPrecipitationInterpolationState(mobj); return mobj; } diff --git a/src/p_mobj.h b/src/p_mobj.h index 702fd4047..7f2736801 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -501,6 +501,8 @@ void P_RingZMovement(mobj_t *mo); boolean P_SceneryZMovement(mobj_t *mo); void P_PlayerZMovement(mobj_t *mo); void P_EmeraldManager(void); +void P_ResetInterpolationState(mobj_t *mobj); +void P_ResetPrecipitationInterpolationState(precipmobj_t *mobj); extern INT32 modulothing; From 4c31902b9808646e2823b8130184d4c7d13395f2 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 11 Apr 2022 19:28:16 -0500 Subject: [PATCH 013/137] Reset precip interpolation on snap to ceil --- src/p_mobj.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index a20f5e1c3..d9910b1ee 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4056,7 +4056,10 @@ void P_SnowThinker(precipmobj_t *mobj) // adjust height if ((mobj->z += mobj->momz) <= mobj->floorz) + { mobj->z = mobj->ceilingz; + P_ResetPrecipitationInterpolationState(mobj); + } } void P_RainThinker(precipmobj_t *mobj) @@ -4082,6 +4085,7 @@ void P_RainThinker(precipmobj_t *mobj) return; mobj->z = mobj->ceilingz; + P_ResetPrecipitationInterpolationState(mobj); P_SetPrecipMobjState(mobj, S_RAIN1); return; From f0279e69f296f07113a457cb52ca33d270e17495 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 11 Apr 2022 19:41:27 -0500 Subject: [PATCH 014/137] Reset mobj interp state on TeleportMove --- src/p_map.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_map.c b/src/p_map.c index 9f80d92b5..145f9bbe9 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -103,6 +103,8 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) thing->floorrover = tmfloorrover; thing->ceilingrover = tmceilingrover; + P_ResetInterpolationState(thing); + return true; } From 8908dcccde0f175ea0380e0a699752f581c46fa0 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 11 Apr 2022 20:06:52 -0500 Subject: [PATCH 015/137] Only swap view interp state if a tick is run --- src/g_game.c | 11 +++++++++-- src/r_fps.c | 8 ++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index fb1c0d522..8eb731b1f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2363,7 +2363,11 @@ void G_Ticker(boolean run) F_TextPromptTicker(); AM_Ticker(); HU_Ticker(); - R_UpdateViewInterpolation(); + if (run) + { + R_UpdateViewInterpolation(); + } + break; @@ -2420,7 +2424,10 @@ void G_Ticker(boolean run) if (titlemapinaction) { P_Ticker(run); - R_UpdateViewInterpolation(); + if (run) + { + R_UpdateViewInterpolation(); + } // then intentionally fall through } /* FALLTHRU */ diff --git a/src/r_fps.c b/src/r_fps.c index f9f1d60c0..5ab531346 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -34,7 +34,7 @@ static viewvars_t sky2view_old; static viewvars_t sky2view_new; static viewvars_t *oldview = &p1view_old; -static BOOL oldview_valid = FALSE; +static boolean oldview_valid = false; viewvars_t *newview = &p1view_new; @@ -95,7 +95,7 @@ void R_InterpolateView(fixed_t frac) if (frac > FRACUNIT) frac = FRACUNIT; - if (oldview_valid == FALSE) + if (oldview_valid == false) { // interpolate from newview to newview prevview = newview; @@ -131,12 +131,12 @@ void R_UpdateViewInterpolation(void) p2view_old = p2view_new; sky1view_old = sky1view_new; sky2view_old = sky2view_new; - oldview_valid = TRUE; + oldview_valid = true; } void R_ResetViewInterpolation(void) { - oldview_valid = FALSE; + oldview_valid = false; } void R_SetViewContext(enum viewcontext_e _viewcontext) From 6dd27af26e6fa47f6e449db139f193c730b24910 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 11 Apr 2022 22:56:48 -0500 Subject: [PATCH 016/137] Run anti-lag chasecam at tic frequency Fixes jittery and unstable chasecam in high latency netgames --- src/d_main.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 00ede9aec..2f564c6c8 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -825,10 +825,17 @@ void D_SRB2Loop(void) // Lagless camera! Yay! if (gamestate == GS_LEVEL && netgame) { - if (splitscreen && camera2.chase) - P_MoveChaseCamera(&players[secondarydisplayplayer], &camera2, false); - if (camera.chase) - P_MoveChaseCamera(&players[displayplayer], &camera, false); + // Evaluate the chase cam once for every local realtic + // This might actually be better suited inside G_Ticker or TryRunTics + for (tic_t chasecamtics = 0; chasecamtics < realtics; chasecamtics++) + { + if (splitscreen && camera2.chase) + P_MoveChaseCamera(&players[secondarydisplayplayer], &camera2, false); + if (camera.chase) + P_MoveChaseCamera(&players[displayplayer], &camera, false); + } + R_UpdateViewInterpolation(); + } // (Only display if not already done for frame interp) cv_frameinterpolation.value == 0 ? D_Display() : 0; From ac2510f28444d9529be8c01ad8634248d1055a2e Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 12 Apr 2022 18:39:11 -0500 Subject: [PATCH 017/137] Homogenize mobj interpolations --- src/hardware/hw_main.c | 76 ++++++++++----------- src/r_fps.c | 38 +++++++++-- src/r_fps.h | 11 +++ src/r_things.c | 152 ++++++++++++++++++++--------------------- 4 files changed, 152 insertions(+), 125 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 9155da201..95b62eb5f 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -24,6 +24,7 @@ #include "../v_video.h" #include "../p_local.h" #include "../p_setup.h" +#include "../r_fps.h" #include "../r_local.h" #include "../r_patch.h" #include "../r_picformats.h" @@ -3645,16 +3646,15 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) pslope_t *groundslope; // uncapped/interpolation - fixed_t interpx; - fixed_t interpy; - - interpx = thing->x; - interpy = thing->y; + interpmobjstate_t interp = {0}; if (cv_frameinterpolation.value == 1 && !paused) { - interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); - interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); + R_InterpolateMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); } groundz = R_GetShadowZ(thing, &groundslope); @@ -3677,7 +3677,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) return; } - floordiff = abs((flip < 0 ? thing->height : 0) + thing->z - groundz); + floordiff = abs((flip < 0 ? thing->height : 0) + interp.z - groundz); alpha = floordiff / (4*FRACUNIT) + 75; if (alpha >= 255) return; @@ -3691,8 +3691,8 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height); fscale = FIXED_TO_FLOAT(scalemul); - fx = FIXED_TO_FLOAT(interpx); - fy = FIXED_TO_FLOAT(interpy); + fx = FIXED_TO_FLOAT(interp.x); + fy = FIXED_TO_FLOAT(interp.y); // 3--2 // | /| @@ -5065,10 +5065,7 @@ static void HWR_ProjectSprite(mobj_t *thing) #endif // uncapped/interpolation - fixed_t interpx; - fixed_t interpy; - fixed_t interpz; - angle_t interpangle; + interpmobjstate_t interp = {0}; if (!thing) return; @@ -5091,17 +5088,14 @@ static void HWR_ProjectSprite(mobj_t *thing) dispoffset = thing->info->dispoffset; - interpx = thing->x; - interpy = thing->y; - interpz = thing->z; - interpangle = mobjangle; if (cv_frameinterpolation.value == 1 && !paused) { - interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); - interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); - interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); - interpangle = mobjangle; + R_InterpolateMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); } this_scale = FIXED_TO_FLOAT(thing->scale); @@ -5109,8 +5103,8 @@ static void HWR_ProjectSprite(mobj_t *thing) spriteyscale = FIXED_TO_FLOAT(thing->spriteyscale); // transform the origin point - tr_x = FIXED_TO_FLOAT(interpx) - gl_viewx; - tr_y = FIXED_TO_FLOAT(interpy) - gl_viewy; + tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx; + tr_y = FIXED_TO_FLOAT(interp.y) - gl_viewy; // rotation around vertical axis tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin); @@ -5133,8 +5127,8 @@ static void HWR_ProjectSprite(mobj_t *thing) } // The above can stay as it works for cutting sprites that are too close - tr_x = FIXED_TO_FLOAT(interpx); - tr_y = FIXED_TO_FLOAT(interpy); + tr_x = FIXED_TO_FLOAT(interp.x); + tr_y = FIXED_TO_FLOAT(interp.y); // decide which patch to use for sprite relative to player #ifdef RANGECHECK @@ -5182,7 +5176,7 @@ static void HWR_ProjectSprite(mobj_t *thing) I_Error("sprframes NULL for sprite %d\n", thing->sprite); #endif - ang = R_PointToAngle (interpx, interpy) - interpangle; + ang = R_PointToAngle (interp.x, interp.y) - interp.angle; if (mirrored) ang = InvAngle(ang); @@ -5328,12 +5322,12 @@ static void HWR_ProjectSprite(mobj_t *thing) if (vflip) { - gz = FIXED_TO_FLOAT(interpz + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gz = FIXED_TO_FLOAT(interp.z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale); } else { - gzt = FIXED_TO_FLOAT(interpz) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); + gzt = FIXED_TO_FLOAT(interp.z) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale); gz = gzt - (FIXED_TO_FLOAT(spr_height) * this_yscale); } @@ -5352,7 +5346,7 @@ static void HWR_ProjectSprite(mobj_t *thing) if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { float top = gzt; - float bottom = FIXED_TO_FLOAT(thing->z); + float bottom = FIXED_TO_FLOAT(interp.z); if (R_ThingIsFloorSprite(thing)) top = bottom; @@ -5505,21 +5499,21 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) } // uncapped/interpolation - fixed_t interpx = thing->x; - fixed_t interpy = thing->y; - fixed_t interpz = thing->z; + interpmobjstate_t interp = {0}; // do interpolation if (cv_frameinterpolation.value == 1 && !paused) { - interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); - interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); - interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); + R_InterpolatePrecipMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolatePrecipMobjState(thing, FRACUNIT, &interp); } // transform the origin point - tr_x = FIXED_TO_FLOAT(interpx) - gl_viewx; - tr_y = FIXED_TO_FLOAT(interpy) - gl_viewy; + tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx; + tr_y = FIXED_TO_FLOAT(interp.y) - gl_viewy; // rotation around vertical axis tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin); @@ -5528,8 +5522,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) if (tz < ZCLIP_PLANE) return; - tr_x = FIXED_TO_FLOAT(interpx); - tr_y = FIXED_TO_FLOAT(interpy); + tr_x = FIXED_TO_FLOAT(interp.x); + tr_y = FIXED_TO_FLOAT(interp.y); // decide which patch to use for sprite relative to player if ((unsigned)thing->sprite >= numsprites) @@ -5591,7 +5585,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->colormap = NULL; // set top/bottom coords - vis->gzt = FIXED_TO_FLOAT(interpz + spritecachedinfo[lumpoff].topoffset); + vis->gzt = FIXED_TO_FLOAT(interp.z + spritecachedinfo[lumpoff].topoffset); vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height); vis->precip = true; diff --git a/src/r_fps.c b/src/r_fps.c index 5ab531346..9bbae0676 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -42,12 +42,12 @@ enum viewcontext_e viewcontext = VIEWCONTEXT_PLAYER1; static fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac) { - return FixedMul(frac, to - from); + return from + FixedMul(frac, to - from); } static angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac) { - return FixedMul(frac, to - from); + return from + FixedMul(frac, to - from); } // recalc necessary stuff for mouseaiming @@ -101,12 +101,12 @@ void R_InterpolateView(fixed_t frac) prevview = newview; } - viewx = prevview->x + R_LerpFixed(prevview->x, newview->x, frac); - viewy = prevview->y + R_LerpFixed(prevview->y, newview->y, frac); - viewz = prevview->z + R_LerpFixed(prevview->z, newview->z, frac); + viewx = R_LerpFixed(prevview->x, newview->x, frac); + viewy = R_LerpFixed(prevview->y, newview->y, frac); + viewz = R_LerpFixed(prevview->z, newview->z, frac); - viewangle = prevview->angle + R_LerpAngle(prevview->angle, newview->angle, frac); - aimingangle = prevview->aim + R_LerpAngle(prevview->aim, newview->aim, frac); + viewangle = R_LerpAngle(prevview->angle, newview->angle, frac); + aimingangle = R_LerpAngle(prevview->aim, newview->aim, frac); viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT); viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); @@ -170,3 +170,27 @@ void R_SetViewContext(enum viewcontext_e _viewcontext) break; } } + +void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) +{ + out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); + out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); + out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); + + if (mobj->player) + { + out->angle = mobj->player->drawangle; + } + else + { + out->angle = mobj->angle; + } +} + +void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out) +{ + out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); + out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); + out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); + out->angle = mobj->angle; +} diff --git a/src/r_fps.h b/src/r_fps.h index 831ffbdc8..04f44de6e 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -44,6 +44,13 @@ typedef struct { extern viewvars_t *newview; +typedef struct { + fixed_t x; + fixed_t y; + fixed_t z; + angle_t angle; +} interpmobjstate_t; + // Interpolates the current view variables (r_state.h) against the selected view context in R_SetViewContext void R_InterpolateView(fixed_t frac); // Buffer the current new views into the old views. Call once after each real tic. @@ -52,5 +59,9 @@ void R_UpdateViewInterpolation(void); void R_ResetViewInterpolation(void); // Set the current view context (the viewvars pointed to by newview) void R_SetViewContext(enum viewcontext_e _viewcontext); +// Evaluate the interpolated mobj state for the given mobj +void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out); +// Evaluate the interpolated mobj state for the given precipmobj +void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out); #endif diff --git a/src/r_things.c b/src/r_things.c index c8cdf6e62..10fb25cc0 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -23,6 +23,7 @@ #include "info.h" // spr2names #include "i_video.h" // rendermode #include "i_system.h" +#include "r_fps.h" #include "r_things.h" #include "r_patch.h" #include "r_patchrotation.h" @@ -1142,22 +1143,18 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) ffloor_t *rover; // for frame interpolation - fixed_t interpx; - fixed_t interpy; - fixed_t interpz; - - interpx = thing->x; - interpy = thing->y; - interpz = thing->z; + interpmobjstate_t interp = {0}; if (cv_frameinterpolation.value == 1 && !paused) { - interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); - interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); - interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); + R_InterpolateMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); } -#define CHECKZ (isflipped ? z > interpz+thing->height/2 && z < groundz : z < interpz+thing->height/2 && z > groundz) +#define CHECKZ (isflipped ? z > interp.z+thing->height/2 && z < groundz : z < interp.z+thing->height/2 && z > groundz) for (node = thing->touching_sectorlist; node; node = node->m_sectorlist_next) { @@ -1168,7 +1165,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) if (sector->heightsec != -1) z = isflipped ? sectors[sector->heightsec].ceilingheight : sectors[sector->heightsec].floorheight; else - z = isflipped ? P_GetSectorCeilingZAt(sector, interpx, interpy) : P_GetSectorFloorZAt(sector, interpx, interpy); + z = isflipped ? P_GetSectorCeilingZAt(sector, interp.x, interp.y) : P_GetSectorFloorZAt(sector, interp.x, interp.y); if CHECKZ { @@ -1182,7 +1179,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES) || (rover->alpha < 90 && !(rover->flags & FF_SWIMMABLE))) continue; - z = isflipped ? P_GetFFloorBottomZAt(rover, interpx, interpy) : P_GetFFloorTopZAt(rover, interpx, interpy); + z = isflipped ? P_GetFFloorBottomZAt(rover, interp.x, interp.y) : P_GetFFloorTopZAt(rover, interp.x, interp.y); if CHECKZ { groundz = z; @@ -1275,18 +1272,18 @@ static void R_SkewShadowSprite( angle_t sloperelang; // for frame interpolation - fixed_t interpx; - fixed_t interpy; - - interpx = thing->x; - interpy = thing->y; + interpmobjstate_t interp = {0}; if (cv_frameinterpolation.value == 1 && !paused) { - interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); - interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); + R_InterpolateMobjState(thing, rendertimefrac, &interp); } - sloperelang = (R_PointToAngle(interpx, interpy) - groundslope->xydirection) >> ANGLETOFINESHIFT; + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); + } + + sloperelang = (R_PointToAngle(interp.x, interp.y) - groundslope->xydirection) >> ANGLETOFINESHIFT; xslope = FixedMul(FINESINE(sloperelang), groundslope->zdelta); zslope = FixedMul(FINECOSINE(sloperelang), groundslope->zdelta); @@ -1314,11 +1311,21 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t groundz; pslope_t *groundslope; boolean isflipped = thing->eflags & MFE_VERTICALFLIP; + interpmobjstate_t interp = {0}; groundz = R_GetShadowZ(thing, &groundslope); if (abs(groundz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes + if (cv_frameinterpolation.value == 1 && !paused) + { + R_InterpolateMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); + } + heightsec = thing->subsector->sector->heightsec; if (viewplayer->mo && viewplayer->mo->subsector) phs = viewplayer->mo->subsector->sector->heightsec; @@ -1337,7 +1344,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, return; } - floordiff = abs((isflipped ? thing->height : 0) + thing->z - groundz); + floordiff = abs((isflipped ? thing->height : 0) + interp.z - groundz); trans = floordiff / (100*FRACUNIT) + 3; if (trans >= 9) return; @@ -1377,8 +1384,8 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->mobjflags = 0; shadow->sortscale = vis->sortscale; shadow->dispoffset = vis->dispoffset - 5; - shadow->gx = thing->x; - shadow->gy = thing->y; + shadow->gx = interp.x; + shadow->gy = interp.y; shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + patch->height * shadowyscale / 2; shadow->gz = shadow->gzt - patch->height * shadowyscale; shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale)); @@ -1422,7 +1429,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, // R_GetPlaneLight won't work on sloped lights! for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { - fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y); + fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interp.x, interp.y); if (h <= shadow->gzt) { light = lightnum - 1; break; @@ -1513,33 +1520,21 @@ static void R_ProjectSprite(mobj_t *thing) #endif // uncapped/interpolation - fixed_t interpx = thing->x; - fixed_t interpy = thing->y; - fixed_t interpz = thing->z; - angle_t interpangle = thing->angle; - - // use player drawangle if player - if (thing->player) interpangle = thing->player->drawangle; + interpmobjstate_t interp = {0}; // do interpolation if (cv_frameinterpolation.value == 1 && !paused) { - interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); - interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); - interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); - if (thing->player) - { - interpangle = thing->player->drawangle; - } - else - { - interpangle = thing->angle; - } + R_InterpolateMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); } // transform the origin point - tr_x = interpx - viewx; - tr_y = interpy - viewy; + tr_x = interp.x - viewx; + tr_y = interp.y - viewy; basetz = tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance @@ -1616,7 +1611,7 @@ static void R_ProjectSprite(mobj_t *thing) if (sprframe->rotate != SRF_SINGLE || papersprite) { - ang = R_PointToAngle (interpx, interpy) - interpangle; + ang = R_PointToAngle (interp.x, interp.y) - interp.angle; if (mirrored) ang = InvAngle(ang); } @@ -1631,7 +1626,7 @@ static void R_ProjectSprite(mobj_t *thing) else { // choose a different rotation based on player view - //ang = R_PointToAngle (interpx, interpy) - interpangle; + //ang = R_PointToAngle (interp.x, interp.y) - interpangle; if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right rot = 6; // F7 slot @@ -1850,15 +1845,18 @@ static void R_ProjectSprite(mobj_t *thing) thing = thing->tracer; if (cv_frameinterpolation.value == 1 && !paused) { - interpx = thing->old_x + FixedMul(thing->x - thing->old_x, rendertimefrac); - interpy = thing->old_y + FixedMul(thing->y - thing->old_y, rendertimefrac); + R_InterpolateMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &interp); } if (! R_ThingVisible(thing)) return; - tr_x = (interpx + sort_x) - viewx; - tr_y = (interpy + sort_y) - viewy; + tr_x = (interp.x + sort_x) - viewx; + tr_y = (interp.y + sort_y) - viewy; tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); linkscale = FixedDiv(projectiony, tz); @@ -1873,8 +1871,8 @@ static void R_ProjectSprite(mobj_t *thing) } else if (splat) { - tr_x = (thing->x + sort_x) - viewx; - tr_y = (thing->y + sort_y) - viewy; + tr_x = (interp.x + sort_x) - viewx; + tr_y = (interp.y + sort_y) - viewy; sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); sortscale = FixedDiv(projectiony, sort_z); } @@ -1882,8 +1880,8 @@ static void R_ProjectSprite(mobj_t *thing) // Calculate the splat's sortscale if (splat) { - tr_x = (thing->x - sort_x) - viewx; - tr_y = (thing->y - sort_y) - viewy; + tr_x = (interp.x - sort_x) - viewx; + tr_y = (interp.y - sort_y) - viewy; sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); sortsplat = FixedDiv(projectiony, sort_z); } @@ -1894,7 +1892,7 @@ static void R_ProjectSprite(mobj_t *thing) if (x2 < portalclipstart || x1 >= portalclipend) return; - if (P_PointOnLineSide(interpx, interpy, portalclipline) != 0) + if (P_PointOnLineSide(interp.x, interp.y, portalclipline) != 0) return; } @@ -1968,7 +1966,7 @@ static void R_ProjectSprite(mobj_t *thing) { R_SkewShadowSprite(thing, thing->standingslope, groundz, patch->height, shadowscale, &spriteyscale, &sheartan); - gzt = (isflipped ? (thing->z + thing->height) : thing->z) + patch->height * spriteyscale / 2; + gzt = (isflipped ? (interp.z + thing->height) : interp.z) + patch->height * spriteyscale / 2; gz = gzt - patch->height * spriteyscale; cut |= SC_SHEAR; @@ -1983,12 +1981,12 @@ static void R_ProjectSprite(mobj_t *thing) // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned. // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course. // remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes! - gz = interpz + oldthing->height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); + gz = interp.z + oldthing->height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); gzt = gz + FixedMul(spr_height, FixedMul(spriteyscale, this_scale)); } else { - gzt = interpz + FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); + gzt = interp.z + FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale)); gz = gzt - FixedMul(spr_height, FixedMul(spriteyscale, this_scale)); } } @@ -2007,7 +2005,7 @@ static void R_ProjectSprite(mobj_t *thing) // R_GetPlaneLight won't work on sloped lights! for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { - fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interpx, interpy); + fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interp.x, interp.y); if (h <= top) { light = lightnum - 1; break; @@ -2033,7 +2031,7 @@ static void R_ProjectSprite(mobj_t *thing) if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { fixed_t top = gzt; - fixed_t bottom = thing->z; + fixed_t bottom = interp.z; if (splat) top = bottom; @@ -2057,12 +2055,12 @@ static void R_ProjectSprite(mobj_t *thing) vis->sortscale = sortscale; vis->sortsplat = sortsplat; vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15 - vis->gx = interpx; - vis->gy = interpy; + vis->gx = interp.x; + vis->gy = interp.y; vis->gz = gz; vis->gzt = gzt; vis->thingheight = thing->height; - vis->pz = interpz; + vis->pz = interp.z; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = FixedDiv(gzt - viewz, spriteyscale); vis->scalestep = scalestep; @@ -2202,21 +2200,21 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) fixed_t gz, gzt; // uncapped/interpolation - fixed_t interpx = thing->x; - fixed_t interpy = thing->y; - fixed_t interpz = thing->z; + interpmobjstate_t interp = {0}; // do interpolation if (cv_frameinterpolation.value == 1 && !paused) { - interpx = thing->old_x + FixedMul(rendertimefrac, thing->x - thing->old_x); - interpy = thing->old_y + FixedMul(rendertimefrac, thing->y - thing->old_y); - interpz = thing->old_z + FixedMul(rendertimefrac, thing->z - thing->old_z); + R_InterpolatePrecipMobjState(thing, rendertimefrac, &interp); + } + else + { + R_InterpolatePrecipMobjState(thing, FRACUNIT, &interp); } // transform the origin point - tr_x = interpx - viewx; - tr_y = interpy - viewy; + tr_x = interp.x - viewx; + tr_y = interp.y - viewy; tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance @@ -2280,13 +2278,13 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) if (x2 < portalclipstart || x1 >= portalclipend) return; - if (P_PointOnLineSide(interpx, interpy, portalclipline) != 0) + if (P_PointOnLineSide(interp.x, interp.y, portalclipline) != 0) return; } //SoM: 3/17/2000: Disregard sprites that are out of view.. - gzt = interpz + spritecachedinfo[lump].topoffset; + gzt = interp.z + spritecachedinfo[lump].topoffset; gz = gzt - spritecachedinfo[lump].height; if (thing->subsector->sector->cullheight) @@ -2299,12 +2297,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis = R_NewVisSprite(); vis->scale = vis->sortscale = yscale; //<dispoffset = 0; // Monster Iestyn: 23/11/15 - vis->gx = interpx; - vis->gy = interpy; + vis->gx = interp.x; + vis->gy = interp.y; vis->gz = gz; vis->gzt = gzt; vis->thingheight = 4*FRACUNIT; - vis->pz = interpz; + vis->pz = interp.z; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; vis->scalestep = 0; From 9c8d0a3b6f76eb9a2eb185648d55a891df4edd82 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 12 Apr 2022 20:45:49 -0500 Subject: [PATCH 018/137] Add sector plane level interpolations --- src/d_main.c | 2 + src/g_game.c | 1 + src/p_ceilng.c | 8 +++ src/p_floor.c | 14 +++++ src/p_spec.c | 16 +++++ src/p_tick.c | 5 ++ src/r_fps.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++ src/r_fps.h | 34 +++++++++++ 8 files changed, 238 insertions(+) diff --git a/src/d_main.c b/src/d_main.c index 2f564c6c8..963439d66 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -477,6 +477,7 @@ static void D_Display(void) if (!automapactive && !dedicated && cv_renderview.value) { + R_ApplyLevelInterpolators(cv_frameinterpolation.value == 1 ? rendertimefrac : FRACUNIT); PS_START_TIMING(ps_rendercalltime); if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { @@ -525,6 +526,7 @@ static void D_Display(void) V_DoPostProcessor(1, postimgtype2, postimgparam2); } PS_STOP_TIMING(ps_rendercalltime); + R_RestoreLevelInterpolators(); } if (lastdraw) diff --git a/src/g_game.c b/src/g_game.c index 8eb731b1f..6d263e302 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1830,6 +1830,7 @@ void G_DoLoadLevel(boolean resetplayer) } // Setup the level. + R_InitializeLevelInterpolators(); if (!P_LoadLevel(false, false)) // this never returns false? { // fail so reset game stuff diff --git a/src/p_ceilng.c b/src/p_ceilng.c index 50344ee0c..f1cca0825 100644 --- a/src/p_ceilng.c +++ b/src/p_ceilng.c @@ -13,6 +13,7 @@ #include "doomdef.h" #include "p_local.h" +#include "r_fps.h" #include "r_main.h" #include "s_sound.h" #include "z_zone.h" @@ -602,6 +603,9 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type) ceiling->tag = tag; ceiling->type = type; firstone = 0; + + // interpolation + R_CreateInterpolator_SectorPlane(&ceiling->thinker, sec, true); } return rtn; } @@ -679,6 +683,10 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type) ceiling->tag = tag; ceiling->type = type; + + // interpolation + R_CreateInterpolator_SectorPlane(&ceiling->thinker, sec, false); + R_CreateInterpolator_SectorPlane(&ceiling->thinker, sec, true); } return rtn; } diff --git a/src/p_floor.c b/src/p_floor.c index 5536ee913..5fcefd203 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -16,6 +16,7 @@ #include "m_random.h" #include "p_local.h" #include "p_slopes.h" +#include "r_fps.h" #include "r_state.h" #include "s_sound.h" #include "z_zone.h" @@ -573,6 +574,8 @@ void T_ContinuousFalling(continuousfall_t *faller) { faller->sector->ceilingheight = faller->ceilingstartheight; faller->sector->floorheight = faller->floorstartheight; + + R_ClearLevelInterpolatorState(&faller->thinker); } P_CheckSector(faller->sector, false); // you might think this is irrelevant. you would be wrong @@ -2010,6 +2013,9 @@ void EV_DoFloor(line_t *line, floor_e floortype) } firstone = 0; + + // interpolation + R_CreateInterpolator_SectorPlane(&dofloor->thinker, sec, false); } } @@ -2140,6 +2146,10 @@ void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed) default: break; } + + // interpolation + R_CreateInterpolator_SectorPlane(&elevator->thinker, sec, false); + R_CreateInterpolator_SectorPlane(&elevator->thinker, sec, true); } } @@ -2318,6 +2328,10 @@ void EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, boole faller->destheight = backwards ? backsector->ceilingheight : backsector->floorheight; faller->direction = backwards ? 1 : -1; + + // interpolation + R_CreateInterpolator_SectorPlane(&faller->thinker, sec, false); + R_CreateInterpolator_SectorPlane(&faller->thinker, sec, true); } // Some other 3dfloor special things Tails 03-11-2002 (Search p_mobj.c for description) diff --git a/src/p_spec.c b/src/p_spec.c index 3fe77d7a2..f6a0ce606 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -20,6 +20,7 @@ #include "p_local.h" #include "p_setup.h" // levelflats for flat animation #include "r_data.h" +#include "r_fps.h" #include "r_textures.h" #include "m_random.h" #include "p_mobj.h" @@ -5695,6 +5696,9 @@ static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, displace->speed = speed; displace->type = type; displace->reverse = reverse; + + // interpolation + R_CreateInterpolator_SectorPlane(&displace->thinker, §ors[affectee], false); } /** Adds a Mario block thinker, which changes the block's texture between blank @@ -5754,6 +5758,10 @@ static void P_AddRaiseThinker(sector_t *sec, INT16 tag, fixed_t speed, fixed_t c raise->flags |= RF_REVERSE; if (spindash) raise->flags |= RF_SPINDASH; + + // interpolation + R_CreateInterpolator_SectorPlane(&raise->thinker, sec, false); + R_CreateInterpolator_SectorPlane(&raise->thinker, sec, true); } static void P_AddAirbob(sector_t *sec, INT16 tag, fixed_t dist, boolean raise, boolean spindash, boolean dynamic) @@ -5779,6 +5787,10 @@ static void P_AddAirbob(sector_t *sec, INT16 tag, fixed_t dist, boolean raise, b airbob->flags |= RF_SPINDASH; if (dynamic) airbob->flags |= RF_DYNAMIC; + + // interpolation + R_CreateInterpolator_SectorPlane(&airbob->thinker, sec, false); + R_CreateInterpolator_SectorPlane(&airbob->thinker, sec, true); } /** Adds a thwomp thinker. @@ -5819,6 +5831,10 @@ static inline void P_AddThwompThinker(sector_t *sec, line_t *sourceline, fixed_t sec->ceilingdata = thwomp; // Start with 'resting' texture sides[sourceline->sidenum[0]].midtexture = sides[sourceline->sidenum[0]].bottomtexture; + + // interpolation + R_CreateInterpolator_SectorPlane(&thwomp->thinker, sec, false); + R_CreateInterpolator_SectorPlane(&thwomp->thinker, sec, true); } /** Adds a thinker which checks if any MF_ENEMY objects with health are in the defined area. diff --git a/src/p_tick.c b/src/p_tick.c index ca70fb926..c2f2b0579 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -764,6 +764,11 @@ void P_Ticker(boolean run) LUA_HOOK(PostThinkFrame); } + if (run) + { + R_UpdateLevelInterpolators(); + } + P_MapEnd(); // Z_CheckMemCleanup(); diff --git a/src/r_fps.c b/src/r_fps.c index 9bbae0676..b69531574 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -20,6 +20,7 @@ #include "r_plane.h" #include "p_spec.h" #include "r_state.h" +#include "z_zone.h" #ifdef HWRENDER #include "hardware/hw_main.h" // for cv_glshearing #endif @@ -40,6 +41,11 @@ viewvars_t *newview = &p1view_new; enum viewcontext_e viewcontext = VIEWCONTEXT_PLAYER1; +static levelinterpolator_t **levelinterpolators; +static size_t levelinterpolators_len; +static size_t levelinterpolators_size; + + static fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac) { return from + FixedMul(frac, to - from); @@ -194,3 +200,155 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); out->angle = mobj->angle; } + +static void AddInterpolator(levelinterpolator_t* interpolator) +{ + if (levelinterpolators_len >= levelinterpolators_size) + { + if (levelinterpolators_size == 0) + { + levelinterpolators_size = 128; + } + else + { + levelinterpolators_size *= 2; + } + + levelinterpolators = Z_ReallocAlign( + (void*) levelinterpolators, + sizeof(levelinterpolator_t*) * levelinterpolators_size, + PU_LEVEL, + NULL, + sizeof(levelinterpolator_t*) * 8 + ); + } + + levelinterpolators[levelinterpolators_len] = interpolator; + levelinterpolators_len += 1; +} + +static levelinterpolator_t *CreateInterpolator(levelinterpolator_type_e type, thinker_t *thinker) +{ + levelinterpolator_t *ret = (levelinterpolator_t*) Z_CallocAlign( + sizeof(levelinterpolator_t), + PU_LEVEL, + NULL, + sizeof(levelinterpolator_t) * 8 + ); + + ret->type = type; + ret->thinker = thinker; + + AddInterpolator(ret); + + return ret; +} + +void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, boolean ceiling) +{ + levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_SectorPlane, thinker); + interp->sectorplane.sector = sector; + interp->sectorplane.ceiling = ceiling; + if (ceiling) + { + interp->sectorplane.oldheight = interp->sectorplane.bakheight = sector->ceilingheight; + } + else + { + interp->sectorplane.oldheight = interp->sectorplane.bakheight = sector->floorheight; + } +} + +void R_InitializeLevelInterpolators(void) +{ + levelinterpolators_len = 0; + levelinterpolators_size = 0; + levelinterpolators = NULL; +} + +static void UpdateLevelInterpolatorState(levelinterpolator_t *interp) +{ + switch (interp->type) + { + case LVLINTERP_SectorPlane: + interp->sectorplane.oldheight = interp->sectorplane.bakheight; + interp->sectorplane.bakheight = interp->sectorplane.ceiling ? interp->sectorplane.sector->ceilingheight : interp->sectorplane.sector->floorheight; + break; + } +} + +void R_UpdateLevelInterpolators(void) +{ + size_t i; + + for (i = 0; i < levelinterpolators_len; i++) + { + levelinterpolator_t *interp = levelinterpolators[i]; + + UpdateLevelInterpolatorState(interp); + } +} + +void R_ClearLevelInterpolatorState(thinker_t *thinker) +{ + + size_t i; + + for (i = 0; i < levelinterpolators_len; i++) + { + levelinterpolator_t *interp = levelinterpolators[i]; + + if (interp->thinker == thinker) + { + // Do it twice to make the old state match the new + UpdateLevelInterpolatorState(interp); + UpdateLevelInterpolatorState(interp); + } + } +} + +void R_ApplyLevelInterpolators(fixed_t frac) +{ + size_t i; + + for (i = 0; i < levelinterpolators_len; i++) + { + levelinterpolator_t *interp = levelinterpolators[i]; + + switch (interp->type) + { + case LVLINTERP_SectorPlane: + if (interp->sectorplane.ceiling) + { + interp->sectorplane.sector->ceilingheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac); + } + else + { + interp->sectorplane.sector->floorheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac); + } + } + } +} + +void R_RestoreLevelInterpolators(void) +{ + size_t i; + + for (i = 0; i < levelinterpolators_len; i++) + { + levelinterpolator_t *interp = levelinterpolators[i]; + + switch (interp->type) + { + case LVLINTERP_SectorPlane: + if (interp->sectorplane.ceiling) + { + interp->sectorplane.sector->ceilingheight = interp->sectorplane.bakheight; + } + else + { + interp->sectorplane.sector->floorheight = interp->sectorplane.bakheight; + } + } + } +} diff --git a/src/r_fps.h b/src/r_fps.h index 04f44de6e..df506fb56 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -51,6 +51,27 @@ typedef struct { angle_t angle; } interpmobjstate_t; +// Level interpolators + +// The union tag for levelinterpolator_t +typedef enum { + LVLINTERP_SectorPlane, +} levelinterpolator_type_e; + +// Tagged union of a level interpolator +typedef struct levelinterpolator_s { + levelinterpolator_type_e type; + thinker_t *thinker; + union { + struct { + sector_t *sector; + fixed_t oldheight; + fixed_t bakheight; + boolean ceiling; + } sectorplane; + }; +} levelinterpolator_t; + // Interpolates the current view variables (r_state.h) against the selected view context in R_SetViewContext void R_InterpolateView(fixed_t frac); // Buffer the current new views into the old views. Call once after each real tic. @@ -64,4 +85,17 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out); // Evaluate the interpolated mobj state for the given precipmobj void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out); +void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, boolean ceiling); + +// Initialize level interpolators after a level change +void R_InitializeLevelInterpolators(void); +// Update level interpolators, storing the previous and current states. +void R_UpdateLevelInterpolators(void); +// Clear states for all level interpolators for the thinker +void R_ClearLevelInterpolatorState(thinker_t *thinker); +// Apply level interpolators to the actual game state +void R_ApplyLevelInterpolators(fixed_t frac); +// Restore level interpolators to the real game state +void R_RestoreLevelInterpolators(void); + #endif From ba110852a77327bacd748319e07839bc7dcb615c Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 12 Apr 2022 21:22:39 -0500 Subject: [PATCH 019/137] Add SectorScroll interpolator --- src/p_spec.c | 15 +++++++++++++++ src/r_fps.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/r_fps.h | 7 +++++++ 3 files changed, 71 insertions(+) diff --git a/src/p_spec.c b/src/p_spec.c index f6a0ce606..04b333628 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -7408,6 +7408,21 @@ static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT3 s->last_height = sectors[control].floorheight + sectors[control].ceilingheight; s->affectee = affectee; P_AddThinker(THINK_MAIN, &s->thinker); + + // interpolation + switch (type) + { + case sc_side: + break; + case sc_floor: + R_CreateInterpolator_SectorScroll(&s->thinker, §ors[affectee], false); + break; + case sc_ceiling: + R_CreateInterpolator_SectorScroll(&s->thinker, §ors[affectee], true); + break; + default: + break; + } } /** Initializes the scrollers. diff --git a/src/r_fps.c b/src/r_fps.c index b69531574..b672a6f0f 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -259,6 +259,23 @@ void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, bool } } +void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boolean ceiling) +{ + levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_SectorScroll, thinker); + interp->sectorscroll.sector = sector; + interp->sectorscroll.ceiling = ceiling; + if (ceiling) + { + interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs = sector->ceiling_xoffs; + interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs = sector->ceiling_yoffs; + } + else + { + interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs = sector->floor_xoffs; + interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs = sector->floor_yoffs; + } +} + void R_InitializeLevelInterpolators(void) { levelinterpolators_len = 0; @@ -274,6 +291,12 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp) interp->sectorplane.oldheight = interp->sectorplane.bakheight; interp->sectorplane.bakheight = interp->sectorplane.ceiling ? interp->sectorplane.sector->ceilingheight : interp->sectorplane.sector->floorheight; break; + case LVLINTERP_SectorScroll: + interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs; + interp->sectorscroll.bakxoffs = interp->sectorscroll.ceiling ? interp->sectorscroll.sector->ceiling_xoffs : interp->sectorscroll.sector->floor_xoffs; + interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs; + interp->sectorscroll.bakyoffs = interp->sectorscroll.ceiling ? interp->sectorscroll.sector->ceiling_yoffs : interp->sectorscroll.sector->floor_yoffs; + break; } } @@ -326,6 +349,19 @@ void R_ApplyLevelInterpolators(fixed_t frac) { interp->sectorplane.sector->floorheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac); } + break; + case LVLINTERP_SectorScroll: + if (interp->sectorscroll.ceiling) + { + interp->sectorscroll.sector->ceiling_xoffs = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac); + interp->sectorscroll.sector->ceiling_yoffs = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac); + } + else + { + interp->sectorscroll.sector->floor_xoffs = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac); + interp->sectorscroll.sector->floor_yoffs = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac); + } + break; } } } @@ -349,6 +385,19 @@ void R_RestoreLevelInterpolators(void) { interp->sectorplane.sector->floorheight = interp->sectorplane.bakheight; } + break; + case LVLINTERP_SectorScroll: + if (interp->sectorscroll.ceiling) + { + interp->sectorscroll.sector->ceiling_xoffs = interp->sectorscroll.bakxoffs; + interp->sectorscroll.sector->ceiling_yoffs = interp->sectorscroll.bakyoffs; + } + else + { + interp->sectorscroll.sector->floor_xoffs = interp->sectorscroll.bakxoffs; + interp->sectorscroll.sector->floor_yoffs = interp->sectorscroll.bakyoffs; + } + break; } } } diff --git a/src/r_fps.h b/src/r_fps.h index df506fb56..cc240ffc8 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -56,6 +56,7 @@ typedef struct { // The union tag for levelinterpolator_t typedef enum { LVLINTERP_SectorPlane, + LVLINTERP_SectorScroll, } levelinterpolator_type_e; // Tagged union of a level interpolator @@ -69,6 +70,11 @@ typedef struct levelinterpolator_s { fixed_t bakheight; boolean ceiling; } sectorplane; + struct { + sector_t *sector; + fixed_t oldxoffs, oldyoffs, bakxoffs, bakyoffs; + boolean ceiling; + } sectorscroll; }; } levelinterpolator_t; @@ -86,6 +92,7 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out); void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out); void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, boolean ceiling); +void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boolean ceiling); // Initialize level interpolators after a level change void R_InitializeLevelInterpolators(void); From 330b34ee6bcedbfb83c0b9cba9217b57b590c0b5 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 12 Apr 2022 21:35:52 -0500 Subject: [PATCH 020/137] Add SideScroll interpolator --- src/p_spec.c | 1 + src/r_fps.c | 22 ++++++++++++++++++++++ src/r_fps.h | 6 ++++++ 3 files changed, 29 insertions(+) diff --git a/src/p_spec.c b/src/p_spec.c index 04b333628..6147a8392 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -7413,6 +7413,7 @@ static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT3 switch (type) { case sc_side: + R_CreateInterpolator_SideScroll(&s->thinker, &sides[affectee]); break; case sc_floor: R_CreateInterpolator_SectorScroll(&s->thinker, §ors[affectee], false); diff --git a/src/r_fps.c b/src/r_fps.c index b672a6f0f..e42e8745d 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -276,6 +276,14 @@ void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boo } } +void R_CreateInterpolator_SideScroll(thinker_t *thinker, side_t *side) +{ + levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_SideScroll, thinker); + interp->sidescroll.side = side; + interp->sidescroll.oldtextureoffset = interp->sidescroll.baktextureoffset = side->textureoffset; + interp->sidescroll.oldrowoffset = interp->sidescroll.bakrowoffset = side->rowoffset; +} + void R_InitializeLevelInterpolators(void) { levelinterpolators_len = 0; @@ -297,6 +305,12 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp) interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs; interp->sectorscroll.bakyoffs = interp->sectorscroll.ceiling ? interp->sectorscroll.sector->ceiling_yoffs : interp->sectorscroll.sector->floor_yoffs; break; + case LVLINTERP_SideScroll: + interp->sidescroll.oldtextureoffset = interp->sidescroll.baktextureoffset; + interp->sidescroll.baktextureoffset = interp->sidescroll.side->textureoffset; + interp->sidescroll.oldrowoffset = interp->sidescroll.bakrowoffset; + interp->sidescroll.bakrowoffset = interp->sidescroll.side->rowoffset; + break; } } @@ -362,6 +376,10 @@ void R_ApplyLevelInterpolators(fixed_t frac) interp->sectorscroll.sector->floor_yoffs = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac); } break; + case LVLINTERP_SideScroll: + interp->sidescroll.side->textureoffset = R_LerpFixed(interp->sidescroll.oldtextureoffset, interp->sidescroll.baktextureoffset, frac); + interp->sidescroll.side->rowoffset = R_LerpFixed(interp->sidescroll.oldrowoffset, interp->sidescroll.bakrowoffset, frac); + break; } } } @@ -398,6 +416,10 @@ void R_RestoreLevelInterpolators(void) interp->sectorscroll.sector->floor_yoffs = interp->sectorscroll.bakyoffs; } break; + case LVLINTERP_SideScroll: + interp->sidescroll.side->textureoffset = interp->sidescroll.baktextureoffset; + interp->sidescroll.side->rowoffset = interp->sidescroll.bakrowoffset; + break; } } } diff --git a/src/r_fps.h b/src/r_fps.h index cc240ffc8..0210a24f2 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -57,6 +57,7 @@ typedef struct { typedef enum { LVLINTERP_SectorPlane, LVLINTERP_SectorScroll, + LVLINTERP_SideScroll, } levelinterpolator_type_e; // Tagged union of a level interpolator @@ -75,6 +76,10 @@ typedef struct levelinterpolator_s { fixed_t oldxoffs, oldyoffs, bakxoffs, bakyoffs; boolean ceiling; } sectorscroll; + struct { + side_t *side; + fixed_t oldtextureoffset, oldrowoffset, baktextureoffset, bakrowoffset; + } sidescroll; }; } levelinterpolator_t; @@ -93,6 +98,7 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, boolean ceiling); void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boolean ceiling); +void R_CreateInterpolator_SideScroll(thinker_t *thinker, side_t *side); // Initialize level interpolators after a level change void R_InitializeLevelInterpolators(void); From 2aa34f027390f4f774cf2a606120a5def1fd0a4f Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 12 Apr 2022 22:22:16 -0500 Subject: [PATCH 021/137] Add Polyobj interpolator --- src/p_polyobj.c | 25 ++++++++++++++++++++++ src/r_fps.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++-- src/r_fps.h | 9 ++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 6d7ef3999..a553ca235 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -24,6 +24,7 @@ #include "p_tick.h" #include "p_local.h" #include "p_polyobj.h" +#include "r_fps.h" #include "r_main.h" #include "r_state.h" #include "r_defs.h" @@ -2049,6 +2050,9 @@ boolean EV_DoPolyObjRotate(polyrotdata_t *prdata) oldpo = po; + // interpolation + R_CreateInterpolator_Polyobj(&th->thinker, po); + th->turnobjs = prdata->turnobjs; // apply action to mirroring polyobjects as well @@ -2110,6 +2114,9 @@ boolean EV_DoPolyObjMove(polymovedata_t *pmdata) oldpo = po; + // interpolation + R_CreateInterpolator_Polyobj(&th->thinker, po); + // apply action to mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) @@ -2177,6 +2184,9 @@ boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) th->continuous = false; } + // interpolation + R_CreateInterpolator_Polyobj(&th->thinker, po); + th->pointnum = first->health; return true; @@ -2225,6 +2235,9 @@ static void Polyobj_doSlideDoor(polyobj_t *po, polydoordata_t *doordata) oldpo = po; + // interpolation + R_CreateInterpolator_Polyobj(&th->thinker, po); + // start action on mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) @@ -2265,6 +2278,9 @@ static void Polyobj_doSwingDoor(polyobj_t *po, polydoordata_t *doordata) oldpo = po; + // interpolation + R_CreateInterpolator_Polyobj(&th->thinker, po); + // start action on mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) @@ -2336,6 +2352,9 @@ boolean EV_DoPolyObjDisplace(polydisplacedata_t *prdata) oldpo = po; + // interpolation + R_CreateInterpolator_Polyobj(&th->thinker, po); + // apply action to mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) @@ -2382,6 +2401,9 @@ boolean EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata) oldpo = po; + // interpolation + R_CreateInterpolator_Polyobj(&th->thinker, po); + // apply action to mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) @@ -2486,6 +2508,9 @@ boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata) oldpo = po; + // interpolation + R_CreateInterpolator_Polyobj(&th->thinker, po); + // apply action to mirroring polyobjects as well start = 0; while ((po = Polyobj_GetChild(oldpo, &start))) diff --git a/src/r_fps.c b/src/r_fps.c index e42e8745d..d2a31a6e6 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -284,6 +284,24 @@ void R_CreateInterpolator_SideScroll(thinker_t *thinker, side_t *side) interp->sidescroll.oldrowoffset = interp->sidescroll.bakrowoffset = side->rowoffset; } +void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj) +{ + levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_Polyobj, thinker); + interp->polyobj.polyobj = polyobj; + interp->polyobj.vertices_size = polyobj->numVertices; + + interp->polyobj.oldvertices = Z_CallocAlign(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL, 32); + interp->polyobj.bakvertices = Z_CallocAlign(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL, 32); + for (size_t i = 0; i < polyobj->numVertices; i++) + { + interp->polyobj.oldvertices[i * 2 ] = interp->polyobj.bakvertices[i * 2 ] = polyobj->vertices[i]->x; + interp->polyobj.oldvertices[i * 2 + 1] = interp->polyobj.bakvertices[i * 2 + 1] = polyobj->vertices[i]->y; + } + + interp->polyobj.oldcx = interp->polyobj.bakcx = polyobj->centerPt.x; + interp->polyobj.oldcy = interp->polyobj.bakcy = polyobj->centerPt.y; +} + void R_InitializeLevelInterpolators(void) { levelinterpolators_len = 0; @@ -293,6 +311,8 @@ void R_InitializeLevelInterpolators(void) static void UpdateLevelInterpolatorState(levelinterpolator_t *interp) { + size_t i; + switch (interp->type) { case LVLINTERP_SectorPlane: @@ -311,6 +331,19 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp) interp->sidescroll.oldrowoffset = interp->sidescroll.bakrowoffset; interp->sidescroll.bakrowoffset = interp->sidescroll.side->rowoffset; break; + case LVLINTERP_Polyobj: + for (i = 0; i < interp->polyobj.vertices_size; i++) + { + interp->polyobj.oldvertices[i * 2 ] = interp->polyobj.bakvertices[i * 2 ]; + interp->polyobj.oldvertices[i * 2 + 1] = interp->polyobj.bakvertices[i * 2 + 1]; + interp->polyobj.bakvertices[i * 2 ] = interp->polyobj.polyobj->vertices[i]->x; + interp->polyobj.bakvertices[i * 2 + 1] = interp->polyobj.polyobj->vertices[i]->y; + } + interp->polyobj.oldcx = interp->polyobj.bakcx; + interp->polyobj.oldcy = interp->polyobj.bakcy; + interp->polyobj.bakcx = interp->polyobj.polyobj->centerPt.x; + interp->polyobj.bakcy = interp->polyobj.polyobj->centerPt.y; + break; } } @@ -346,7 +379,7 @@ void R_ClearLevelInterpolatorState(thinker_t *thinker) void R_ApplyLevelInterpolators(fixed_t frac) { - size_t i; + size_t i, ii; for (i = 0; i < levelinterpolators_len; i++) { @@ -380,13 +413,22 @@ void R_ApplyLevelInterpolators(fixed_t frac) interp->sidescroll.side->textureoffset = R_LerpFixed(interp->sidescroll.oldtextureoffset, interp->sidescroll.baktextureoffset, frac); interp->sidescroll.side->rowoffset = R_LerpFixed(interp->sidescroll.oldrowoffset, interp->sidescroll.bakrowoffset, frac); break; + case LVLINTERP_Polyobj: + for (ii = 0; ii < interp->polyobj.vertices_size; ii++) + { + interp->polyobj.polyobj->vertices[ii]->x = R_LerpFixed(interp->polyobj.oldvertices[ii * 2 ], interp->polyobj.bakvertices[ii * 2 ], frac); + interp->polyobj.polyobj->vertices[ii]->y = R_LerpFixed(interp->polyobj.oldvertices[ii * 2 + 1], interp->polyobj.bakvertices[ii * 2 + 1], frac); + } + interp->polyobj.polyobj->centerPt.x = R_LerpFixed(interp->polyobj.oldcx, interp->polyobj.bakcx, frac); + interp->polyobj.polyobj->centerPt.y = R_LerpFixed(interp->polyobj.oldcy, interp->polyobj.bakcy, frac); + break; } } } void R_RestoreLevelInterpolators(void) { - size_t i; + size_t i, ii; for (i = 0; i < levelinterpolators_len; i++) { @@ -420,6 +462,15 @@ void R_RestoreLevelInterpolators(void) interp->sidescroll.side->textureoffset = interp->sidescroll.baktextureoffset; interp->sidescroll.side->rowoffset = interp->sidescroll.bakrowoffset; break; + case LVLINTERP_Polyobj: + for (ii = 0; ii < interp->polyobj.vertices_size; ii++) + { + interp->polyobj.polyobj->vertices[ii]->x = interp->polyobj.bakvertices[ii * 2 ]; + interp->polyobj.polyobj->vertices[ii]->y = interp->polyobj.bakvertices[ii * 2 + 1]; + } + interp->polyobj.polyobj->centerPt.x = interp->polyobj.bakcx; + interp->polyobj.polyobj->centerPt.y = interp->polyobj.bakcy; + break; } } } diff --git a/src/r_fps.h b/src/r_fps.h index 0210a24f2..af9baa962 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -58,6 +58,7 @@ typedef enum { LVLINTERP_SectorPlane, LVLINTERP_SectorScroll, LVLINTERP_SideScroll, + LVLINTERP_Polyobj, } levelinterpolator_type_e; // Tagged union of a level interpolator @@ -80,6 +81,13 @@ typedef struct levelinterpolator_s { side_t *side; fixed_t oldtextureoffset, oldrowoffset, baktextureoffset, bakrowoffset; } sidescroll; + struct { + polyobj_t *polyobj; + fixed_t *oldvertices; + fixed_t *bakvertices; + size_t vertices_size; + fixed_t oldcx, oldcy, bakcx, bakcy; + } polyobj; }; } levelinterpolator_t; @@ -99,6 +107,7 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, boolean ceiling); void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boolean ceiling); void R_CreateInterpolator_SideScroll(thinker_t *thinker, side_t *side); +void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj); // Initialize level interpolators after a level change void R_InitializeLevelInterpolators(void); From 3e5cec7e725fed345f33146927af0587ec39d687 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 12 Apr 2022 22:32:15 -0500 Subject: [PATCH 022/137] Intialize interpolator list at a better time --- src/g_game.c | 1 - src/p_setup.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/g_game.c b/src/g_game.c index 6d263e302..8eb731b1f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1830,7 +1830,6 @@ void G_DoLoadLevel(boolean resetplayer) } // Setup the level. - R_InitializeLevelInterpolators(); if (!P_LoadLevel(false, false)) // this never returns false? { // fail so reset game stuff diff --git a/src/p_setup.c b/src/p_setup.c index 547ad4575..65e7b5886 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4373,6 +4373,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) Patch_FreeTag(PU_PATCH_ROTATED); Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1); + R_InitializeLevelInterpolators(); + P_InitThinkers(); P_InitCachedActions(); From 5fda1b297f77705d16a73d7db8c73be18ce6f06a Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 12 Apr 2022 22:39:40 -0500 Subject: [PATCH 023/137] Delete interpolators associated with thinkers --- src/p_tick.c | 1 + src/r_fps.c | 20 ++++++++++++++++++++ src/r_fps.h | 2 ++ 3 files changed, 23 insertions(+) diff --git a/src/p_tick.c b/src/p_tick.c index c2f2b0579..e244de1c6 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -255,6 +255,7 @@ void P_RemoveThinkerDelayed(thinker_t *thinker) * thinker->prev->next = thinker->next */ (next->prev = currentthinker = thinker->prev)->next = next; + R_DestroyLevelInterpolators(thinker); Z_Free(thinker); } diff --git a/src/r_fps.c b/src/r_fps.c index d2a31a6e6..559520c5d 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -474,3 +474,23 @@ void R_RestoreLevelInterpolators(void) } } } + +void R_DestroyLevelInterpolators(thinker_t *thinker) +{ + size_t i; + + for (i = 0; i < levelinterpolators_len; i++) + { + levelinterpolator_t *interp = levelinterpolators[i]; + + if (interp->thinker == thinker) + { + // Swap the tail of the level interpolators to this spot + levelinterpolators[i] = levelinterpolators[levelinterpolators_len - 1]; + levelinterpolators_len -= 1; + + Z_Free(interp); + i -= 1; + } + } +} diff --git a/src/r_fps.h b/src/r_fps.h index af9baa962..0e10cf5e6 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -119,5 +119,7 @@ void R_ClearLevelInterpolatorState(thinker_t *thinker); void R_ApplyLevelInterpolators(fixed_t frac); // Restore level interpolators to the real game state void R_RestoreLevelInterpolators(void); +// Destroy interpolators associated with a thinker +void R_DestroyLevelInterpolators(thinker_t *thinker); #endif From ab7c2dfb3d8c6f88032b304af45d7bf26a703da1 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 12 Apr 2022 22:54:56 -0500 Subject: [PATCH 024/137] Interpolate mobj angles and player drawangle --- src/d_player.h | 1 + src/p_mobj.c | 7 +++++++ src/p_mobj.h | 2 ++ src/r_fps.c | 6 +++--- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 755926480..0111083d0 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -382,6 +382,7 @@ typedef struct player_s // fun thing for player sprite angle_t drawangle; + angle_t old_drawangle; // player's ring count INT16 rings; diff --git a/src/p_mobj.c b/src/p_mobj.c index d9910b1ee..90707eae5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -902,6 +902,12 @@ void P_ResetInterpolationState(mobj_t *mobj) mobj->old_x = mobj->x; mobj->old_y = mobj->y; mobj->old_z = mobj->z; + mobj->old_angle = mobj->angle; + + if (mobj->player) + { + mobj->player->old_drawangle = mobj->player->drawangle; + } } // @@ -914,6 +920,7 @@ void P_ResetPrecipitationInterpolationState(precipmobj_t *mobj) mobj->old_x = mobj->x; mobj->old_y = mobj->y; mobj->old_z = mobj->z; + mobj->old_angle = mobj->angle; } // diff --git a/src/p_mobj.h b/src/p_mobj.h index 7f2736801..9975075a1 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -287,6 +287,7 @@ typedef struct mobj_s // More drawing info: to determine current sprite. angle_t angle, pitch, roll; // orientation + angle_t old_angle; angle_t rollangle; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h @@ -415,6 +416,7 @@ typedef struct precipmobj_s // More drawing info: to determine current sprite. angle_t angle, pitch, roll; // orientation + angle_t old_angle; angle_t rollangle; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h diff --git a/src/r_fps.c b/src/r_fps.c index 559520c5d..819df0325 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -185,11 +185,11 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) if (mobj->player) { - out->angle = mobj->player->drawangle; + out->angle = R_LerpAngle(mobj->player->old_drawangle, mobj->player->drawangle, frac); } else { - out->angle = mobj->angle; + out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); } } @@ -198,7 +198,7 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); - out->angle = mobj->angle; + out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); } static void AddInterpolator(levelinterpolator_t* interpolator) From ca8698d13eb7a9cf03b9cee36108a257ba730f24 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 12 Apr 2022 23:06:14 -0500 Subject: [PATCH 025/137] Interpolate HWR_DrawModel --- src/hardware/hw_md2.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index e765656ca..7bc218d14 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -30,6 +30,7 @@ #include "hw_md2.h" #include "../d_main.h" #include "../r_bsp.h" +#include "../r_fps.h" #include "../r_main.h" #include "../m_misc.h" #include "../w_wad.h" @@ -1341,6 +1342,16 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) angle_t ang; INT32 mod; float finalscale; + interpmobjstate_t interp; + + if (cv_frameinterpolation.value == 1 && !paused) + { + R_InterpolateMobjState(spr->mobj, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(spr->mobj, FRACUNIT, &interp); + } // Apparently people don't like jump frames like that, so back it goes //if (tics > durs) @@ -1564,13 +1575,13 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) #endif //Hurdler: it seems there is still a small problem with mobj angle - p.x = FIXED_TO_FLOAT(spr->mobj->x); - p.y = FIXED_TO_FLOAT(spr->mobj->y)+md2->offset; + p.x = FIXED_TO_FLOAT(interp.x); + p.y = FIXED_TO_FLOAT(interp.y)+md2->offset; if (flip) - p.z = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height); + p.z = FIXED_TO_FLOAT(interp.z + spr->mobj->height); else - p.z = FIXED_TO_FLOAT(spr->mobj->z); + p.z = FIXED_TO_FLOAT(interp.z); if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) sprdef = &((skin_t *)spr->mobj->skin)->sprites[spr->mobj->sprite2]; @@ -1581,16 +1592,13 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) if (sprframe->rotate || papersprite) { - fixed_t anglef = AngleFixed(spr->mobj->angle); - - if (spr->mobj->player) - anglef = AngleFixed(spr->mobj->player->drawangle); + fixed_t anglef = AngleFixed(interp.angle); p.angley = FIXED_TO_FLOAT(anglef); } else { - const fixed_t anglef = AngleFixed((R_PointToAngle(spr->mobj->x, spr->mobj->y))-ANGLE_180); + const fixed_t anglef = AngleFixed((R_PointToAngle(interp.x, interp.y))-ANGLE_180); p.angley = FIXED_TO_FLOAT(anglef); } @@ -1612,7 +1620,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) p.rotaxis = (UINT8)(sprinfo->pivot[(spr->mobj->frame & FF_FRAMEMASK)].rotaxis); // for NiGHTS specifically but should work everywhere else - ang = R_PointToAngle (spr->mobj->x, spr->mobj->y) - (spr->mobj->player ? spr->mobj->player->drawangle : spr->mobj->angle); + ang = R_PointToAngle (interp.x, interp.y) - interp.angle; if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right p.rollflip = 1; else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left From 8fb939df7999a4f73535fc7fed6afa2c95768fe9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 24 Dec 2021 11:30:19 -0500 Subject: [PATCH 026/137] Add functions to handle interpolation Much less code duplication --- src/r_fps.c | 20 ++++++++++++++++++++ src/r_fps.h | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/src/r_fps.c b/src/r_fps.c index 819df0325..863e9613a 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -177,6 +177,26 @@ void R_SetViewContext(enum viewcontext_e _viewcontext) } } +fixed_t R_InterpolateFixed(fixed_t from, fixed_t to) +{ + if (cv_frameinterpolation.value == 0) + { + return to; + } + + return (R_LerpFixed(from, to, rendertimefrac)); +} + +angle_t R_InterpolateAngle(angle_t from, angle_t to) +{ + if (cv_frameinterpolation.value == 0) + { + return to; + } + + return (R_LerpAngle(from, to, rendertimefrac)); +} + void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) { out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); diff --git a/src/r_fps.h b/src/r_fps.h index 0e10cf5e6..aa6213ae3 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -99,6 +99,10 @@ void R_UpdateViewInterpolation(void); void R_ResetViewInterpolation(void); // Set the current view context (the viewvars pointed to by newview) void R_SetViewContext(enum viewcontext_e _viewcontext); + +fixed_t R_InterpolateFixed(fixed_t from, fixed_t to); +angle_t R_InterpolateAngle(angle_t from, angle_t to); + // Evaluate the interpolated mobj state for the given mobj void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out); // Evaluate the interpolated mobj state for the given precipmobj From e4930535f344d8203ade9242930f5e91c4357c85 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 24 Dec 2021 12:45:51 -0500 Subject: [PATCH 027/137] P_InitAngle, to fix angle interpolation on spawning objects --- src/p_enemy.c | 69 +++++++++++++++++++++++------------------------ src/p_inter.c | 10 +++---- src/p_local.h | 3 +++ src/p_map.c | 24 +++++++++++++++++ src/p_mobj.c | 72 ++++++++++++++++++++++++++++---------------------- src/p_mobj.h | 2 +- src/p_saveg.c | 20 +++++++------- src/p_spec.c | 2 +- src/p_telept.c | 4 +-- src/p_user.c | 2 +- src/r_fps.c | 5 ++++ src/r_fps.h | 2 ++ 12 files changed, 130 insertions(+), 85 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index 87aa5ff2f..40aab9ec1 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -1406,7 +1406,7 @@ void A_StatueBurst(mobj_t *actor) if (!locvar1 || !(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1))) return; - new->angle = actor->angle; + P_InitAngle(new, actor->angle); P_SetTarget(&new->target, actor->target); if (locvar2) P_SetMobjState(new, (statenum_t)locvar2); @@ -2700,8 +2700,8 @@ void A_LobShot(mobj_t *actor) P_SetTarget(&shot->target, actor); // where it came from - shot->angle = an = actor->angle; - an >>= ANGLETOFINESHIFT; + P_InitAngle(shot, actor->angle); + an = actor->angle >> ANGLETOFINESHIFT; dist = P_AproxDistance(actor->target->x - shot->x, actor->target->y - shot->y); @@ -3067,7 +3067,7 @@ void A_Boss1Laser(mobj_t *actor) S_StartSound(actor, mobjinfo[locvar1].seesound); point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); - point->angle = actor->angle; + P_InitAngle(point, actor->angle); point->fuse = dur+1; P_SetTarget(&point->target, actor->target); P_SetTarget(&actor->target, point); @@ -3077,7 +3077,7 @@ void A_Boss1Laser(mobj_t *actor) point = P_SpawnMobj(x, y, z, locvar1); P_SetTarget(&point->target, actor); - point->angle = actor->angle; + P_InitAngle(point, actor->angle); speed = point->radius; point->momz = FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT), speed); point->momx = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(point->angle>>ANGLETOFINESHIFT), speed)); @@ -3086,7 +3086,7 @@ void A_Boss1Laser(mobj_t *actor) for (i = 0; i < 256; i++) { mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type); - mo->angle = point->angle; + P_InitAngle(mo, point->angle); mo->color = LASERCOLORS[((UINT8)(i + 3*dur) >> 2) % sizeof(LASERCOLORS)]; // codeing P_UnsetThingPosition(mo); mo->flags = MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY; @@ -3118,7 +3118,7 @@ void A_Boss1Laser(mobj_t *actor) if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1 && dur & 1) { point = P_SpawnMobj(x, y, floorz, MT_EGGMOBILE_FIRE); - point->angle = actor->angle; + P_InitAngle(point, actor->angle); point->destscale = actor->scale; P_SetScale(point, point->destscale); P_SetTarget(&point->target, actor); @@ -3970,7 +3970,7 @@ bossjustdie: P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; + P_InitAngle(mo2, mo->angle); P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); P_SetObjectMomZ(mo2, 4*FRACUNIT, false); P_SetMobjState(mo2, S_BOSSEGLZ1); @@ -3979,7 +3979,7 @@ bossjustdie: P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; + P_InitAngle(mo2, mo->angle); P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); P_SetObjectMomZ(mo2, 4*FRACUNIT, false); P_SetMobjState(mo2, S_BOSSEGLZ2); @@ -3991,7 +3991,7 @@ bossjustdie: P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle = mo->angle; + P_InitAngle(mo2, mo->angle); P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); P_SetObjectMomZ(mo2, 4*FRACUNIT, false); P_SetMobjState(mo2, S_BOSSTANK1); @@ -4000,7 +4000,7 @@ bossjustdie: P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle = mo->angle; + P_InitAngle(mo2, mo->angle); P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); P_SetObjectMomZ(mo2, 4*FRACUNIT, false); P_SetMobjState(mo2, S_BOSSTANK2); @@ -4008,7 +4008,7 @@ bossjustdie: mo2 = P_SpawnMobjFromMobj(mo, 0, 0, mobjinfo[MT_EGGMOBILE2].height + (32<angle = mo->angle; + P_InitAngle(mo2, mo->angle); P_SetObjectMomZ(mo2, 4*FRACUNIT, false); mo2->momz += mo->momz; P_SetMobjState(mo2, S_BOSSSPIGOT); @@ -4017,7 +4017,7 @@ bossjustdie: case MT_EGGMOBILE3: { mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSJUNK); - mo2->angle = mo->angle; + P_InitAngle(mo2, mo->angle); P_SetMobjState(mo2, S_BOSSSEBH1); } break; @@ -4091,7 +4091,8 @@ bossjustdie: pole->tracer->flags |= MF_NOCLIPTHING; P_SetScale(pole, (pole->destscale = 2*FRACUNIT)); P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT)); - pole->angle = pole->tracer->angle = mo->tracer->angle; + P_InitAngle(pole, mo->tracer->angle); + P_InitAngle(pole->tracer, mo->tracer->angle); pole->tracer->tracer->angle = pole->angle - ANGLE_90; pole->momx = P_ReturnThrustX(pole, pole->angle, speed); pole->momy = P_ReturnThrustY(pole, pole->angle, speed); @@ -6254,7 +6255,7 @@ void A_RockSpawn(mobj_t *actor) mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FALLINGROCK); P_SetMobjState(mo, mobjinfo[type].spawnstate); - mo->angle = R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y); + P_InitAngle(mo, R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y)); P_InstaThrust(mo, mo->angle, dist + randomoomph); mo->momz = dist + randomoomph; @@ -8312,7 +8313,7 @@ void A_Boss3ShockThink(mobj_t *actor) snew->momx = (actor->momx + snext->momx) >> 1; snew->momy = (actor->momy + snext->momy) >> 1; snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed? - snew->angle = (actor->angle + snext->angle) >> 1; + P_InitAngle(snew, (actor->angle + snext->angle) >> 1); P_SetTarget(&snew->target, actor->target); snew->fuse = actor->fuse; @@ -8468,7 +8469,7 @@ void A_SpawnObjectAbsolute(mobj_t *actor) mo = P_SpawnMobj(x<angle = actor->angle; + P_InitAngle(mo, actor->angle); if (actor->eflags & MFE_VERTICALFLIP) mo->flags2 |= MF2_OBJECTFLIP; @@ -8510,7 +8511,7 @@ void A_SpawnObjectRelative(mobj_t *actor) (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[type].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), type); // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn - mo->angle = actor->angle; + P_InitAngle(mo, actor->angle); if (actor->eflags & MFE_VERTICALFLIP) mo->flags2 |= MF2_OBJECTFLIP; @@ -9220,7 +9221,7 @@ void A_BossJetFume(mobj_t *actor) P_SetScale(filler, filler->destscale); if (actor->eflags & MFE_VERTICALFLIP) filler->flags2 |= MF2_OBJECTFLIP; - filler->angle = actor->angle - ANGLE_180; + P_InitAngle(filler, actor->angle - ANGLE_180); P_SetTarget(&actor->tracer, filler); }*/ @@ -10982,7 +10983,7 @@ void A_TrapShot(mobj_t *actor) S_StartSound(missile, missile->info->seesound); P_SetTarget(&missile->target, actor); - missile->angle = actor->angle; + P_InitAngle(missile, actor->angle); speed = FixedMul(missile->info->speed, missile->scale); @@ -11561,7 +11562,7 @@ void A_BrakLobShot(mobj_t *actor) S_StartSound(shot, shot->info->seesound); P_SetTarget(&shot->target, actor); // where it came from - shot->angle = actor->angle; + P_InitAngle(shot, actor->angle); // Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle. shot->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(shot->angle >> ANGLETOFINESHIFT)); @@ -11628,7 +11629,7 @@ void A_NapalmScatter(mobj_t *actor) mo = P_SpawnMobj(actor->x, actor->y, actor->z, typeOfShot); P_SetTarget(&mo->target, actor->target); // Transfer target so Brak doesn't hit himself like an idiot - mo->angle = fa << ANGLETOFINESHIFT; + P_InitAngle(mo, fa << ANGLETOFINESHIFT); mo->momx = FixedMul(FINECOSINE(fa),vx); mo->momy = FixedMul(FINESINE(fa),vx); mo->momz = vy; @@ -11652,7 +11653,7 @@ void A_SpawnFreshCopy(mobj_t *actor) newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type); newObject->flags2 = actor->flags2 & MF2_AMBUSH; - newObject->angle = actor->angle; + P_InitAngle(newObject, actor->angle); newObject->color = actor->color; P_SetTarget(&newObject->target, actor->target); P_SetTarget(&newObject->tracer, actor->tracer); @@ -11686,7 +11687,7 @@ mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz } flicky = P_SpawnMobjFromMobj(actor, offsx, offsy, 0, flickytype); - flicky->angle = actor->angle; + P_InitAngle(flicky, actor->angle); if (flickytype == MT_SEED) flicky->z += P_MobjFlip(actor)*(actor->height - flicky->height)/2; @@ -11836,7 +11837,7 @@ void A_FlickyCenter(mobj_t *actor) else if (actor->flags & MF_SLIDEME) // aimless { actor->tracer->fuse = 0; // less than 2*TICRATE means move aimlessly. - actor->tracer->angle = P_RandomKey(180)*ANG2; + P_InitAngle(actor->tracer, P_RandomKey(180)*ANG2); } else //orbit actor->tracer->fuse = FRACUNIT; @@ -12532,7 +12533,7 @@ void A_ConnectToGround(mobj_t *actor) { work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1); if (work) - work->angle = ang; + P_InitAngle(work, ang); ang += ANGLE_90; workz += workh; } @@ -12578,7 +12579,7 @@ void A_SpawnParticleRelative(mobj_t *actor) (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[MT_PARTICLE].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), MT_PARTICLE); // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn - mo->angle = actor->angle; + P_InitAngle(mo, actor->angle); if (actor->eflags & MFE_VERTICALFLIP) mo->flags2 |= MF2_OBJECTFLIP; @@ -13325,7 +13326,7 @@ void A_Boss5MakeJunk(mobj_t *actor) broked->fuse = TICRATE; else broked->fuse = (((locvar2 & 1) ? 4 : 2)*TICRATE)/3; - broked->angle = ang; + P_InitAngle(broked, ang); P_InstaThrust(broked, ang, ((locvar2 & 2) ? 8 : 5)*actor->scale); P_SetObjectMomZ(broked, (((locvar2) ? 4 : 0) + P_RandomRange(2, 5))< 0) @@ -13404,7 +13405,7 @@ static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fi mobjtype ); - dust->angle = ang*i + ANGLE_90; + P_InitAngle(dust, ang*i + ANGLE_90); P_SetScale(dust, FixedMul(initscale, scale)); dust->destscale = FixedMul(4*FRACUNIT + P_RandomFixed(), scale); dust->scalespeed = scale/24; @@ -13758,7 +13759,7 @@ static mobj_t *P_TrainSeg(mobj_t *src, fixed_t x, fixed_t y, fixed_t z, angle_t s->fuse = 16*TICRATE; s->sprite = spr; s->frame = frame|FF_PAPERSPRITE; - s->angle = ang; + P_InitAngle(s, ang); P_Thrust(s, src->angle, 7*FRACUNIT); return s; } @@ -14130,7 +14131,7 @@ void A_SaloonDoorSpawn(mobj_t *actor) // One door... if (!(door = P_SpawnMobjFromMobj(actor, c, s, 0, locvar1))) return; - door->angle = ang + ANGLE_180; + P_InitAngle(door, ang + ANGLE_180); door->extravalue1 = AngleFixed(door->angle); // Origin angle door->extravalue2 = 0; // Angular speed P_SetTarget(&door->tracer, actor); // Origin door @@ -14138,7 +14139,7 @@ void A_SaloonDoorSpawn(mobj_t *actor) // ...two door! if (!(door = P_SpawnMobjFromMobj(actor, -c, -s, 0, locvar1))) return; - door->angle = ang; + P_InitAngle(door, ang); door->extravalue1 = AngleFixed(door->angle); // Origin angle door->extravalue2 = 0; // Angular speed P_SetTarget(&door->tracer, actor); // Origin door @@ -14334,7 +14335,7 @@ void A_SpawnPterabytes(mobj_t *actor) c = FINECOSINE(fa); s = FINESINE(fa); waypoint = P_SpawnMobjFromMobj(actor, FixedMul(c, rad), FixedMul(s, rad), 0, MT_PTERABYTEWAYPOINT); - waypoint->angle = ang + ANGLE_90; + P_InitAngle(waypoint, ang + ANGLE_90); P_SetTarget(&waypoint->tracer, actor); ptera = P_SpawnMobjFromMobj(waypoint, 0, 0, 0, MT_PTERABYTE); ptera->angle = waypoint->angle; @@ -14514,7 +14515,7 @@ void A_DragonbomberSpawn(mobj_t *actor) segment = P_SpawnMobjFromMobj(mo, x, y, 0, MT_DRAGONTAIL); P_SetTarget(&segment->target, mo); P_SetTarget(&mo->tracer, segment); - segment->angle = mo->angle; + P_InitAngle(segment, mo->angle); mo = segment; } for (i = 0; i < 2; i++) // spawn wings diff --git a/src/p_inter.c b/src/p_inter.c index 582cdb0d0..56ef23578 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2749,7 +2749,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget mo->angle = FixedAngle((P_RandomKey(36)*10)<angle = mo->angle; + P_InitAngle(mo2, mo->angle); P_SetMobjState(mo2, S_BOSSSEBH2); if (++i == 2) // we've already removed 2 of these, let's stop now @@ -2852,7 +2852,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);\ P_SetMobjState(chunk, target->info->xdeathstate);\ chunk->health = 0;\ - chunk->angle = angtweak;\ + P_InitAngle(chunk, angtweak);\ P_UnsetThingPosition(chunk);\ chunk->flags = MF_NOCLIP;\ chunk->x += xmov;\ @@ -2874,7 +2874,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE); P_SetMobjState(chunk, target->info->deathstate); chunk->health = 0; - chunk->angle = ang + ANGLE_180; + P_InitAngle(chunk, ang + ANGLE_180); P_UnsetThingPosition(chunk); chunk->flags = MF_NOCLIP; chunk->x -= xoffs; @@ -2920,7 +2920,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);\ P_SetMobjState(chunk, target->info->xdeathstate);\ chunk->health = 0;\ - chunk->angle = target->angle;\ + P_InitAngle(chunk, target->angle);\ P_UnsetThingPosition(chunk);\ chunk->flags = MF_NOCLIP;\ chunk->x += xmov - forwardxoffs;\ @@ -2946,7 +2946,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget P_SetMobjState(chunk, target->info->deathstate); chunk->health = 0; - chunk->angle = target->angle; + P_InitAngle(chunk, target->angle); P_UnsetThingPosition(chunk); chunk->flags = MF_NOCLIP; chunk->x += forwardxoffs - xoffs; diff --git a/src/p_local.h b/src/p_local.h index ba8cbe166..ec7e65b71 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -415,6 +415,9 @@ boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_Move(mobj_t *actor, fixed_t speed); boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); +void P_InitAngle(mobj_t *thing, angle_t newValue); +void P_InitPitch(mobj_t *thing, angle_t newValue); +void P_InitRoll(mobj_t *thing, angle_t newValue); void P_SlideMove(mobj_t *mo); void P_BounceMove(mobj_t *mo); boolean P_CheckSight(mobj_t *t1, mobj_t *t2); diff --git a/src/p_map.c b/src/p_map.c index 145f9bbe9..1f02123d5 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -108,6 +108,30 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) return true; } +// +// P_InitAngle - Change an object's angle, including interp values. +// +void P_InitAngle(mobj_t *thing, angle_t newValue) +{ + thing->angle = thing->old_angle = newValue; +} + +// +// P_InitPitch - Change an object's pitch, including interp values. +// +void P_InitPitch(mobj_t *thing, angle_t newValue) +{ + thing->pitch = thing->old_pitch = newValue; +} + +// +// P_InitRoll - Change an object's roll, including interp values. +// +void P_InitRoll(mobj_t *thing, angle_t newValue) +{ + thing->roll = thing->old_roll = newValue; +} + // ========================================================================= // MOVEMENT ITERATOR FUNCTIONS // ========================================================================= diff --git a/src/p_mobj.c b/src/p_mobj.c index 90707eae5..57af599cf 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -903,6 +903,8 @@ void P_ResetInterpolationState(mobj_t *mobj) mobj->old_y = mobj->y; mobj->old_z = mobj->z; mobj->old_angle = mobj->angle; + mobj->old_pitch = mobj->pitch; + mobj->old_roll = mobj->roll; if (mobj->player) { @@ -6372,7 +6374,7 @@ void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 numb mobj->z -= mobj->height>>1; // change angle - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, x, y); + P_InitAngle(mobj, R_PointToAngle2(mobj->x, mobj->y, x, y)); // change slope dist = P_AproxDistance(P_AproxDistance(x - mobj->x, y - mobj->y), z - mobj->z); @@ -7256,7 +7258,7 @@ static void P_FlameJetSceneryThink(mobj_t *mobj) flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); P_SetMobjState(flame, S_FLAMEJETFLAME4); - flame->angle = mobj->angle; + P_InitAngle(flame, mobj->angle); if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side flame->momz = mobj->fuse << (FRACBITS - 2); @@ -10730,7 +10732,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_CRUSHSTACEAN: { mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CRUSHCLAW); - bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);; + P_InitAngle(bigmeatyclaw, mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270)); P_SetTarget(&mobj->tracer, bigmeatyclaw); P_SetTarget(&bigmeatyclaw->tracer, mobj); mobj->reactiontime >>= 1; @@ -10739,7 +10741,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BANPYURA: { mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_BANPSPRING); - bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);; + P_InitAngle(bigmeatyclaw, mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270)); P_SetTarget(&mobj->tracer, bigmeatyclaw); P_SetTarget(&bigmeatyclaw->tracer, mobj); mobj->reactiontime >>= 1; @@ -10861,7 +10863,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_MINECARTEND: P_SetTarget(&mobj->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID)); - mobj->tracer->angle = mobj->angle + ANGLE_90; + P_InitAngle(mobj->tracer, mobj->angle + ANGLE_90); break; case MT_TORCHFLOWER: { @@ -11492,7 +11494,7 @@ void P_SpawnPlayer(INT32 playernum) mobj = P_SpawnMobj(0, 0, 0, MT_PLAYER); (mobj->player = p)->mo = mobj; - mobj->angle = 0; + P_InitAngle(mobj, 0); // set color translations for player sprites mobj->color = p->skincolor; @@ -11560,6 +11562,12 @@ void P_AfterPlayerSpawn(INT32 playernum) player_t *p = &players[playernum]; mobj_t *mobj = p->mo; + // Update interpolation + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; + mobj->old_angle = mobj->angle; + P_SetPlayerAngle(p, mobj->angle); p->viewheight = 41*p->height/48; @@ -12345,7 +12353,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) spawnee->friction = mroll;\ spawnee->movefactor = mwidthset;\ spawnee->movecount = dist;\ - spawnee->angle = myaw;\ + P_InitAngle(spawnee, myaw);\ spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\ spawnee->flags2 |= (mflags2apply|moreflags2);\ spawnee->eflags |= meflagsapply;\ @@ -12663,29 +12671,29 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) statenum_t rollerstate = strong ? S_REDBOOSTERROLLER : S_YELLOWBOOSTERROLLER; mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG); - seg->angle = angle - ANGLE_90; + P_InitAngle(seg, angle - ANGLE_90); P_SetMobjState(seg, facestate); seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG); - seg->angle = angle + ANGLE_90; + P_InitAngle(seg, angle + ANGLE_90); P_SetMobjState(seg, facestate); seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG); - seg->angle = angle; + P_InitAngle(seg, angle); P_SetMobjState(seg, leftstate); seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG); - seg->angle = angle; + P_InitAngle(seg, angle); P_SetMobjState(seg, rightstate); seg = P_SpawnMobjFromMobj(mobj, 13*(x1 + x2), 13*(y1 + y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; + P_InitAngle(seg, angle); P_SetMobjState(seg, rollerstate); seg = P_SpawnMobjFromMobj(mobj, 13*(x1 - x2), 13*(y1 - y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; + P_InitAngle(seg, angle); P_SetMobjState(seg, rollerstate); seg = P_SpawnMobjFromMobj(mobj, -13*(x1 + x2), -13*(y1 + y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; + P_InitAngle(seg, angle); P_SetMobjState(seg, rollerstate); seg = P_SpawnMobjFromMobj(mobj, -13*(x1 - x2), -13*(y1 - y2), 0, MT_BOOSTERROLLER); - seg->angle = angle; + P_InitAngle(seg, angle); P_SetMobjState(seg, rollerstate); return true; @@ -12901,9 +12909,9 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean case MT_THZTREE: { // Spawn the branches angle_t mobjangle = FixedAngle((mthing->angle % 113) << FRACBITS); - P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h; - P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h; - P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; + P_InitAngle(P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH), mobjangle + ANGLE_22h); + P_InitAngle(P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH), mobjangle + ANGLE_157h); + P_InitAngle(P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH), mobjangle + ANGLE_270); } break; case MT_TUTORIALPLANT: @@ -12929,10 +12937,10 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean case MT_CEZPOLE2: { // Spawn the banner angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS); - P_SpawnMobjFromMobj(mobj, + P_InitAngle(P_SpawnMobjFromMobj(mobj, P_ReturnThrustX(mobj, mobjangle, 4 << FRACBITS), P_ReturnThrustY(mobj, mobjangle, 4 << FRACBITS), - 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90; + 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2)), mobjangle + ANGLE_90); } break; case MT_HHZTREE_TOP: @@ -12941,7 +12949,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj_t* leaf; #define doleaf(x, y) \ leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\ - leaf->angle = mobjangle;\ + P_InitAngle(leaf, mobjangle);\ P_SetMobjState(leaf, leaf->info->seestate);\ mobjangle += ANGLE_90 doleaf(FRACUNIT, 0); @@ -12982,7 +12990,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean fixed_t xoffs = FINECOSINE(fa); fixed_t yoffs = FINESINE(fa); mobj_t* leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF); - leaf->angle = angle; + P_InitAngle(leaf, angle); angle += ANGLE_45; } break; @@ -13108,7 +13116,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), mobj->z, MT_WALLSPIKEBASE); - base->angle = mobjangle + ANGLE_90; + P_InitAngle(base, mobjangle + ANGLE_90); base->destscale = mobj->destscale; P_SetScale(base, mobj->scale); P_SetTarget(&base->target, mobj); @@ -13236,10 +13244,12 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, return mobj; if (doangle) - mobj->angle = FixedAngle(mthing->angle << FRACBITS); + { + P_InitAngle(mobj, FixedAngle(mthing->angle << FRACBITS)); + } - mobj->pitch = FixedAngle(mthing->pitch << FRACBITS); - mobj->roll = FixedAngle(mthing->roll << FRACBITS); + P_InitPitch(mobj, FixedAngle(mthing->pitch << FRACBITS)); + P_InitRoll(mobj, FixedAngle(mthing->roll << FRACBITS)); mthing->mobj = mobj; @@ -13675,7 +13685,7 @@ mobj_t *P_SpawnXYZMissile(mobj_t *source, mobj_t *dest, mobjtype_t type, P_SetTarget(&th->target, source); // where it came from an = R_PointToAngle2(x, y, dest->x, dest->y); - th->angle = an; + P_InitAngle(th, an); an >>= ANGLETOFINESHIFT; th->momx = FixedMul(speed, FINECOSINE(an)); th->momy = FixedMul(speed, FINESINE(an)); @@ -13737,7 +13747,7 @@ mobj_t *P_SpawnAlteredDirectionMissile(mobj_t *source, mobjtype_t type, fixed_t P_SetTarget(&th->target, source->target); // where it came from an = R_PointToAngle2(0, 0, source->momx, source->momy) + (ANG1*shiftingAngle); - th->angle = an; + P_InitAngle(th, an); an >>= ANGLETOFINESHIFT; th->momx = FixedMul(speed, FINECOSINE(an)); th->momy = FixedMul(speed, FINESINE(an)); @@ -13802,7 +13812,7 @@ mobj_t *P_SpawnPointMissile(mobj_t *source, fixed_t xa, fixed_t ya, fixed_t za, P_SetTarget(&th->target, source); // where it came from an = R_PointToAngle2(x, y, xa, ya); - th->angle = an; + P_InitAngle(th, an); an >>= ANGLETOFINESHIFT; th->momx = FixedMul(speed, FINECOSINE(an)); th->momy = FixedMul(speed, FINESINE(an)); @@ -13881,7 +13891,7 @@ mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type) else an = R_PointToAngle2(source->x, source->y, dest->x, dest->y); - th->angle = an; + P_InitAngle(th, an); an >>= ANGLETOFINESHIFT; th->momx = FixedMul(speed, FINECOSINE(an)); th->momy = FixedMul(speed, FINESINE(an)); @@ -13971,7 +13981,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai if (source->player && source->player->charability == CA_FLY) speed = FixedMul(speed, 3*FRACUNIT/2); - th->angle = an; + P_InitAngle(th, an); th->momx = FixedMul(speed, FINECOSINE(an>>ANGLETOFINESHIFT)); th->momy = FixedMul(speed, FINESINE(an>>ANGLETOFINESHIFT)); diff --git a/src/p_mobj.h b/src/p_mobj.h index 9975075a1..371dc49dc 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -287,7 +287,7 @@ typedef struct mobj_s // More drawing info: to determine current sprite. angle_t angle, pitch, roll; // orientation - angle_t old_angle; + angle_t old_angle, old_pitch, old_roll; // orientation interpolation angle_t rollangle; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h diff --git a/src/p_saveg.c b/src/p_saveg.c index 99ec58bb9..46b509d19 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2758,19 +2758,19 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->info = &mobjinfo[mobj->type]; if (diff & MD_POS) { - mobj->x = READFIXED(save_p); - mobj->y = READFIXED(save_p); - mobj->angle = READANGLE(save_p); - mobj->pitch = READANGLE(save_p); - mobj->roll = READANGLE(save_p); + mobj->x = mobj->old_x = READFIXED(save_p); + mobj->y = mobj->old_y = READFIXED(save_p); + mobj->angle = mobj->old_angle = READANGLE(save_p); + mobj->pitch = mobj->old_pitch = READANGLE(save_p); + mobj->roll = mobj->old_roll = READANGLE(save_p); } else { - mobj->x = mobj->spawnpoint->x << FRACBITS; - mobj->y = mobj->spawnpoint->y << FRACBITS; - mobj->angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT); - mobj->pitch = FixedAngle(mobj->spawnpoint->pitch*FRACUNIT); - mobj->roll = FixedAngle(mobj->spawnpoint->roll*FRACUNIT); + mobj->x = mobj->old_x = mobj->spawnpoint->x << FRACBITS; + mobj->y = mobj->old_y = mobj->spawnpoint->y << FRACBITS; + mobj->angle = mobj->old_angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT); + mobj->pitch = mobj->old_pitch = FixedAngle(mobj->spawnpoint->pitch*FRACUNIT); + mobj->roll = mobj->old_roll = FixedAngle(mobj->spawnpoint->roll*FRACUNIT); } if (diff & MD_MOM) { diff --git a/src/p_spec.c b/src/p_spec.c index 6147a8392..34dcd917d 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3755,7 +3755,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (mobj) { if (line->flags & ML_EFFECT1) - mobj->angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); + P_InitAngle(mobj, R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y)); CONS_Debug(DBG_GAMELOGIC, "Linedef Type %d - Spawn Object: %d spawned at (%d, %d, %d)\n", line->special, mobj->type, mobj->x>>FRACBITS, mobj->y>>FRACBITS, mobj->z>>FRACBITS); //TODO: Convert mobj->type to a string somehow. } else diff --git a/src/p_telept.c b/src/p_telept.c index cbbd0ff6b..cfd7be1e2 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -101,7 +101,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, P_FlashPal(thing->player, PAL_MIXUP, 10); } - thing->angle = angle; + P_InitAngle(thing, angle); thing->momx = thing->momy = thing->momz = 0; @@ -174,7 +174,7 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle P_FlashPal(thing->player, PAL_MIXUP, 10); } - thing->angle = angle; + P_InitAngle(thing, angle); return true; } diff --git a/src/p_user.c b/src/p_user.c index 8e8194da0..f047499d0 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -393,7 +393,7 @@ void P_GiveFinishFlags(player_t *player) fixed_t xoffs = FINECOSINE(fa); fixed_t yoffs = FINESINE(fa); mobj_t* flag = P_SpawnMobjFromMobj(player->mo, xoffs, yoffs, 0, MT_FINISHFLAG); - flag->angle = angle; + P_InitAngle(flag, angle); angle += FixedAngle(120*FRACUNIT); P_SetTarget(&flag->target, player->mo); diff --git a/src/r_fps.c b/src/r_fps.c index 863e9613a..708add820 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -211,6 +211,9 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) { out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); } + + out->pitch = R_LerpAngle(mobj->old_pitch, mobj->pitch, frac); + out->roll = R_LerpAngle(mobj->old_roll, mobj->roll, frac); } void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out) @@ -219,6 +222,8 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); + out->pitch = 0; + out->roll = 0; } static void AddInterpolator(levelinterpolator_t* interpolator) diff --git a/src/r_fps.h b/src/r_fps.h index aa6213ae3..1eb53b346 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -49,6 +49,8 @@ typedef struct { fixed_t y; fixed_t z; angle_t angle; + angle_t pitch; + angle_t roll; } interpmobjstate_t; // Level interpolators From cd70b499bd272eaa2c71ceb00a60d79180d47faa Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 25 Dec 2021 02:07:56 -0500 Subject: [PATCH 028/137] Fully fix drop shadows It used the thing's floorz / ceilingz directly -- that wouldn't account for interpolated coordinates. --- src/r_things.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index 10fb25cc0..bdbb6b95f 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1135,7 +1135,10 @@ static void R_SplitSprite(vissprite_t *sprite) // fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) { + fixed_t halfHeight; boolean isflipped = thing->eflags & MFE_VERTICALFLIP; + fixed_t floorz; + fixed_t ceilingz; fixed_t z, groundz = isflipped ? INT32_MAX : INT32_MIN; pslope_t *slope, *groundslope = NULL; msecnode_t *node; @@ -1154,7 +1157,11 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) R_InterpolateMobjState(thing, FRACUNIT, &interp); } -#define CHECKZ (isflipped ? z > interp.z+thing->height/2 && z < groundz : z < interp.z+thing->height/2 && z > groundz) + halfHeight = interp.z + (thing->height >> 1); + floorz = P_GetFloorZ(thing, thing->subsector->sector, interp.x, interp.y, NULL); + ceilingz = P_GetCeilingZ(thing, thing->subsector->sector, interp.x, interp.y, NULL); + +#define CHECKZ (isflipped ? z > halfHeight && z < groundz : z < halfHeight && z > groundz) for (node = thing->touching_sectorlist; node; node = node->m_sectorlist_next) { @@ -1188,10 +1195,10 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) } } - if (isflipped ? (thing->ceilingz < groundz - (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2))) - : (thing->floorz > groundz + (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2)))) + if (isflipped ? (ceilingz < groundz - (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2))) + : (floorz > groundz + (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2)))) { - groundz = isflipped ? thing->ceilingz : thing->floorz; + groundz = isflipped ? ceilingz : floorz; groundslope = NULL; } @@ -1202,10 +1209,10 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) { INT32 xl, xh, yl, yh, bx, by; - xl = (unsigned)(thing->x - thing->radius - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(thing->x + thing->radius - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(thing->y - thing->radius - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(thing->y + thing->radius - bmaporgy)>>MAPBLOCKSHIFT; + xl = (unsigned)(interp.x - thing->radius - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(interp.x + thing->radius - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(interp.y - thing->radius - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(interp.y + thing->radius - bmaporgy)>>MAPBLOCKSHIFT; BMBOUNDFIX(xl, xh, yl, yh); @@ -1242,7 +1249,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) // We're inside it! Yess... z = po->lines[0]->backsector->ceilingheight; - if (z < thing->z+thing->height/2 && z > groundz) + if (z < halfHeight && z > groundz) { groundz = z; groundslope = NULL; From 56c0c1f415ccca94d62b67751f68bcad7f1ab4eb Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 12 Jan 2022 04:30:03 -0800 Subject: [PATCH 029/137] Do not speed up underwater/heatwave effect in OpenGL --- src/hardware/hw_main.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 95b62eb5f..dc045da7c 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6711,7 +6711,6 @@ void HWR_DoPostProcessor(player_t *player) // 10 by 10 grid. 2 coordinates (xy) float v[SCREENVERTS][SCREENVERTS][2]; static double disStart = 0; - static fixed_t last_fractime = 0; UINT8 x, y; INT32 WAVELENGTH; @@ -6743,16 +6742,7 @@ void HWR_DoPostProcessor(player_t *player) } HWD.pfnPostImgRedraw(v); if (!(paused || P_AutoPause())) - disStart += 1; - if (renderdeltatics > FRACUNIT) - { - disStart = disStart - FIXED_TO_FLOAT(last_fractime) + 1 + FIXED_TO_FLOAT(rendertimefrac); - } - else - { - disStart = disStart - FIXED_TO_FLOAT(last_fractime) + FIXED_TO_FLOAT(rendertimefrac); - } - last_fractime = rendertimefrac; + disStart += FIXED_TO_FLOAT(renderdeltatics); // Capture the screen again for screen waving on the intermission if(gamestate != GS_INTERMISSION) From e6dff8eedc1ffa6f0f28139dabe6d3cf04c0c581 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 12 Jan 2022 04:30:43 -0800 Subject: [PATCH 030/137] Closer OpenGL underwater/heatwave effect to Software --- src/hardware/hw_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index dc045da7c..829d9b04b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -6720,15 +6720,15 @@ void HWR_DoPostProcessor(player_t *player) // Modifies the wave. if (*type == postimg_water) { - WAVELENGTH = 20; // Lower is longer - AMPLITUDE = 20; // Lower is bigger - FREQUENCY = 16; // Lower is faster + WAVELENGTH = 5; + AMPLITUDE = 20; + FREQUENCY = 8; } else { - WAVELENGTH = 10; // Lower is longer - AMPLITUDE = 30; // Lower is bigger - FREQUENCY = 4; // Lower is faster + WAVELENGTH = 10; + AMPLITUDE = 60; + FREQUENCY = 4; } for (x = 0; x < SCREENVERTS; x++) From 1b49a96eed927e80e019b580c5a94e13ae3e0640 Mon Sep 17 00:00:00 2001 From: James R Date: Wed, 12 Jan 2022 03:36:02 -0800 Subject: [PATCH 031/137] Interpolate from time of previous tic Previously interpolated from last 35th of a second, which may be offset from game time due to connection lag. Consider this the proper fix to 54148a0dd0 too. --- src/d_clisrv.c | 16 ++++++++++++---- src/d_clisrv.h | 2 +- src/d_main.c | 16 +++++++++++++--- src/i_system.h | 4 ++-- src/sdl/i_system.c | 5 ++--- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ac8bba608..2972502a7 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5206,8 +5206,10 @@ static void SV_Maketic(void) maketic++; } -void TryRunTics(tic_t realtics) +boolean TryRunTics(tic_t realtics) { + boolean ticking; + // the machine has lagged but it is not so bad if (realtics > TICRATE/7) // FIXME: consistency failure!! { @@ -5251,10 +5253,14 @@ void TryRunTics(tic_t realtics) } #endif - if (player_joining) - return; + ticking = neededtic > gametic; - if (neededtic > gametic) + if (player_joining) + { + return false; + } + + if (ticking) { if (advancedemo) { @@ -5290,6 +5296,8 @@ void TryRunTics(tic_t realtics) break; } } + + return ticking; } /* diff --git a/src/d_clisrv.h b/src/d_clisrv.h index bf3f0b64f..c75f7f0bf 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -430,7 +430,7 @@ boolean Playing(void); void D_QuitNetGame(void); //? How many ticks to run? -void TryRunTics(tic_t realtic); +boolean TryRunTics(tic_t realtic); // extra data for lmps // these functions scare me. they contain magic. diff --git a/src/d_main.c b/src/d_main.c index 963439d66..155913320 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -697,6 +697,7 @@ void D_SRB2Loop(void) { tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS; static lumpnum_t gstartuplumpnum; + boolean ticked; if (dedicated) server = true; @@ -783,11 +784,20 @@ void D_SRB2Loop(void) realtics = 1; // process tics (but maybe not if realtic == 0) - TryRunTics(realtics); + ticked = TryRunTics(realtics); - if (cv_frameinterpolation.value == 1) + if (cv_frameinterpolation.value == 1 && !(paused || P_AutoPause())) { - fixed_t entertimefrac = I_GetTimeFrac(); + static float tictime; + float entertime = I_GetTimeFrac(); + + fixed_t entertimefrac; + + if (ticked) + tictime = entertime; + + entertimefrac = FLOAT_TO_FIXED(entertime - tictime); + // renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based renderdeltatics = realtics * FRACUNIT; if (entertimefrac > rendertimefrac) diff --git a/src/i_system.h b/src/i_system.h index 0cdc7db85..93bb34a21 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -46,9 +46,9 @@ UINT32 I_GetFreeMem(UINT32 *total); */ tic_t I_GetTime(void); -/** \brief Get the current time as a fraction of a tic since the last tic. +/** \brief Get the current time in tics including fractions. */ -fixed_t I_GetTimeFrac(void); +float I_GetTimeFrac(void); /** \brief Returns precise time value for performance measurement. */ diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 2d99f5c1f..bf2e42cfd 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2160,11 +2160,10 @@ tic_t I_GetTime(void) return (tic_t) floor(elapsed_tics); } -fixed_t I_GetTimeFrac(void) +float I_GetTimeFrac(void) { UpdateElapsedTics(); - - return FLOAT_TO_FIXED((float) (elapsed_tics - floor(elapsed_tics))); + return elapsed_tics; } precise_t I_GetPreciseTime(void) From 40b021d6e4fe8c7d3637b070507e3ee5ef71cd28 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Mar 2022 16:32:43 -0400 Subject: [PATCH 032/137] Calculate FPS stuff even if frame is skipped I decided ultimately to actually keep the frame skip optimization disabled, because I think it is actually a little bit helpful that you can still get accurate rendering perfstats while paused, however if we decide otherwise then we can have this optimization back without making the game act like it's lagging. --- src/screen.c | 69 +++++++++++++++++++++++++++++++++++++---------- src/screen.h | 3 +++ src/sdl/i_video.c | 10 +++---- 3 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/screen.c b/src/screen.c index 73af4313d..f81a6563d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -451,18 +451,50 @@ boolean SCR_IsAspectCorrect(INT32 width, INT32 height) // moved out of os-specific code for consistency static boolean fpsgraph[TICRATE]; static tic_t lasttic; +static tic_t totaltics; -void SCR_DisplayTicRate(void) +static UINT32 fpstime = 0; +static UINT32 lastupdatetime = 0; + +#define FPSUPDATERATE 1/20 // What fraction of a second to update at. The fraction will not simplify to 0, trust me. +#define FPSMAXSAMPLES 16 + +static UINT32 fpssamples[FPSMAXSAMPLES]; +static UINT32 fpssampleslen = 0; +static UINT32 fpssum = 0; +double aproxfps = 0.0f; + +void SCR_CalcAproxFps(void) { - tic_t i; + tic_t i = 0; tic_t ontic = I_GetTime(); - tic_t totaltics = 0; - INT32 ticcntcolor = 0; - const INT32 h = vid.height-(8*vid.dupy); - if (gamestate == GS_NULL) - return; + totaltics = 0; + // Update FPS time + if (I_PreciseToMicros(fpstime - lastupdatetime) > 1000000 * FPSUPDATERATE) + { + if (fpssampleslen == FPSMAXSAMPLES) + { + fpssum -= fpssamples[0]; + + for (i = 1; i < fpssampleslen; i++) + fpssamples[i-1] = fpssamples[i]; + } + else + fpssampleslen++; + + fpssamples[fpssampleslen-1] = I_GetPreciseTime() - fpstime; + fpssum += fpssamples[fpssampleslen-1]; + + aproxfps = 1000000 / (I_PreciseToMicros(fpssum) / (double)fpssampleslen); + + lastupdatetime = I_GetPreciseTime(); + } + + fpstime = I_GetPreciseTime(); + + // Update ticrate time for (i = lasttic + 1; i < TICRATE+lasttic && i < ontic; ++i) fpsgraph[i % TICRATE] = false; @@ -472,21 +504,30 @@ void SCR_DisplayTicRate(void) if (fpsgraph[i]) ++totaltics; + lasttic = ontic; +} + +void SCR_DisplayTicRate(void) +{ + INT32 ticcntcolor = 0; + const INT32 h = vid.height-(8*vid.dupy); + + if (gamestate == GS_NULL) + return; + if (totaltics <= TICRATE/2) ticcntcolor = V_REDMAP; else if (totaltics == TICRATE) ticcntcolor = V_GREENMAP; if (cv_ticrate.value == 2) // compact counter - V_DrawString(vid.width-(16*vid.dupx), h, - ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%02d", totaltics)); + V_DrawString(vid.width-(24*vid.dupx), h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%03.0f", aproxfps)); else if (cv_ticrate.value == 1) // full counter { - V_DrawString(vid.width-(72*vid.dupx), h, + V_DrawString(vid.width-(88*vid.dupx), h, V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); - V_DrawString(vid.width-(40*vid.dupx), h, - ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%02d/%02u", totaltics, TICRATE)); + V_DrawString(vid.width-(56*vid.dupx), h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%03.0f/%03u", aproxfps, TICRATE)); } - - lasttic = ontic; } void SCR_DisplayLocalPing(void) diff --git a/src/screen.h b/src/screen.h index 376953169..425d10954 100644 --- a/src/screen.h +++ b/src/screen.h @@ -181,6 +181,7 @@ extern boolean R_SSE2; extern viddef_t vid; extern INT32 setmodeneeded; // mode number to set if needed, or 0 extern UINT8 setrenderneeded; +extern double aproxfps; void SCR_ChangeRenderer(void); @@ -211,6 +212,8 @@ void SCR_CheckDefaultMode(void); // Set the mode number which is saved in the config void SCR_SetDefaultMode(void); +void SCR_CalcAproxFps(void); + FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height); // move out to main code for consistency diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index a27a5ebd2..f90eb09ae 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1178,12 +1178,11 @@ void I_UpdateNoBlit(void) // from PrBoom's src/SDL/i_video.c static inline boolean I_SkipFrame(void) { -#if 0 +#if 1 + return false; +#else static boolean skip = false; - if (rendermode != render_soft) - return false; - skip = !skip; switch (gamestate) @@ -1199,7 +1198,6 @@ static inline boolean I_SkipFrame(void) return false; } #endif - return false; } // @@ -1210,6 +1208,8 @@ void I_FinishUpdate(void) if (rendermode == render_none) return; //Alam: No software or OpenGl surface + SCR_CalcAproxFps(); + if (I_SkipFrame()) return; From 41997c45490deeb0978a9b73094edd6244fc96c7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Mar 2022 17:16:13 -0400 Subject: [PATCH 033/137] Keep rect in memory Feel better about this than creating one all da time --- src/sdl/i_video.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index f90eb09ae..d8899e932 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1179,6 +1179,10 @@ void I_UpdateNoBlit(void) static inline boolean I_SkipFrame(void) { #if 1 + // While I fixed the FPS counter bugging out with this, + // I actually really like being able to pause and + // use perfstats to measure rendering performance + // without game logic changes. return false; #else static boolean skip = false; @@ -1203,6 +1207,8 @@ static inline boolean I_SkipFrame(void) // // I_FinishUpdate // +static SDL_Rect src_rect = { 0, 0, 0, 0 }; + void I_FinishUpdate(void) { if (rendermode == render_none) @@ -1228,27 +1234,22 @@ void I_FinishUpdate(void) if (rendermode == render_soft && screens[0]) { - SDL_Rect rect; - - rect.x = 0; - rect.y = 0; - rect.w = vid.width; - rect.h = vid.height; - if (!bufSurface) //Double-Check { Impl_VideoSetupSDLBuffer(); } + if (bufSurface) { - SDL_BlitSurface(bufSurface, NULL, vidSurface, &rect); + SDL_BlitSurface(bufSurface, &src_rect, vidSurface, &src_rect); // Fury -- there's no way around UpdateTexture, the GL backend uses it anyway SDL_LockSurface(vidSurface); - SDL_UpdateTexture(texture, &rect, vidSurface->pixels, vidSurface->pitch); + SDL_UpdateTexture(texture, &src_rect, vidSurface->pixels, vidSurface->pitch); SDL_UnlockSurface(vidSurface); } + SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderCopy(renderer, texture, &src_rect, NULL); SDL_RenderPresent(renderer); } #ifdef HWRENDER @@ -1257,6 +1258,7 @@ void I_FinishUpdate(void) OglSdlFinishUpdate(cv_vidwait.value); } #endif + exposevideo = SDL_FALSE; } @@ -1610,6 +1612,9 @@ INT32 VID_SetMode(INT32 modeNum) vid.modenum = modeNum; //Impl_SetWindowName("SRB2 "VERSIONSTRING); + src_rect.w = vid.width; + src_rect.h = vid.height; + VID_CheckRenderer(); return SDL_TRUE; } From c186d6402b77a52a7839ed69790d964be6af639e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 26 Mar 2022 23:48:08 -0400 Subject: [PATCH 034/137] Lots of FPS stuff - Disabled VSync, due to the numerous problems it has. - Instead, added an FPS cap. - Frame interpolation is now tied to fpscap != 35. - By default, the FPS cap is set to the monitor's refresh rate. - Rewrote the FPS counter. (This also consolidates several more commits ahead of this fixing various issues. -eid) --- src/d_clisrv.c | 2 +- src/d_main.c | 195 ++++++++++++++++++++++++++++------------- src/d_netcmd.c | 2 +- src/hardware/hw_main.c | 6 +- src/hardware/hw_md2.c | 2 +- src/i_system.h | 4 +- src/i_video.h | 2 + src/m_menu.c | 13 ++- src/r_fps.c | 46 +++++++++- src/r_fps.h | 5 ++ src/r_main.c | 9 +- src/r_main.h | 3 - src/r_things.c | 12 +-- src/screen.c | 102 ++++++++++----------- src/screen.h | 5 +- src/sdl/i_system.c | 52 +++++++++++ src/sdl/i_video.c | 29 +++++- 17 files changed, 342 insertions(+), 147 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 2972502a7..74f3dd959 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5233,7 +5233,7 @@ boolean TryRunTics(tic_t realtics) if (demoplayback) { - neededtic = gametic + (realtics * cv_playbackspeed.value); + neededtic = gametic + realtics; // start a game after a demo maketic += realtics; firstticstosend = maketic; diff --git a/src/d_main.c b/src/d_main.c index 155913320..bb01976cd 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -477,7 +477,7 @@ static void D_Display(void) if (!automapactive && !dedicated && cv_renderview.value) { - R_ApplyLevelInterpolators(cv_frameinterpolation.value == 1 ? rendertimefrac : FRACUNIT); + R_ApplyLevelInterpolators(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT); PS_START_TIMING(ps_rendercalltime); if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD) { @@ -687,6 +687,29 @@ static void D_Display(void) } } +static boolean D_CheckFrameCap(void) +{ + static boolean init = false; + static precise_t startCap = 0; + precise_t endCap = 0; + + endCap = I_GetPreciseTime(); + + if (init == false) + { + startCap = endCap; + init = true; + } + else if (I_CheckFrameCap(startCap, endCap)) + { + // Framerate should be capped. + return true; + } + + startCap = endCap; + return false; +} + // ========================================================================= // D_SRB2Loop // ========================================================================= @@ -698,6 +721,8 @@ void D_SRB2Loop(void) tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS; static lumpnum_t gstartuplumpnum; boolean ticked; + boolean interp; + boolean doDisplay = false; if (dedicated) server = true; @@ -762,14 +787,25 @@ void D_SRB2Loop(void) refreshdirmenu = 0; // not sure where to put this, here as good as any? + if (demoplayback && gamestate == GS_LEVEL) + { + // Nicer place to put this. + realtics = realtics * cv_playbackspeed.value; + } + #ifdef DEBUGFILE if (!realtics) if (debugload) debugload--; #endif - if (!realtics && !singletics && cv_frameinterpolation.value != 1) + interp = R_UsingFrameInterpolation(); + doDisplay = false; + ticked = false; + + if (!realtics && !singletics && !interp) { + // Non-interp sleep I_Sleep(); continue; } @@ -778,85 +814,115 @@ void D_SRB2Loop(void) HW3S_BeginFrameUpdate(); #endif - // don't skip more than 10 frames at a time - // (fadein / fadeout cause massive frame skip!) - if (realtics > 8) - realtics = 1; - - // process tics (but maybe not if realtic == 0) - ticked = TryRunTics(realtics); - - if (cv_frameinterpolation.value == 1 && !(paused || P_AutoPause())) + if (realtics > 0 || singletics) { - static float tictime; + // don't skip more than 10 frames at a time + // (fadein / fadeout cause massive frame skip!) + if (realtics > 8) + realtics = 1; + + // process tics (but maybe not if realtic == 0) + ticked = TryRunTics(realtics); + + if (lastdraw || singletics || gametic > rendergametic) + { + rendergametic = gametic; + rendertimeout = entertic+TICRATE/17; + + doDisplay = true; + } + else if (rendertimeout < entertic) // in case the server hang or netsplit + { + // Lagless camera! Yay! + if (gamestate == GS_LEVEL && netgame) + { + // Evaluate the chase cam once for every local realtic + // This might actually be better suited inside G_Ticker or TryRunTics + for (tic_t chasecamtics = 0; chasecamtics < realtics; chasecamtics++) + { + if (splitscreen && camera2.chase) + P_MoveChaseCamera(&players[secondarydisplayplayer], &camera2, false); + if (camera.chase) + P_MoveChaseCamera(&players[displayplayer], &camera, false); + } + R_UpdateViewInterpolation(); + } + + doDisplay = true; + } + } + + if (interp) + { + static float tictime = 0.0f; + static float prevtime = 0.0f; float entertime = I_GetTimeFrac(); - fixed_t entertimefrac; + fixed_t entertimefrac = FRACUNIT; if (ticked) + { tictime = entertime; + } - entertimefrac = FLOAT_TO_FIXED(entertime - tictime); + // Handle interp sleep / framerate cap here. + // TryRunTics needs ran if possible to prevent lagged map changes, + // (and if that runs, the code above needs to also run) + // so this is done here after TryRunTics. + if (D_CheckFrameCap()) + { + continue; + } - // renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based - renderdeltatics = realtics * FRACUNIT; - if (entertimefrac > rendertimefrac) - renderdeltatics += entertimefrac - rendertimefrac; - else - renderdeltatics -= rendertimefrac - entertimefrac; + if (!(paused || P_AutoPause())) + { +#if 0 + CONS_Printf("prevtime = %f\n", prevtime); + CONS_Printf("entertime = %f\n", entertime); + CONS_Printf("tictime = %f\n", tictime); + CONS_Printf("entertime - prevtime = %f\n", entertime - prevtime); + CONS_Printf("entertime - tictime = %f\n", entertime - tictime); + CONS_Printf("========\n"); +#endif - rendertimefrac = entertimefrac; + if (entertime - prevtime >= 1.0f) + { + // Lagged for more frames than a gametic... + // No need for interpolation. + entertimefrac = FRACUNIT; + } + else + { + entertimefrac = min(FRACUNIT, FLOAT_TO_FIXED(entertime - tictime)); + } + + // renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based + renderdeltatics = realtics * FRACUNIT; + if (entertimefrac > rendertimefrac) + renderdeltatics += entertimefrac - rendertimefrac; + else + renderdeltatics -= rendertimefrac - entertimefrac; + + rendertimefrac = entertimefrac; + } + + prevtime = entertime; } else { - rendertimefrac = FRACUNIT; renderdeltatics = realtics * FRACUNIT; + rendertimefrac = FRACUNIT; } - if (cv_frameinterpolation.value == 1) + if (interp || doDisplay) { D_Display(); } - if (lastdraw || singletics || gametic > rendergametic) - { - rendergametic = gametic; - rendertimeout = entertic+TICRATE/17; - - // Update display, next frame, with current state. - // (Only display if not already done for frame interp) - cv_frameinterpolation.value == 0 ? D_Display() : 0; - - if (moviemode) - M_SaveFrame(); - if (takescreenshot) // Only take screenshots after drawing. - M_DoScreenShot(); - } - else if (rendertimeout < entertic) // in case the server hang or netsplit - { - // Lagless camera! Yay! - if (gamestate == GS_LEVEL && netgame) - { - // Evaluate the chase cam once for every local realtic - // This might actually be better suited inside G_Ticker or TryRunTics - for (tic_t chasecamtics = 0; chasecamtics < realtics; chasecamtics++) - { - if (splitscreen && camera2.chase) - P_MoveChaseCamera(&players[secondarydisplayplayer], &camera2, false); - if (camera.chase) - P_MoveChaseCamera(&players[displayplayer], &camera, false); - } - R_UpdateViewInterpolation(); - - } - // (Only display if not already done for frame interp) - cv_frameinterpolation.value == 0 ? D_Display() : 0; - - if (moviemode) - M_SaveFrame(); - if (takescreenshot) // Only take screenshots after drawing. - M_DoScreenShot(); - } + if (moviemode) + M_SaveFrame(); + if (takescreenshot) // Only take screenshots after drawing. + M_DoScreenShot(); // consoleplayer -> displayplayer (hear sounds from viewpoint) S_UpdateSounds(); // move positional sounds @@ -867,6 +933,11 @@ void D_SRB2Loop(void) #endif LUA_Step(); + + // Moved to here from I_FinishUpdate. + // It doesn't track fades properly anymore by being here (might be easy fix), + // but it's a little more accurate for actual game logic when its here. + SCR_CalculateFPS(); } } diff --git a/src/d_netcmd.c b/src/d_netcmd.c index d9080d342..9b14e0913 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -191,7 +191,7 @@ static CV_PossibleValue_t joyport_cons_t[] = {{1, "/dev/js0"}, {2, "/dev/js1"}, static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}}; static CV_PossibleValue_t startingliveslimit_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}}; -static CV_PossibleValue_t sleeping_cons_t[] = {{-1, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}}; +static CV_PossibleValue_t sleeping_cons_t[] = {{0, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}}; static CV_PossibleValue_t competitionboxes_cons_t[] = {{0, "Normal"}, {1, "Mystery"}, //{2, "Teleport"}, {3, "None"}, {0, NULL}}; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 829d9b04b..f56856bb4 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3648,7 +3648,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) // uncapped/interpolation interpmobjstate_t interp = {0}; - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolateMobjState(thing, rendertimefrac, &interp); } @@ -5089,7 +5089,7 @@ static void HWR_ProjectSprite(mobj_t *thing) dispoffset = thing->info->dispoffset; - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolateMobjState(thing, rendertimefrac, &interp); } @@ -5502,7 +5502,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) interpmobjstate_t interp = {0}; // do interpolation - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolatePrecipMobjState(thing, rendertimefrac, &interp); } diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 7bc218d14..67bed7ee3 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1344,7 +1344,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) float finalscale; interpmobjstate_t interp; - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolateMobjState(spr->mobj, rendertimefrac, &interp); } diff --git a/src/i_system.h b/src/i_system.h index 93bb34a21..fefe0a7c1 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -56,7 +56,7 @@ precise_t I_GetPreciseTime(void); /** \brief Converts a precise_t to microseconds and casts it to a 32 bit integer. */ -int I_PreciseToMicros(precise_t); +int I_PreciseToMicros(precise_t d); /** \brief The I_Sleep function @@ -64,6 +64,8 @@ int I_PreciseToMicros(precise_t); */ void I_Sleep(void); +boolean I_CheckFrameCap(precise_t start, precise_t end); + /** \brief Get events Called by D_SRB2Loop, diff --git a/src/i_video.h b/src/i_video.h index 638fcb668..d66b2d95f 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -151,4 +151,6 @@ void I_BeginRead(void); */ void I_EndRead(void); +UINT32 I_GetRefreshRate(void); + #endif diff --git a/src/m_menu.c b/src/m_menu.c index 368e7778e..6383c106d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -22,6 +22,7 @@ #include "d_main.h" #include "d_netcmd.h" #include "console.h" +#include "r_fps.h" #include "r_local.h" #include "hu_stuff.h" #include "g_game.h" @@ -1380,16 +1381,14 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_HEADER, NULL, "Diagnostic", NULL, 184}, {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 190}, - {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 195}, - {IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 200}, + {IT_STRING | IT_CVAR, NULL, "FPS Cap", &cv_fpscap, 195}, + {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 200}, + {IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 205}, #ifdef HWRENDER - {IT_HEADER, NULL, "Renderer", NULL, 208}, - {IT_CALL | IT_STRING, NULL, "OpenGL Options...", M_OpenGLOptionsMenu, 214}, + {IT_HEADER, NULL, "Renderer", NULL, 213}, + {IT_CALL | IT_STRING, NULL, "OpenGL Options...", M_OpenGLOptionsMenu, 219}, #endif - - {IT_HEADER, NULL, "Experimental", NULL, 222}, - {IT_STRING | IT_CVAR, NULL, "Frame Interpolation", &cv_frameinterpolation, 228}, }; static menuitem_t OP_VideoModeMenu[] = diff --git a/src/r_fps.c b/src/r_fps.c index 708add820..9c3a9db53 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -21,10 +21,52 @@ #include "p_spec.h" #include "r_state.h" #include "z_zone.h" +#include "console.h" // con_startup_loadprogress #ifdef HWRENDER #include "hardware/hw_main.h" // for cv_glshearing #endif +static CV_PossibleValue_t fpscap_cons_t[] = { + {-1, "Match refresh rate"}, + {0, "Unlimited"}, +#ifdef DEVELOP + // Lower values are actually pretty useful for debugging interp problems! + {1, "One Singular Frame"}, + {10, "10"}, + {20, "20"}, + {25, "25"}, + {30, "30"}, +#endif + {35, "35"}, + {50, "50"}, + {60, "60"}, + {70, "70"}, + {75, "75"}, + {90, "90"}, + {100, "100"}, + {120, "120"}, + {144, "144"}, + {200, "200"}, + {240, "240"}, + {0, NULL} +}; +consvar_t cv_fpscap = CVAR_INIT ("fpscap", "Match refresh rate", CV_SAVE, fpscap_cons_t, NULL); + +UINT32 R_GetFramerateCap(void) +{ + if (cv_fpscap.value < 0) + { + return I_GetRefreshRate(); + } + + return cv_fpscap.value; +} + +boolean R_UsingFrameInterpolation(void) +{ + return (R_GetFramerateCap() != TICRATE); // maybe use ">" instead? +} + static viewvars_t p1view_old; static viewvars_t p1view_new; static viewvars_t p2view_old; @@ -179,7 +221,7 @@ void R_SetViewContext(enum viewcontext_e _viewcontext) fixed_t R_InterpolateFixed(fixed_t from, fixed_t to) { - if (cv_frameinterpolation.value == 0) + if (!R_UsingFrameInterpolation()) { return to; } @@ -189,7 +231,7 @@ fixed_t R_InterpolateFixed(fixed_t from, fixed_t to) angle_t R_InterpolateAngle(angle_t from, angle_t to) { - if (cv_frameinterpolation.value == 0) + if (!R_UsingFrameInterpolation()) { return to; } diff --git a/src/r_fps.h b/src/r_fps.h index 1eb53b346..75d9ead3d 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -19,6 +19,11 @@ #include "p_local.h" #include "r_state.h" +extern consvar_t cv_fpscap; + +UINT32 R_GetFramerateCap(void); +boolean R_UsingFrameInterpolation(void); + enum viewcontext_e { VIEWCONTEXT_PLAYER1 = 0, diff --git a/src/r_main.c b/src/r_main.c index e7f567b58..896b6a29b 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -168,9 +168,6 @@ consvar_t cv_drawdist_precip = CVAR_INIT ("drawdist_precip", "1024", CV_SAVE, dr //consvar_t cv_precipdensity = CVAR_INIT ("precipdensity", "Moderate", CV_SAVE, precipdensity_cons_t, NULL); consvar_t cv_fov = CVAR_INIT ("fov", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange); -// Frame interpolation/uncapped -consvar_t cv_frameinterpolation = {"frameinterpolation", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; - // Okay, whoever said homremoval causes a performance hit should be shot. consvar_t cv_homremoval = CVAR_INIT ("homremoval", "No", CV_SAVE, homremoval_cons_t, NULL); @@ -1199,7 +1196,7 @@ void R_SetupFrame(player_t *player) // newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT); // newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - R_InterpolateView(cv_frameinterpolation.value == 1 ? rendertimefrac : FRACUNIT); + R_InterpolateView(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT); } void R_SkyboxFrame(player_t *player) @@ -1343,7 +1340,7 @@ void R_SkyboxFrame(player_t *player) // newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT); // newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT); - R_InterpolateView(cv_frameinterpolation.value == 1 ? rendertimefrac : FRACUNIT); + R_InterpolateView(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT); } boolean R_ViewpointHasChasecam(player_t *player) @@ -1627,5 +1624,5 @@ void R_RegisterEngineStuff(void) CV_RegisterVar(&cv_movebob); // Frame interpolation/uncapped - CV_RegisterVar(&cv_frameinterpolation); + CV_RegisterVar(&cv_fpscap); } diff --git a/src/r_main.h b/src/r_main.h index 08654a694..ccbc0ad8c 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -119,9 +119,6 @@ extern consvar_t cv_fov; extern consvar_t cv_skybox; extern consvar_t cv_tailspickup; -// Frame interpolation (uncapped framerate) -extern consvar_t cv_frameinterpolation; - // Called by startup code. void R_Init(void); diff --git a/src/r_things.c b/src/r_things.c index bdbb6b95f..a7df5adef 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1148,7 +1148,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) // for frame interpolation interpmobjstate_t interp = {0}; - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolateMobjState(thing, rendertimefrac, &interp); } @@ -1281,7 +1281,7 @@ static void R_SkewShadowSprite( // for frame interpolation interpmobjstate_t interp = {0}; - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolateMobjState(thing, rendertimefrac, &interp); } @@ -1324,7 +1324,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, if (abs(groundz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolateMobjState(thing, rendertimefrac, &interp); } @@ -1530,7 +1530,7 @@ static void R_ProjectSprite(mobj_t *thing) interpmobjstate_t interp = {0}; // do interpolation - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolateMobjState(thing, rendertimefrac, &interp); } @@ -1850,7 +1850,7 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t linkscale; thing = thing->tracer; - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolateMobjState(thing, rendertimefrac, &interp); } @@ -2210,7 +2210,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) interpmobjstate_t interp = {0}; // do interpolation - if (cv_frameinterpolation.value == 1 && !paused) + if (R_UsingFrameInterpolation() && !paused) { R_InterpolatePrecipMobjState(thing, rendertimefrac, &interp); } diff --git a/src/screen.c b/src/screen.c index f81a6563d..88898c503 100644 --- a/src/screen.c +++ b/src/screen.c @@ -33,12 +33,15 @@ #include "s_sound.h" // ditto #include "g_game.h" // ditto #include "p_local.h" // P_AutoPause() + #ifdef HWRENDER #include "hardware/hw_main.h" #include "hardware/hw_light.h" #include "hardware/hw_model.h" #endif +// SRB2Kart +#include "r_fps.h" // R_GetFramerateCap #if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200)) #define RUSEASM //MSC.NET can't patch itself @@ -67,6 +70,7 @@ static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"}, consvar_t cv_scr_width = CVAR_INIT ("scr_width", "1280", CV_SAVE, CV_Unsigned, NULL); consvar_t cv_scr_height = CVAR_INIT ("scr_height", "800", CV_SAVE, CV_Unsigned, NULL); consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL); + consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL); CV_PossibleValue_t cv_renderer_t[] = { @@ -447,86 +451,82 @@ boolean SCR_IsAspectCorrect(INT32 width, INT32 height) ); } -// XMOD FPS display -// moved out of os-specific code for consistency -static boolean fpsgraph[TICRATE]; -static tic_t lasttic; static tic_t totaltics; +double averageFPS = 0.0f; -static UINT32 fpstime = 0; -static UINT32 lastupdatetime = 0; +#define FPS_SAMPLE_RATE (50000) // How often to update FPS samples, in microseconds +#define NUM_FPS_SAMPLES 16 // Number of samples to store -#define FPSUPDATERATE 1/20 // What fraction of a second to update at. The fraction will not simplify to 0, trust me. -#define FPSMAXSAMPLES 16 +static double fps_samples[NUM_FPS_SAMPLES]; -static UINT32 fpssamples[FPSMAXSAMPLES]; -static UINT32 fpssampleslen = 0; -static UINT32 fpssum = 0; -double aproxfps = 0.0f; - -void SCR_CalcAproxFps(void) +void SCR_CalculateFPS(void) { - tic_t i = 0; - tic_t ontic = I_GetTime(); + static boolean init = false; - totaltics = 0; + static precise_t startTime = 0; + precise_t endTime = 0; - // Update FPS time - if (I_PreciseToMicros(fpstime - lastupdatetime) > 1000000 * FPSUPDATERATE) + static precise_t updateTime = 0; + int updateElapsed = 0; + int i; + + endTime = I_GetPreciseTime(); + + if (init == false) { - if (fpssampleslen == FPSMAXSAMPLES) - { - fpssum -= fpssamples[0]; - - for (i = 1; i < fpssampleslen; i++) - fpssamples[i-1] = fpssamples[i]; - } - else - fpssampleslen++; - - fpssamples[fpssampleslen-1] = I_GetPreciseTime() - fpstime; - fpssum += fpssamples[fpssampleslen-1]; - - aproxfps = 1000000 / (I_PreciseToMicros(fpssum) / (double)fpssampleslen); - - lastupdatetime = I_GetPreciseTime(); + startTime = updateTime = endTime; + init = true; + return; } - fpstime = I_GetPreciseTime(); + updateElapsed = I_PreciseToMicros(endTime - updateTime); - // Update ticrate time - for (i = lasttic + 1; i < TICRATE+lasttic && i < ontic; ++i) - fpsgraph[i % TICRATE] = false; + if (updateElapsed >= FPS_SAMPLE_RATE) + { + static int sampleIndex = 0; + int frameElapsed = I_PreciseToMicros(endTime - startTime); - fpsgraph[ontic % TICRATE] = true; + fps_samples[sampleIndex] = frameElapsed / 1000.0f; - for (i = 0;i < TICRATE;++i) - if (fpsgraph[i]) - ++totaltics; + sampleIndex++; + if (sampleIndex >= NUM_FPS_SAMPLES) + sampleIndex = 0; - lasttic = ontic; + averageFPS = 0.0f; + for (i = 0; i < NUM_FPS_SAMPLES; i++) + { + averageFPS += fps_samples[i]; + } + averageFPS = 1000.0f / (averageFPS / NUM_FPS_SAMPLES); + + updateTime = endTime; + } + + startTime = endTime; } void SCR_DisplayTicRate(void) { INT32 ticcntcolor = 0; const INT32 h = vid.height-(8*vid.dupy); + UINT32 cap = R_GetFramerateCap(); + double fps = ceil(averageFPS); if (gamestate == GS_NULL) return; - if (totaltics <= TICRATE/2) ticcntcolor = V_REDMAP; - else if (totaltics == TICRATE) ticcntcolor = V_GREENMAP; + if (totaltics <= cap/2) ticcntcolor = V_REDMAP; + else if (totaltics >= cap) ticcntcolor = V_GREENMAP; if (cv_ticrate.value == 2) // compact counter - V_DrawString(vid.width-(24*vid.dupx), h, - ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%03.0f", aproxfps)); + V_DrawString(vid.width-(32*vid.dupx), h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%04.0f", fps)); else if (cv_ticrate.value == 1) // full counter { - V_DrawString(vid.width-(88*vid.dupx), h, + V_DrawString(vid.width-(104*vid.dupx), h, V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); - V_DrawString(vid.width-(56*vid.dupx), h, - ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%03.0f/%03u", aproxfps, TICRATE)); + V_DrawString(vid.width-(72*vid.dupx), h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%4.0f/%4u", fps, cap)); } } diff --git a/src/screen.h b/src/screen.h index 425d10954..bfb9e7fbf 100644 --- a/src/screen.h +++ b/src/screen.h @@ -181,7 +181,8 @@ extern boolean R_SSE2; extern viddef_t vid; extern INT32 setmodeneeded; // mode number to set if needed, or 0 extern UINT8 setrenderneeded; -extern double aproxfps; + +extern double averageFPS; void SCR_ChangeRenderer(void); @@ -212,7 +213,7 @@ void SCR_CheckDefaultMode(void); // Set the mode number which is saved in the config void SCR_SetDefaultMode(void); -void SCR_CalcAproxFps(void); +void SCR_CalculateFPS(void); FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index bf2e42cfd..6b9b11327 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -186,6 +186,7 @@ static char returnWadPath[256]; #include "../m_argv.h" #include "../r_main.h" // Frame interpolation/uncapped +#include "../r_fps.h" #ifdef MAC_ALERT #include "macosx/mac_alert.h" @@ -2200,6 +2201,57 @@ void I_Sleep(void) SDL_Delay(cv_sleep.value); } +boolean I_CheckFrameCap(precise_t start, precise_t end) +{ + UINT32 capFrames = R_GetFramerateCap(); + int capMicros = 0; + + int elapsed; + + if (capFrames == 0) + { + // We don't want to cap. + return false; + } + + elapsed = I_PreciseToMicros(end - start); + capMicros = 1000000 / capFrames; + + if (elapsed < capMicros) + { + // Wait to draw the next frame. + UINT32 wait = ((capMicros - elapsed) / 1000); + + if (cv_sleep.value > 1) + { + // 1 is the default, and in non-interpolated mode is just the bare minimum wait. + // Since we're already adding some wait with an FPS cap, only apply when it's above 1. + wait += cv_sleep.value - 1; + } + + // If the wait's greater than our granularity value, + // we'll just burn the couple extra cycles in the main loop + // in order to get to the next frame. + // This makes us get to the exact FPS cap more often. + + // Higher values have more wasted CPU cycles, but the in-game frame performance is better. + // 10ms is the average clock tick of most OS scheduling. + // 15ms is a little more than that, for leniency on slow machines. (This helps mine reach a stable 60, at least!) + // (https://www.libsdl.org/release/SDL-1.2.15/docs/html/sdldelay.html) +#define DELAY_GRANULARITY 15 + if (wait >= DELAY_GRANULARITY) + { + SDL_Delay(wait); + } +#undef DELAY_GRANULARITY + + return true; + } + + // Waited enough to draw again. + return false; +} + #ifdef NEWSIGNALHANDLER static void newsignalhandler_Warn(const char *pr) { diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index d8899e932..eedb60e09 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1214,7 +1214,7 @@ void I_FinishUpdate(void) if (rendermode == render_none) return; //Alam: No software or OpenGl surface - SCR_CalcAproxFps(); + //SCR_CalculateFPS(); // Moved to main loop if (I_SkipFrame()) return; @@ -1475,8 +1475,15 @@ static SDL_bool Impl_CreateContext(void) int flags = 0; // Use this to set SDL_RENDERER_* flags now if (usesdl2soft) flags |= SDL_RENDERER_SOFTWARE; +#if 0 + // This shit is BROKEN. + // - The version of SDL we're using cannot toggle VSync at runtime. We'll need a new SDL version implemented to have this work properly. + // - cv_vidwait is initialized before config is loaded, so it's forced to default value at runtime, and forced off when switching. The config loading code would need restructured. + // - With both this & frame interpolation on, I_FinishUpdate takes x10 longer. At this point, it is simpler to use a standard FPS cap. + // So you can probably guess why I'm kinda over this, I'm just disabling it. else if (cv_vidwait.value) flags |= SDL_RENDERER_PRESENTVSYNC; +#endif if (!renderer) renderer = SDL_CreateRenderer(window, -1, flags); @@ -1961,3 +1968,23 @@ void I_GetCursorPosition(INT32 *x, INT32 *y) { SDL_GetMouseState(x, y); } + +UINT32 I_GetRefreshRate(void) +{ + int index = SDL_GetWindowDisplayIndex(window); + SDL_DisplayMode m; + + if (SDL_WasInit(SDL_INIT_VIDEO) == 0) + { + // Video not init yet. + return 0; + } + + if (SDL_GetDesktopDisplayMode(index, &m) != 0) + { + // Error has occurred. + return 0; + } + + return m.refresh_rate; +} From a56a57b3d1093f0122d74e3e6277881973bb4a4b Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 16 Apr 2022 00:21:49 -0500 Subject: [PATCH 035/137] Misc changes after Kart cherry-picks --- src/m_menu.c | 10 +++++----- src/screen.c | 32 +++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 6383c106d..0ed7e6882 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1381,13 +1381,13 @@ static menuitem_t OP_VideoOptionsMenu[] = {IT_HEADER, NULL, "Diagnostic", NULL, 184}, {IT_STRING | IT_CVAR, NULL, "Show FPS", &cv_ticrate, 190}, - {IT_STRING | IT_CVAR, NULL, "FPS Cap", &cv_fpscap, 195}, - {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 200}, - {IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 205}, + {IT_STRING | IT_CVAR, NULL, "Clear Before Redraw", &cv_homremoval, 195}, + {IT_STRING | IT_CVAR, NULL, "Show \"FOCUS LOST\"", &cv_showfocuslost, 200}, #ifdef HWRENDER - {IT_HEADER, NULL, "Renderer", NULL, 213}, - {IT_CALL | IT_STRING, NULL, "OpenGL Options...", M_OpenGLOptionsMenu, 219}, + {IT_HEADER, NULL, "Renderer", NULL, 208}, + {IT_CALL | IT_STRING, NULL, "OpenGL Options...", M_OpenGLOptionsMenu, 214}, + {IT_STRING | IT_CVAR, NULL, "FPS Cap", &cv_fpscap, 219}, #endif }; diff --git a/src/screen.c b/src/screen.c index 88898c503..b51b5472f 100644 --- a/src/screen.c +++ b/src/screen.c @@ -451,7 +451,6 @@ boolean SCR_IsAspectCorrect(INT32 width, INT32 height) ); } -static tic_t totaltics; double averageFPS = 0.0f; #define FPS_SAMPLE_RATE (50000) // How often to update FPS samples, in microseconds @@ -515,18 +514,37 @@ void SCR_DisplayTicRate(void) if (gamestate == GS_NULL) return; - if (totaltics <= cap/2) ticcntcolor = V_REDMAP; - else if (totaltics >= cap) ticcntcolor = V_GREENMAP; + if (cap > 0) + { + if (fps <= cap / 2.0) ticcntcolor = V_REDMAP; + else if (fps <= cap * 0.90) ticcntcolor = V_YELLOWMAP; + else ticcntcolor = V_GREENMAP; + } + else + { + ticcntcolor = V_GREENMAP; + } + if (cv_ticrate.value == 2) // compact counter V_DrawString(vid.width-(32*vid.dupx), h, ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%04.0f", fps)); else if (cv_ticrate.value == 1) // full counter { - V_DrawString(vid.width-(104*vid.dupx), h, - V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); - V_DrawString(vid.width-(72*vid.dupx), h, - ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%4.0f/%4u", fps, cap)); + if (cap > 0) + { + V_DrawString(vid.width-(104*vid.dupx), h, + V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); + V_DrawString(vid.width-(72*vid.dupx), h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%4.0f/%4u", fps, cap)); + } + else + { + V_DrawString(vid.width-(88*vid.dupx), h, + V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); + V_DrawString(vid.width-(56*vid.dupx), h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%4.0f", fps)); + } } } From 84f62f91f453abf68f49234b457a3304483143a3 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 16 Apr 2022 00:41:34 -0500 Subject: [PATCH 036/137] Fix renderdeltatics with new timing data --- src/d_main.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index bb01976cd..fcff182a9 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -897,12 +897,7 @@ void D_SRB2Loop(void) } // renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based - renderdeltatics = realtics * FRACUNIT; - if (entertimefrac > rendertimefrac) - renderdeltatics += entertimefrac - rendertimefrac; - else - renderdeltatics -= rendertimefrac - entertimefrac; - + renderdeltatics = FloatToFixed(entertime - prevtime); rendertimefrac = entertimefrac; } From 0e1b01f2067a87ad768a4b5c2491fecd29bb1e61 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 16 Apr 2022 02:40:10 -0500 Subject: [PATCH 037/137] Update mobj oldstates before all thinkers --- src/p_map.c | 2 +- src/p_mobj.c | 95 ++++++++++++++++++++++++++++++++++++++++++++------- src/p_mobj.h | 8 +++-- src/p_setup.c | 1 + src/p_tick.c | 2 ++ 5 files changed, 93 insertions(+), 15 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index 1f02123d5..fe67ad49c 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -103,7 +103,7 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) thing->floorrover = tmfloorrover; thing->ceilingrover = tmceilingrover; - P_ResetInterpolationState(thing); + P_ResetMobjInterpolationState(thing); return true; } diff --git a/src/p_mobj.c b/src/p_mobj.c index 57af599cf..6b413bcd5 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -42,6 +42,77 @@ actioncache_t actioncachehead; static mobj_t *overlaycap = NULL; +static mobj_t **interpolated_mobjs = NULL; +static size_t interpolated_mobjs_len = 0; +static size_t interpolated_mobjs_capacity = 0; + +// NOTE: This will NOT check that the mobj has already been added, for perf +// reasons. +static void AddInterpolatedMobj(mobj_t *mobj) +{ + if (interpolated_mobjs_len >= interpolated_mobjs_capacity) + { + if (interpolated_mobjs_capacity == 0) + { + interpolated_mobjs_capacity = 256; + } + else + { + interpolated_mobjs_capacity *= 2; + } + + interpolated_mobjs = Z_ReallocAlign( + interpolated_mobjs, + sizeof(mobj_t *) * interpolated_mobjs_capacity, + PU_LEVEL, + NULL, + 64 + ); + } + + interpolated_mobjs[interpolated_mobjs_len] = mobj; + interpolated_mobjs_len += 1; +} + +static void RemoveInterpolatedMobj(mobj_t *mobj) +{ + size_t i; + + if (interpolated_mobjs_len == 0) return; + + for (i = 0; i < interpolated_mobjs_len - 1; i++) + { + if (interpolated_mobjs[i] == mobj) + { + interpolated_mobjs[i] = interpolated_mobjs[ + interpolated_mobjs_len - 1 + ]; + interpolated_mobjs_len -= 1; + return; + } + } +} + +void P_InitMobjInterpolators(void) +{ + // apparently it's not acceptable to free something already unallocated + // Z_Free(interpolated_mobjs); + interpolated_mobjs = NULL; + interpolated_mobjs_len = 0; + interpolated_mobjs_capacity = 0; +} + +void P_UpdateMobjInterpolators(void) +{ + size_t i; + for (i = 0; i < interpolated_mobjs_len; i++) + { + mobj_t *mobj = interpolated_mobjs[i]; + if (!P_MobjWasRemoved(mobj)) + P_ResetMobjInterpolationState(mobj); + } +} + void P_InitCachedActions(void) { actioncachehead.prev = actioncachehead.next = &actioncachehead; @@ -893,11 +964,11 @@ void P_EmeraldManager(void) } // -// P_ResetInterpolationState +// P_ResetMobjInterpolationState // // Reset the rendering interpolation state of the mobj. // -void P_ResetInterpolationState(mobj_t *mobj) +void P_ResetMobjInterpolationState(mobj_t *mobj) { mobj->old_x = mobj->x; mobj->old_y = mobj->y; @@ -913,11 +984,11 @@ void P_ResetInterpolationState(mobj_t *mobj) } // -// P_ResetPrecipitationInterpolationState +// P_ResetPrecipitationMobjInterpolationState // // Reset the rendering interpolation state of the precipmobj. // -void P_ResetPrecipitationInterpolationState(precipmobj_t *mobj) +void P_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj) { mobj->old_x = mobj->x; mobj->old_y = mobj->y; @@ -4059,7 +4130,7 @@ void P_NullPrecipThinker(precipmobj_t *mobj) void P_SnowThinker(precipmobj_t *mobj) { - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); P_CycleStateAnimation((mobj_t *)mobj); @@ -4067,13 +4138,13 @@ void P_SnowThinker(precipmobj_t *mobj) if ((mobj->z += mobj->momz) <= mobj->floorz) { mobj->z = mobj->ceilingz; - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); } } void P_RainThinker(precipmobj_t *mobj) { - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); P_CycleStateAnimation((mobj_t *)mobj); @@ -4094,7 +4165,7 @@ void P_RainThinker(precipmobj_t *mobj) return; mobj->z = mobj->ceilingz; - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); P_SetPrecipMobjState(mobj, S_RAIN1); return; @@ -10072,8 +10143,6 @@ void P_MobjThinker(mobj_t *mobj) I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); - P_ResetInterpolationState(mobj); - if (mobj->flags & MF_NOTHINK) return; @@ -10939,7 +11008,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if (CheckForReverseGravity && !(mobj->flags & MF_NOBLOCKMAP)) P_CheckGravity(mobj, false); - P_ResetInterpolationState(mobj); + AddInterpolatedMobj(mobj); return mobj; } @@ -10988,7 +11057,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype || mobj->subsector->sector->floorpic == skyflatnum) mobj->precipflags |= PCF_PIT; - P_ResetPrecipitationInterpolationState(mobj); + P_ResetPrecipitationMobjInterpolationState(mobj); return mobj; } @@ -11109,6 +11178,8 @@ void P_RemoveMobj(mobj_t *mobj) memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t)); #endif + RemoveInterpolatedMobj(mobj); + // free block if (!mobj->thinker.next) { // Uh-oh, the mobj doesn't think, P_RemoveThinker would never go through! diff --git a/src/p_mobj.h b/src/p_mobj.h index 371dc49dc..455954ca3 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -503,8 +503,12 @@ void P_RingZMovement(mobj_t *mo); boolean P_SceneryZMovement(mobj_t *mo); void P_PlayerZMovement(mobj_t *mo); void P_EmeraldManager(void); -void P_ResetInterpolationState(mobj_t *mobj); -void P_ResetPrecipitationInterpolationState(precipmobj_t *mobj); + +// Initialize internal mobj interpolator list (e.g. during level loading) +void P_InitMobjInterpolators(void); +void P_UpdateMobjInterpolators(void); +void P_ResetMobjInterpolationState(mobj_t *mobj); +void P_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj); extern INT32 modulothing; diff --git a/src/p_setup.c b/src/p_setup.c index 65e7b5886..063c1b975 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4376,6 +4376,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) R_InitializeLevelInterpolators(); P_InitThinkers(); + P_InitMobjInterpolators(); P_InitCachedActions(); if (!fromnetsave && savedata.lives > 0) diff --git a/src/p_tick.c b/src/p_tick.c index e244de1c6..7773dec55 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -642,6 +642,8 @@ void P_Ticker(boolean run) if (run) { + P_UpdateMobjInterpolators(); + if (demorecording) G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); if (demoplayback) From 6e5e74b25f796a8f280faa902dc078e1795b436d Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 16 Apr 2022 12:36:40 -0400 Subject: [PATCH 038/137] Allow FPS cap values --- src/command.c | 3 ++- src/r_fps.c | 33 ++++++++++++++------------------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/command.c b/src/command.c index 50310f112..723388058 100644 --- a/src/command.c +++ b/src/command.c @@ -2076,9 +2076,10 @@ void CV_AddValue(consvar_t *var, INT32 increment) { increment = 0; currentindice = max; + break; // The value we definitely want, stop here. } else if (var->PossibleValue[max].value == var->value) - currentindice = max; + currentindice = max; // The value we maybe want. } if (increment) diff --git a/src/r_fps.c b/src/r_fps.c index 9c3a9db53..136cdfe9e 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -27,36 +27,31 @@ #endif static CV_PossibleValue_t fpscap_cons_t[] = { - {-1, "Match refresh rate"}, - {0, "Unlimited"}, #ifdef DEVELOP // Lower values are actually pretty useful for debugging interp problems! - {1, "One Singular Frame"}, - {10, "10"}, - {20, "20"}, - {25, "25"}, - {30, "30"}, + {1, "MIN"}, +#else + {TICRATE, "MIN"}, #endif - {35, "35"}, - {50, "50"}, - {60, "60"}, - {70, "70"}, - {75, "75"}, - {90, "90"}, - {100, "100"}, - {120, "120"}, - {144, "144"}, - {200, "200"}, - {240, "240"}, + {300, "MAX"}, + {-1, "Unlimited"}, + {0, "Match refresh rate"}, {0, NULL} }; consvar_t cv_fpscap = CVAR_INIT ("fpscap", "Match refresh rate", CV_SAVE, fpscap_cons_t, NULL); UINT32 R_GetFramerateCap(void) { + if (cv_fpscap.value == 0) + { + // 0: Match refresh rate + return I_GetRefreshRate(); + } + if (cv_fpscap.value < 0) { - return I_GetRefreshRate(); + // -1: Unlimited + return 0; } return cv_fpscap.value; From 53c71d35bcc46bca37445747d2091ce4750d72cd Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 16 Apr 2022 02:58:43 -0400 Subject: [PATCH 039/137] Adjust how FPS cap is checked to improve FPS stability --- src/d_main.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index fcff182a9..731710a9c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -723,6 +723,7 @@ void D_SRB2Loop(void) boolean ticked; boolean interp; boolean doDisplay = false; + boolean frameCap = false; if (dedicated) server = true; @@ -803,11 +804,25 @@ void D_SRB2Loop(void) doDisplay = false; ticked = false; - if (!realtics && !singletics && !interp) + frameCap = false; + if (interp) { - // Non-interp sleep - I_Sleep(); - continue; + frameCap = D_CheckFrameCap(); + } + + if (!realtics && !singletics) + { + if (interp) + { + if (frameCap) + continue; + } + else + { + // Non-interp sleep + I_Sleep(); + continue; + } } #ifdef HW3SOUND @@ -869,7 +884,7 @@ void D_SRB2Loop(void) // TryRunTics needs ran if possible to prevent lagged map changes, // (and if that runs, the code above needs to also run) // so this is done here after TryRunTics. - if (D_CheckFrameCap()) + if (frameCap) { continue; } From 66cc234be682228e07067c42f70ae302d81a86ce Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 16 Apr 2022 23:05:44 -0500 Subject: [PATCH 040/137] Fix precip crash from missing vars --- src/p_mobj.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.h b/src/p_mobj.h index 455954ca3..5ba79e717 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -416,7 +416,7 @@ typedef struct precipmobj_s // More drawing info: to determine current sprite. angle_t angle, pitch, roll; // orientation - angle_t old_angle; + angle_t old_angle, old_pitch, old_roll; // orientation interpolation angle_t rollangle; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h From 685190fe40bb3efaeaacbab53e0b6b0b74c90f4b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 18 Apr 2022 17:18:31 -0400 Subject: [PATCH 041/137] Improve the framerate limiter's timing for extreme stable FPS --- src/d_main.c | 32 ++++++++++----------------- src/sdl/i_system.c | 55 +++++++++++++++++++++++++++------------------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 731710a9c..470ec4fb7 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -804,25 +804,17 @@ void D_SRB2Loop(void) doDisplay = false; ticked = false; - frameCap = false; - if (interp) - { - frameCap = D_CheckFrameCap(); - } + frameCap = D_CheckFrameCap(); + + // Moved to here from I_FinishUpdate. + // It doesn't track fades properly anymore by being here (might be easy fix), + // but it's a little more accurate for actual rendering when its here. + SCR_CalculateFPS(); if (!realtics && !singletics) { - if (interp) - { - if (frameCap) - continue; - } - else - { - // Non-interp sleep - I_Sleep(); + if (frameCap) continue; - } } #ifdef HW3SOUND @@ -920,6 +912,11 @@ void D_SRB2Loop(void) } else { + if (frameCap) + { + continue; + } + renderdeltatics = realtics * FRACUNIT; rendertimefrac = FRACUNIT; } @@ -943,11 +940,6 @@ void D_SRB2Loop(void) #endif LUA_Step(); - - // Moved to here from I_FinishUpdate. - // It doesn't track fades properly anymore by being here (might be easy fix), - // but it's a little more accurate for actual game logic when its here. - SCR_CalculateFPS(); } } diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 6b9b11327..b3db8b455 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2203,7 +2203,7 @@ void I_Sleep(void) boolean I_CheckFrameCap(precise_t start, precise_t end) { - UINT32 capFrames = R_GetFramerateCap(); + const UINT32 capFrames = R_GetFramerateCap(); int capMicros = 0; int elapsed; @@ -2219,31 +2219,42 @@ boolean I_CheckFrameCap(precise_t start, precise_t end) if (elapsed < capMicros) { - // Wait to draw the next frame. - UINT32 wait = ((capMicros - elapsed) / 1000); - - if (cv_sleep.value > 1) + // Experimental variable delay code. + if (cv_sleep.value > 0) { - // 1 is the default, and in non-interpolated mode is just the bare minimum wait. - // Since we're already adding some wait with an FPS cap, only apply when it's above 1. - wait += cv_sleep.value - 1; - } + const INT64 delayGranularity = 2000; // 2ms, I picked this as it's what GZDoom uses before it stops trying to sleep. + INT64 wait = (capMicros - elapsed); - // If the wait's greater than our granularity value, - // we'll just burn the couple extra cycles in the main loop - // in order to get to the next frame. - // This makes us get to the exact FPS cap more often. + while (wait > 0) + { + precise_t sleepStart = I_GetPreciseTime(); + precise_t sleepEnd = sleepStart; + int sleepElasped = 0; - // Higher values have more wasted CPU cycles, but the in-game frame performance is better. - // 10ms is the average clock tick of most OS scheduling. - // 15ms is a little more than that, for leniency on slow machines. (This helps mine reach a stable 60, at least!) - // (https://www.libsdl.org/release/SDL-1.2.15/docs/html/sdldelay.html) -#define DELAY_GRANULARITY 15 - if (wait >= DELAY_GRANULARITY) - { - SDL_Delay(wait); + if (wait > delayGranularity) + { + // Wait 1ms at a time (on default settings) + // until we're close enough. + SDL_Delay(cv_sleep.value); + + sleepEnd = I_GetPreciseTime(); + sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart); + } + else + { + // When we have an extremely fine wait, + // we do this to spin-lock the remaining time. + + while (sleepElasped < wait) + { + sleepEnd = I_GetPreciseTime(); + sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart); + } + } + + wait -= sleepElasped; + } } -#undef DELAY_GRANULARITY return true; } From b18e53417af84f4f30f972213e0dade3ad640942 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 19 Apr 2022 12:06:17 -0400 Subject: [PATCH 042/137] Handle the sleep at the end of D_SRB2Loop instead of the start Simplifies logic in the other parts of the loop, and fixes problems with it frequently waiting too long. --- src/d_main.c | 75 +++++++++++++------------------------------- src/i_system.h | 8 +++-- src/screen.c | 9 +++--- src/sdl/i_system.c | 77 +++++++++++++++++++++++++++------------------- 4 files changed, 79 insertions(+), 90 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 470ec4fb7..f29fdd224 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -687,29 +687,6 @@ static void D_Display(void) } } -static boolean D_CheckFrameCap(void) -{ - static boolean init = false; - static precise_t startCap = 0; - precise_t endCap = 0; - - endCap = I_GetPreciseTime(); - - if (init == false) - { - startCap = endCap; - init = true; - } - else if (I_CheckFrameCap(startCap, endCap)) - { - // Framerate should be capped. - return true; - } - - startCap = endCap; - return false; -} - // ========================================================================= // D_SRB2Loop // ========================================================================= @@ -720,10 +697,13 @@ void D_SRB2Loop(void) { tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS; static lumpnum_t gstartuplumpnum; - boolean ticked; - boolean interp; + + boolean ticked = false; + boolean interp = false; boolean doDisplay = false; - boolean frameCap = false; + + precise_t frameTime = 0; + int frameElapsed = 0; if (dedicated) server = true; @@ -775,6 +755,9 @@ void D_SRB2Loop(void) for (;;) { + frameTime = I_GetPreciseTime(); + frameElapsed = 0; + if (lastwipetic) { oldentertics = lastwipetic; @@ -804,19 +787,6 @@ void D_SRB2Loop(void) doDisplay = false; ticked = false; - frameCap = D_CheckFrameCap(); - - // Moved to here from I_FinishUpdate. - // It doesn't track fades properly anymore by being here (might be easy fix), - // but it's a little more accurate for actual rendering when its here. - SCR_CalculateFPS(); - - if (!realtics && !singletics) - { - if (frameCap) - continue; - } - #ifdef HW3SOUND HW3S_BeginFrameUpdate(); #endif @@ -872,15 +842,6 @@ void D_SRB2Loop(void) tictime = entertime; } - // Handle interp sleep / framerate cap here. - // TryRunTics needs ran if possible to prevent lagged map changes, - // (and if that runs, the code above needs to also run) - // so this is done here after TryRunTics. - if (frameCap) - { - continue; - } - if (!(paused || P_AutoPause())) { #if 0 @@ -912,11 +873,6 @@ void D_SRB2Loop(void) } else { - if (frameCap) - { - continue; - } - renderdeltatics = realtics * FRACUNIT; rendertimefrac = FRACUNIT; } @@ -940,6 +896,19 @@ void D_SRB2Loop(void) #endif LUA_Step(); + + // Moved to here from I_FinishUpdate. + // It doesn't track fades properly anymore by being here (might be easy fix), + // but it's a little more accurate for actual rendering when its here. + SCR_CalculateFPS(); + + // Fully completed frame made, handle frame cap delay. + frameElapsed = I_PreciseToMicros(I_GetPreciseTime() - frameTime); + + if (!singletics) + { + I_FrameCapSleep(frameElapsed); + } } } diff --git a/src/i_system.h b/src/i_system.h index fefe0a7c1..f813135ce 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -58,13 +58,17 @@ precise_t I_GetPreciseTime(void); */ int I_PreciseToMicros(precise_t d); -/** \brief The I_Sleep function +/** \brief Sleeps by the value of cv_sleep \return void */ void I_Sleep(void); -boolean I_CheckFrameCap(precise_t start, precise_t end); +/** \brief Sleeps for a variable amount of time, depending on how much time the last frame took. + + \return void +*/ +boolean I_FrameCapSleep(const int elapsed); /** \brief Get events diff --git a/src/screen.c b/src/screen.c index b51b5472f..6ad36273b 100644 --- a/src/screen.c +++ b/src/screen.c @@ -509,7 +509,7 @@ void SCR_DisplayTicRate(void) INT32 ticcntcolor = 0; const INT32 h = vid.height-(8*vid.dupy); UINT32 cap = R_GetFramerateCap(); - double fps = ceil(averageFPS); + double fps = round(averageFPS); if (gamestate == GS_NULL) return; @@ -525,10 +525,11 @@ void SCR_DisplayTicRate(void) ticcntcolor = V_GREENMAP; } - if (cv_ticrate.value == 2) // compact counter - V_DrawString(vid.width-(32*vid.dupx), h, - ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%04.0f", fps)); + { + V_DrawRightAlignedString(vid.width, h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%04.2f", averageFPS)); // use averageFPS directly + } else if (cv_ticrate.value == 1) // full counter { if (cap > 0) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index b3db8b455..428186f30 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2167,6 +2167,10 @@ float I_GetTimeFrac(void) return elapsed_tics; } +// +// I_GetPreciseTime +// returns time in precise_t +// precise_t I_GetPreciseTime(void) { return SDL_GetPerformanceCounter(); @@ -2184,7 +2188,7 @@ int I_PreciseToMicros(precise_t d) } // -//I_StartupTimer +// I_StartupTimer // void I_StartupTimer(void) { @@ -2195,71 +2199,82 @@ void I_StartupTimer(void) elapsed_tics = 0.0; } +// +// I_Sleep +// Sleeps by the value of cv_sleep +// void I_Sleep(void) { if (cv_sleep.value != -1) SDL_Delay(cv_sleep.value); } -boolean I_CheckFrameCap(precise_t start, precise_t end) +// +// I_FrameCapSleep +// Sleeps for a variable amount of time, depending on how much time the last frame took. +// +boolean I_FrameCapSleep(const int elapsed) { + const INT64 delayGranularity = 2000; + // I picked 2ms as it's what GZDoom uses before it stops trying to sleep, + // but maybe other values might work better. + const UINT32 capFrames = R_GetFramerateCap(); int capMicros = 0; - int elapsed; - if (capFrames == 0) { // We don't want to cap. return false; } - elapsed = I_PreciseToMicros(end - start); capMicros = 1000000 / capFrames; if (elapsed < capMicros) { - // Experimental variable delay code. - if (cv_sleep.value > 0) + const INT64 error = capMicros / 40; + // 2.5% ... How much we might expect the framerate to flucuate. + // No exact logic behind this number, simply tried stuff until the framerate + // reached the cap 300 more often and only overshot it occasionally. + + INT64 wait = (capMicros - elapsed) - error; + + while (wait > 0) { - const INT64 delayGranularity = 2000; // 2ms, I picked this as it's what GZDoom uses before it stops trying to sleep. - INT64 wait = (capMicros - elapsed); + precise_t sleepStart = I_GetPreciseTime(); + precise_t sleepEnd = sleepStart; + int sleepElasped = 0; - while (wait > 0) + if (wait > delayGranularity && cv_sleep.value != -1) { - precise_t sleepStart = I_GetPreciseTime(); - precise_t sleepEnd = sleepStart; - int sleepElasped = 0; + // Wait 1ms at a time (on default settings) + // until we're close enough. + SDL_Delay(cv_sleep.value); - if (wait > delayGranularity) + sleepEnd = I_GetPreciseTime(); + sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart); + } + else + { + // When we have an extremely fine wait, + // we do this to spin-lock the remaining time. + while (sleepElasped < wait) { - // Wait 1ms at a time (on default settings) - // until we're close enough. - SDL_Delay(cv_sleep.value); - sleepEnd = I_GetPreciseTime(); sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart); } - else - { - // When we have an extremely fine wait, - // we do this to spin-lock the remaining time. - while (sleepElasped < wait) - { - sleepEnd = I_GetPreciseTime(); - sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart); - } - } - - wait -= sleepElasped; + break; } + + wait -= sleepElasped; } + // We took our nap. return true; } - // Waited enough to draw again. + // We're lagging behind. return false; } From 5e4a57b45c8672c2b2fece69e0bbe4e8f7e8a1d0 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 21 Apr 2022 23:56:54 -0500 Subject: [PATCH 043/137] Reset mobj interp state on add --- src/p_mobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 6b413bcd5..6c9dc59af 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -72,6 +72,8 @@ static void AddInterpolatedMobj(mobj_t *mobj) interpolated_mobjs[interpolated_mobjs_len] = mobj; interpolated_mobjs_len += 1; + + P_ResetMobjInterpolationState(mobj); } static void RemoveInterpolatedMobj(mobj_t *mobj) From a67432a415bea5ea42cb5adf05588c9f13a6611a Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 23 Apr 2022 12:49:54 -0500 Subject: [PATCH 044/137] Add mobj interpolator on load netgame --- src/p_mobj.c | 4 ++-- src/p_mobj.h | 2 ++ src/p_saveg.c | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 6c9dc59af..cda1c3cf7 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -48,7 +48,7 @@ static size_t interpolated_mobjs_capacity = 0; // NOTE: This will NOT check that the mobj has already been added, for perf // reasons. -static void AddInterpolatedMobj(mobj_t *mobj) +void P_AddMobjInterpolator(mobj_t *mobj) { if (interpolated_mobjs_len >= interpolated_mobjs_capacity) { @@ -11010,7 +11010,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if (CheckForReverseGravity && !(mobj->flags & MF_NOBLOCKMAP)) P_CheckGravity(mobj, false); - AddInterpolatedMobj(mobj); + P_AddMobjInterpolator(mobj); return mobj; } diff --git a/src/p_mobj.h b/src/p_mobj.h index 5ba79e717..9b5a215a2 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -506,6 +506,8 @@ void P_EmeraldManager(void); // Initialize internal mobj interpolator list (e.g. during level loading) void P_InitMobjInterpolators(void); +// Add interpolation state for the given mobj +void P_AddMobjInterpolator(mobj_t *mobj); void P_UpdateMobjInterpolators(void); void P_ResetMobjInterpolationState(mobj_t *mobj); void P_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj); diff --git a/src/p_saveg.c b/src/p_saveg.c index 46b509d19..eed594198 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2969,6 +2969,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function + P_AddMobjInterpolator(mobj); + return &mobj->thinker; } From 568677edc14cbd44415f6758afe988f8c72cbe9c Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 23 Apr 2022 13:13:58 -0500 Subject: [PATCH 045/137] Move mobj interpolators to r_fps --- src/p_map.c | 3 +- src/p_mobj.c | 121 ++++---------------------------------------------- src/p_mobj.h | 8 ---- src/p_saveg.c | 3 +- src/p_setup.c | 2 +- src/p_tick.c | 2 +- src/r_fps.c | 106 +++++++++++++++++++++++++++++++++++++++++++ src/r_fps.h | 10 +++++ 8 files changed, 130 insertions(+), 125 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index fe67ad49c..e9d289e2d 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -19,6 +19,7 @@ #include "m_random.h" #include "p_local.h" #include "p_setup.h" // NiGHTS stuff +#include "r_fps.h" #include "r_state.h" #include "r_main.h" #include "r_sky.h" @@ -103,7 +104,7 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) thing->floorrover = tmfloorrover; thing->ceilingrover = tmceilingrover; - P_ResetMobjInterpolationState(thing); + R_ResetMobjInterpolationState(thing); return true; } diff --git a/src/p_mobj.c b/src/p_mobj.c index cda1c3cf7..eb939c968 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -18,6 +18,7 @@ #include "hu_stuff.h" #include "p_local.h" #include "p_setup.h" +#include "r_fps.h" #include "r_main.h" #include "r_skins.h" #include "r_sky.h" @@ -42,79 +43,6 @@ actioncache_t actioncachehead; static mobj_t *overlaycap = NULL; -static mobj_t **interpolated_mobjs = NULL; -static size_t interpolated_mobjs_len = 0; -static size_t interpolated_mobjs_capacity = 0; - -// NOTE: This will NOT check that the mobj has already been added, for perf -// reasons. -void P_AddMobjInterpolator(mobj_t *mobj) -{ - if (interpolated_mobjs_len >= interpolated_mobjs_capacity) - { - if (interpolated_mobjs_capacity == 0) - { - interpolated_mobjs_capacity = 256; - } - else - { - interpolated_mobjs_capacity *= 2; - } - - interpolated_mobjs = Z_ReallocAlign( - interpolated_mobjs, - sizeof(mobj_t *) * interpolated_mobjs_capacity, - PU_LEVEL, - NULL, - 64 - ); - } - - interpolated_mobjs[interpolated_mobjs_len] = mobj; - interpolated_mobjs_len += 1; - - P_ResetMobjInterpolationState(mobj); -} - -static void RemoveInterpolatedMobj(mobj_t *mobj) -{ - size_t i; - - if (interpolated_mobjs_len == 0) return; - - for (i = 0; i < interpolated_mobjs_len - 1; i++) - { - if (interpolated_mobjs[i] == mobj) - { - interpolated_mobjs[i] = interpolated_mobjs[ - interpolated_mobjs_len - 1 - ]; - interpolated_mobjs_len -= 1; - return; - } - } -} - -void P_InitMobjInterpolators(void) -{ - // apparently it's not acceptable to free something already unallocated - // Z_Free(interpolated_mobjs); - interpolated_mobjs = NULL; - interpolated_mobjs_len = 0; - interpolated_mobjs_capacity = 0; -} - -void P_UpdateMobjInterpolators(void) -{ - size_t i; - for (i = 0; i < interpolated_mobjs_len; i++) - { - mobj_t *mobj = interpolated_mobjs[i]; - if (!P_MobjWasRemoved(mobj)) - P_ResetMobjInterpolationState(mobj); - } -} - void P_InitCachedActions(void) { actioncachehead.prev = actioncachehead.next = &actioncachehead; @@ -965,39 +893,6 @@ void P_EmeraldManager(void) emeraldspawndelay = 0; } -// -// P_ResetMobjInterpolationState -// -// Reset the rendering interpolation state of the mobj. -// -void P_ResetMobjInterpolationState(mobj_t *mobj) -{ - mobj->old_x = mobj->x; - mobj->old_y = mobj->y; - mobj->old_z = mobj->z; - mobj->old_angle = mobj->angle; - mobj->old_pitch = mobj->pitch; - mobj->old_roll = mobj->roll; - - if (mobj->player) - { - mobj->player->old_drawangle = mobj->player->drawangle; - } -} - -// -// P_ResetPrecipitationMobjInterpolationState -// -// Reset the rendering interpolation state of the precipmobj. -// -void P_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj) -{ - mobj->old_x = mobj->x; - mobj->old_y = mobj->y; - mobj->old_z = mobj->z; - mobj->old_angle = mobj->angle; -} - // // P_ExplodeMissile // @@ -4132,7 +4027,7 @@ void P_NullPrecipThinker(precipmobj_t *mobj) void P_SnowThinker(precipmobj_t *mobj) { - P_ResetPrecipitationMobjInterpolationState(mobj); + R_ResetPrecipitationMobjInterpolationState(mobj); P_CycleStateAnimation((mobj_t *)mobj); @@ -4140,13 +4035,13 @@ void P_SnowThinker(precipmobj_t *mobj) if ((mobj->z += mobj->momz) <= mobj->floorz) { mobj->z = mobj->ceilingz; - P_ResetPrecipitationMobjInterpolationState(mobj); + R_ResetPrecipitationMobjInterpolationState(mobj); } } void P_RainThinker(precipmobj_t *mobj) { - P_ResetPrecipitationMobjInterpolationState(mobj); + R_ResetPrecipitationMobjInterpolationState(mobj); P_CycleStateAnimation((mobj_t *)mobj); @@ -4167,7 +4062,7 @@ void P_RainThinker(precipmobj_t *mobj) return; mobj->z = mobj->ceilingz; - P_ResetPrecipitationMobjInterpolationState(mobj); + R_ResetPrecipitationMobjInterpolationState(mobj); P_SetPrecipMobjState(mobj, S_RAIN1); return; @@ -11010,7 +10905,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) if (CheckForReverseGravity && !(mobj->flags & MF_NOBLOCKMAP)) P_CheckGravity(mobj, false); - P_AddMobjInterpolator(mobj); + R_AddMobjInterpolator(mobj); return mobj; } @@ -11059,7 +10954,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype || mobj->subsector->sector->floorpic == skyflatnum) mobj->precipflags |= PCF_PIT; - P_ResetPrecipitationMobjInterpolationState(mobj); + R_ResetPrecipitationMobjInterpolationState(mobj); return mobj; } @@ -11180,7 +11075,7 @@ void P_RemoveMobj(mobj_t *mobj) memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t)); #endif - RemoveInterpolatedMobj(mobj); + R_RemoveMobjInterpolator(mobj); // free block if (!mobj->thinker.next) diff --git a/src/p_mobj.h b/src/p_mobj.h index 9b5a215a2..e4c57beec 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -504,14 +504,6 @@ boolean P_SceneryZMovement(mobj_t *mo); void P_PlayerZMovement(mobj_t *mo); void P_EmeraldManager(void); -// Initialize internal mobj interpolator list (e.g. during level loading) -void P_InitMobjInterpolators(void); -// Add interpolation state for the given mobj -void P_AddMobjInterpolator(mobj_t *mobj); -void P_UpdateMobjInterpolators(void); -void P_ResetMobjInterpolationState(mobj_t *mobj); -void P_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj); - extern INT32 modulothing; #define MAXHUNTEMERALDS 64 diff --git a/src/p_saveg.c b/src/p_saveg.c index eed594198..d493ae013 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -22,6 +22,7 @@ #include "p_setup.h" #include "p_saveg.h" #include "r_data.h" +#include "r_fps.h" #include "r_textures.h" #include "r_things.h" #include "r_skins.h" @@ -2969,7 +2970,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function - P_AddMobjInterpolator(mobj); + R_AddMobjInterpolator(mobj); return &mobj->thinker; } diff --git a/src/p_setup.c b/src/p_setup.c index 063c1b975..0e7432bbf 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4376,7 +4376,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) R_InitializeLevelInterpolators(); P_InitThinkers(); - P_InitMobjInterpolators(); + R_InitMobjInterpolators(); P_InitCachedActions(); if (!fromnetsave && savedata.lives > 0) diff --git a/src/p_tick.c b/src/p_tick.c index 7773dec55..a388ab3f2 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -642,7 +642,7 @@ void P_Ticker(boolean run) if (run) { - P_UpdateMobjInterpolators(); + R_UpdateMobjInterpolators(); if (demorecording) G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0); diff --git a/src/r_fps.c b/src/r_fps.c index 136cdfe9e..5c0c8f6df 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -556,3 +556,109 @@ void R_DestroyLevelInterpolators(thinker_t *thinker) } } } + +static mobj_t **interpolated_mobjs = NULL; +static size_t interpolated_mobjs_len = 0; +static size_t interpolated_mobjs_capacity = 0; + +// NOTE: This will NOT check that the mobj has already been added, for perf +// reasons. +void R_AddMobjInterpolator(mobj_t *mobj) +{ + if (interpolated_mobjs_len >= interpolated_mobjs_capacity) + { + if (interpolated_mobjs_capacity == 0) + { + interpolated_mobjs_capacity = 256; + } + else + { + interpolated_mobjs_capacity *= 2; + } + + interpolated_mobjs = Z_ReallocAlign( + interpolated_mobjs, + sizeof(mobj_t *) * interpolated_mobjs_capacity, + PU_LEVEL, + NULL, + 64 + ); + } + + interpolated_mobjs[interpolated_mobjs_len] = mobj; + interpolated_mobjs_len += 1; + + R_ResetMobjInterpolationState(mobj); +} + +void R_RemoveMobjInterpolator(mobj_t *mobj) +{ + size_t i; + + if (interpolated_mobjs_len == 0) return; + + for (i = 0; i < interpolated_mobjs_len - 1; i++) + { + if (interpolated_mobjs[i] == mobj) + { + interpolated_mobjs[i] = interpolated_mobjs[ + interpolated_mobjs_len - 1 + ]; + interpolated_mobjs_len -= 1; + return; + } + } +} + +void R_InitMobjInterpolators(void) +{ + // apparently it's not acceptable to free something already unallocated + // Z_Free(interpolated_mobjs); + interpolated_mobjs = NULL; + interpolated_mobjs_len = 0; + interpolated_mobjs_capacity = 0; +} + +void R_UpdateMobjInterpolators(void) +{ + size_t i; + for (i = 0; i < interpolated_mobjs_len; i++) + { + mobj_t *mobj = interpolated_mobjs[i]; + if (!P_MobjWasRemoved(mobj)) + R_ResetMobjInterpolationState(mobj); + } +} + +// +// P_ResetMobjInterpolationState +// +// Reset the rendering interpolation state of the mobj. +// +void R_ResetMobjInterpolationState(mobj_t *mobj) +{ + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; + mobj->old_angle = mobj->angle; + mobj->old_pitch = mobj->pitch; + mobj->old_roll = mobj->roll; + + if (mobj->player) + { + mobj->player->old_drawangle = mobj->player->drawangle; + } +} + +// +// P_ResetPrecipitationMobjInterpolationState +// +// Reset the rendering interpolation state of the precipmobj. +// +void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj) +{ + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; + mobj->old_angle = mobj->angle; +} diff --git a/src/r_fps.h b/src/r_fps.h index 75d9ead3d..ec85a1f35 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -133,4 +133,14 @@ void R_RestoreLevelInterpolators(void); // Destroy interpolators associated with a thinker void R_DestroyLevelInterpolators(thinker_t *thinker); +// Initialize internal mobj interpolator list (e.g. during level loading) +void R_InitMobjInterpolators(void); +// Add interpolation state for the given mobj +void R_AddMobjInterpolator(mobj_t *mobj); +// Remove the interpolation state for the given mobj +void R_RemoveMobjInterpolator(mobj_t *mobj); +void R_UpdateMobjInterpolators(void); +void R_ResetMobjInterpolationState(mobj_t *mobj); +void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj); + #endif From 3da9852d2ac369c31de1d604a647106ba1c84824 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 05:27:57 -0400 Subject: [PATCH 046/137] Dynamic slope interpolators --- src/p_slopes.c | 4 ++++ src/r_fps.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/r_fps.h | 8 ++++++++ 3 files changed, 61 insertions(+) diff --git a/src/p_slopes.c b/src/p_slopes.c index ffbfef2d3..7c700d736 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -22,6 +22,7 @@ #include "r_main.h" #include "p_maputl.h" #include "w_wad.h" +#include "r_fps.h" pslope_t *slopelist = NULL; UINT16 slopecount = 0; @@ -200,6 +201,9 @@ static inline void P_AddDynSlopeThinker (pslope_t* slope, dynplanetype_t type, l th->type = type; P_AddThinker(THINK_DYNSLOPE, &th->thinker); + + // interpolation + R_CreateInterpolator_DynSlope(&th->thinker, slope); } diff --git a/src/r_fps.c b/src/r_fps.c index 5c0c8f6df..732052eac 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -93,6 +93,22 @@ static angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac) return from + FixedMul(frac, to - from); } +static vector2_t *R_LerpVector2(const vector2_t *from, const vector2_t *to, fixed_t frac, vector2_t *out) +{ + FV2_SubEx(to, from, out); + FV2_MulEx(out, frac, out); + FV2_AddEx(from, out, out); + return out; +} + +static vector3_t *R_LerpVector3(const vector3_t *from, const vector3_t *to, fixed_t frac, vector3_t *out) +{ + FV3_SubEx(to, from, out); + FV3_MulEx(out, frac, out); + FV3_AddEx(from, out, out); + return out; +} + // recalc necessary stuff for mouseaiming // slopes are already calculated for the full possible view (which is 4*viewheight). // 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out) @@ -364,6 +380,20 @@ void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj) interp->polyobj.oldcy = interp->polyobj.bakcy = polyobj->centerPt.y; } +void R_CreateInterpolator_DynSlope(thinker_t *thinker, pslope_t *slope) +{ + levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_DynSlope, thinker); + interp->dynslope.slope = slope; + + FV3_Copy(&interp->dynslope.oldo, &slope->o); + FV3_Copy(&interp->dynslope.bako, &slope->o); + + FV2_Copy(&interp->dynslope.oldd, &slope->d); + FV2_Copy(&interp->dynslope.bakd, &slope->d); + + interp->dynslope.oldzdelta = interp->dynslope.bakzdelta = slope->zdelta; +} + void R_InitializeLevelInterpolators(void) { levelinterpolators_len = 0; @@ -406,6 +436,15 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp) interp->polyobj.bakcx = interp->polyobj.polyobj->centerPt.x; interp->polyobj.bakcy = interp->polyobj.polyobj->centerPt.y; break; + case LVLINTERP_DynSlope: + FV3_Copy(&interp->dynslope.oldo, &interp->dynslope.bako); + FV2_Copy(&interp->dynslope.oldd, &interp->dynslope.bakd); + interp->dynslope.oldzdelta = interp->dynslope.bakzdelta; + + FV3_Copy(&interp->dynslope.bako, &interp->dynslope.slope->o); + FV2_Copy(&interp->dynslope.bakd, &interp->dynslope.slope->d); + interp->dynslope.bakzdelta = interp->dynslope.slope->zdelta; + break; } } @@ -484,6 +523,11 @@ void R_ApplyLevelInterpolators(fixed_t frac) interp->polyobj.polyobj->centerPt.x = R_LerpFixed(interp->polyobj.oldcx, interp->polyobj.bakcx, frac); interp->polyobj.polyobj->centerPt.y = R_LerpFixed(interp->polyobj.oldcy, interp->polyobj.bakcy, frac); break; + case LVLINTERP_DynSlope: + R_LerpVector3(&interp->dynslope.oldo, &interp->dynslope.bako, frac, &interp->dynslope.slope->o); + R_LerpVector2(&interp->dynslope.oldd, &interp->dynslope.bakd, frac, &interp->dynslope.slope->d); + interp->dynslope.slope->zdelta = R_LerpFixed(interp->dynslope.oldzdelta, interp->dynslope.bakzdelta, frac); + break; } } } @@ -533,6 +577,11 @@ void R_RestoreLevelInterpolators(void) interp->polyobj.polyobj->centerPt.x = interp->polyobj.bakcx; interp->polyobj.polyobj->centerPt.y = interp->polyobj.bakcy; break; + case LVLINTERP_DynSlope: + FV3_Copy(&interp->dynslope.slope->o, &interp->dynslope.bako); + FV2_Copy(&interp->dynslope.slope->d, &interp->dynslope.bakd); + interp->dynslope.slope->zdelta = interp->dynslope.bakzdelta; + break; } } } diff --git a/src/r_fps.h b/src/r_fps.h index ec85a1f35..8ce2f3c26 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -66,6 +66,7 @@ typedef enum { LVLINTERP_SectorScroll, LVLINTERP_SideScroll, LVLINTERP_Polyobj, + LVLINTERP_DynSlope, } levelinterpolator_type_e; // Tagged union of a level interpolator @@ -95,6 +96,12 @@ typedef struct levelinterpolator_s { size_t vertices_size; fixed_t oldcx, oldcy, bakcx, bakcy; } polyobj; + struct { + pslope_t *slope; + vector3_t oldo, bako; + vector2_t oldd, bakd; + fixed_t oldzdelta, bakzdelta; + } dynslope; }; } levelinterpolator_t; @@ -119,6 +126,7 @@ void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, bool void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boolean ceiling); void R_CreateInterpolator_SideScroll(thinker_t *thinker, side_t *side); void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj); +void R_CreateInterpolator_DynSlope(thinker_t *thinker, pslope_t *slope); // Initialize level interpolators after a level change void R_InitializeLevelInterpolators(void); From f482218913b0c143e8c19be82de79fc3923aea39 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 24 Apr 2022 19:09:25 -0400 Subject: [PATCH 047/137] I_GetFrameTime to try and improve frame pace (It doesn't feel that much better though.) --- src/d_main.c | 10 +-- src/i_system.h | 10 ++- src/sdl/i_system.c | 154 ++++++++++++++++++++++++++++++--------------- 3 files changed, 115 insertions(+), 59 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index f29fdd224..0931944fe 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -702,8 +702,8 @@ void D_SRB2Loop(void) boolean interp = false; boolean doDisplay = false; - precise_t frameTime = 0; - int frameElapsed = 0; + double frameTime = 0.0; + double frameElapsed = 0.0; if (dedicated) server = true; @@ -755,8 +755,8 @@ void D_SRB2Loop(void) for (;;) { - frameTime = I_GetPreciseTime(); - frameElapsed = 0; + frameTime = I_GetFrameTime(); + frameElapsed = 0.0; if (lastwipetic) { @@ -903,7 +903,7 @@ void D_SRB2Loop(void) SCR_CalculateFPS(); // Fully completed frame made, handle frame cap delay. - frameElapsed = I_PreciseToMicros(I_GetPreciseTime() - frameTime); + frameElapsed = I_GetFrameTime() - frameTime; if (!singletics) { diff --git a/src/i_system.h b/src/i_system.h index f813135ce..a6f4ea70f 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -42,11 +42,11 @@ extern UINT8 keyboard_started; */ UINT32 I_GetFreeMem(UINT32 *total); -/** \brief Called by D_SRB2Loop, returns current time in tics. +/** \brief Called by D_SRB2Loop, returns current time in game tics. */ tic_t I_GetTime(void); -/** \brief Get the current time in tics including fractions. +/** \brief Get the current time in game tics, including fractions. */ float I_GetTimeFrac(void); @@ -58,6 +58,10 @@ precise_t I_GetPreciseTime(void); */ int I_PreciseToMicros(precise_t d); +/** \brief Get the current time in rendering tics, including fractions. +*/ +double I_GetFrameTime(void); + /** \brief Sleeps by the value of cv_sleep \return void @@ -68,7 +72,7 @@ void I_Sleep(void); \return void */ -boolean I_FrameCapSleep(const int elapsed); +boolean I_FrameCapSleep(const double elapsed); /** \brief Get events diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 428186f30..21b262207 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2187,6 +2187,58 @@ int I_PreciseToMicros(precise_t d) return (int)(UINT64)(d / (timer_frequency / 1000000.0)); } +// +// I_GetFrameTime +// returns time in 1/fpscap second tics +// + +static UINT32 frame_rate; + +static double frame_frequency; +static UINT64 frame_epoch; +static double elapsed_frames; + +static void I_InitFrameTime(const UINT64 now, const UINT32 cap) +{ + frame_rate = cap; + frame_epoch = now; + + //elapsed_frames = 0.0; + + if (frame_rate == 0) + { + // Shouldn't be used, but just in case...? + frame_frequency = 1.0; + return; + } + + frame_frequency = timer_frequency / (double)frame_rate; +} + +double I_GetFrameTime(void) +{ + const UINT64 now = SDL_GetPerformanceCounter(); + const UINT32 cap = R_GetFramerateCap(); + + if (cap != frame_rate) + { + I_InitFrameTime(now, cap); + } + + if (frame_rate == 0) + { + // Always advance a frame. + elapsed_frames += 1.0; + } + else + { + elapsed_frames += (now - frame_epoch) / frame_frequency; + } + + frame_epoch = now; // moving epoch + return elapsed_frames; +} + // // I_StartupTimer // @@ -2197,6 +2249,9 @@ void I_StartupTimer(void) tic_frequency = timer_frequency / (double)NEWTICRATE; elapsed_tics = 0.0; + + I_InitFrameTime(tic_epoch, R_GetFramerateCap()); + elapsed_frames = 0.0; } // @@ -2213,69 +2268,66 @@ void I_Sleep(void) // I_FrameCapSleep // Sleeps for a variable amount of time, depending on how much time the last frame took. // -boolean I_FrameCapSleep(const int elapsed) +boolean I_FrameCapSleep(const double elapsed) { - const INT64 delayGranularity = 2000; - // I picked 2ms as it's what GZDoom uses before it stops trying to sleep, - // but maybe other values might work better. + // SDL_Delay(1) gives me a range of around 1.95ms to 2.05ms. + // Has a bit extra to be totally safe. + const double delayGranularity = 2.1; - const UINT32 capFrames = R_GetFramerateCap(); - int capMicros = 0; + double capMS = 0.0; + double elapsedMS = 0.0; + double waitMS = 0.0; - if (capFrames == 0) + if (frame_rate == 0) { // We don't want to cap. return false; } - capMicros = 1000000 / capFrames; + capMS = 1000.0 / frame_rate; // Time of 1 frame, in milliseconds + elapsedMS = elapsed * capMS; // Convert elapsed from frame time to milliseconds. + waitMS = (capMS - elapsedMS); // How many MS to delay by. - if (elapsed < capMicros) + if (waitMS <= 0.0) { - const INT64 error = capMicros / 40; - // 2.5% ... How much we might expect the framerate to flucuate. - // No exact logic behind this number, simply tried stuff until the framerate - // reached the cap 300 more often and only overshot it occasionally. - - INT64 wait = (capMicros - elapsed) - error; - - while (wait > 0) - { - precise_t sleepStart = I_GetPreciseTime(); - precise_t sleepEnd = sleepStart; - int sleepElasped = 0; - - if (wait > delayGranularity && cv_sleep.value != -1) - { - // Wait 1ms at a time (on default settings) - // until we're close enough. - SDL_Delay(cv_sleep.value); - - sleepEnd = I_GetPreciseTime(); - sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart); - } - else - { - // When we have an extremely fine wait, - // we do this to spin-lock the remaining time. - while (sleepElasped < wait) - { - sleepEnd = I_GetPreciseTime(); - sleepElasped = I_PreciseToMicros(sleepEnd - sleepStart); - } - - break; - } - - wait -= sleepElasped; - } - - // We took our nap. - return true; + // Too small of a wait, don't delay. + return false; } - // We're lagging behind. - return false; + while (waitMS > 0.0) + { + double sleepStart = I_GetFrameTime(); + double sleepEnd = sleepStart; + double sleepElaspedMS = 0.0; + + if (waitMS > delayGranularity && cv_sleep.value != -1) + { + // Wait 1ms at a time (on default settings) + // until we're close enough. + SDL_Delay(cv_sleep.value); + + sleepEnd = I_GetFrameTime(); + sleepElaspedMS = (sleepEnd - sleepStart) * capMS; + } + else + { + // When we have an extremely fine wait, + // we do this to spin-lock the remaining time. + + while (sleepElaspedMS < waitMS) + { + sleepEnd = I_GetFrameTime(); + sleepElaspedMS = (sleepEnd - sleepStart) * capMS; + } + + break; + } + + waitMS -= sleepElaspedMS; + } + + // We took our nap. + return true; } #ifdef NEWSIGNALHANDLER From 80cb9994d52147c8da25d44fe3f1040b1046f787 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 02:12:27 -0400 Subject: [PATCH 048/137] Move I_FinishUpdate to D_SRB2Loop to sync screen updates with FPS cap, use timestamps in I_FrameCapSleep to simplify the code --- src/d_main.c | 59 +++++++++++++++++++++++----------------------- src/i_system.h | 2 +- src/sdl/i_system.c | 53 +++++++++++++++-------------------------- src/sdl/i_video.c | 2 +- 4 files changed, 51 insertions(+), 65 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 0931944fe..9cfd694e7 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -297,17 +297,17 @@ gamestate_t wipegamestate = GS_LEVEL; INT16 wipetypepre = -1; INT16 wipetypepost = -1; -static void D_Display(void) +static boolean D_Display(void) { boolean forcerefresh = false; static boolean wipe = false; INT32 wipedefindex = 0; if (dedicated) - return; + return false; if (nodrawers) - return; // for comparative timing/profiling + return false; // for comparative timing/profiling // Lactozilla: Switching renderers works by checking // if the game has to do it right when the frame @@ -681,10 +681,10 @@ static void D_Display(void) M_DrawPerfStats(); } - PS_START_TIMING(ps_swaptime); - I_FinishUpdate(); // page flip or blit buffer - PS_STOP_TIMING(ps_swaptime); + return true; // Do I_FinishUpdate in the main loop } + + return false; } // ========================================================================= @@ -701,9 +701,9 @@ void D_SRB2Loop(void) boolean ticked = false; boolean interp = false; boolean doDisplay = false; + boolean screenUpdate = false; - double frameTime = 0.0; - double frameElapsed = 0.0; + double frameEnd = 0.0; if (dedicated) server = true; @@ -755,9 +755,6 @@ void D_SRB2Loop(void) for (;;) { - frameTime = I_GetFrameTime(); - frameElapsed = 0.0; - if (lastwipetic) { oldentertics = lastwipetic; @@ -769,8 +766,6 @@ void D_SRB2Loop(void) realtics = entertic - oldentertics; oldentertics = entertic; - refreshdirmenu = 0; // not sure where to put this, here as good as any? - if (demoplayback && gamestate == GS_LEVEL) { // Nicer place to put this. @@ -784,13 +779,15 @@ void D_SRB2Loop(void) #endif interp = R_UsingFrameInterpolation(); - doDisplay = false; + doDisplay = screenUpdate = false; ticked = false; #ifdef HW3SOUND HW3S_BeginFrameUpdate(); #endif + refreshdirmenu = 0; // not sure where to put this, here as good as any? + if (realtics > 0 || singletics) { // don't skip more than 10 frames at a time @@ -879,14 +876,9 @@ void D_SRB2Loop(void) if (interp || doDisplay) { - D_Display(); + screenUpdate = D_Display(); } - if (moviemode) - M_SaveFrame(); - if (takescreenshot) // Only take screenshots after drawing. - M_DoScreenShot(); - // consoleplayer -> displayplayer (hear sounds from viewpoint) S_UpdateSounds(); // move positional sounds S_UpdateClosedCaptions(); @@ -897,18 +889,27 @@ void D_SRB2Loop(void) LUA_Step(); - // Moved to here from I_FinishUpdate. - // It doesn't track fades properly anymore by being here (might be easy fix), - // but it's a little more accurate for actual rendering when its here. - SCR_CalculateFPS(); - - // Fully completed frame made, handle frame cap delay. - frameElapsed = I_GetFrameTime() - frameTime; - + // Fully completed frame made. + frameEnd = I_GetFrameTime(); if (!singletics) { - I_FrameCapSleep(frameElapsed); + I_FrameCapSleep(frameEnd); } + + // I_FinishUpdate is now here instead of D_Display, + // because it synchronizes it more closely with the frame counter. + if (screenUpdate == true) + { + PS_START_TIMING(ps_swaptime); + I_FinishUpdate(); // page flip or blit buffer + PS_STOP_TIMING(ps_swaptime); + } + + // Only take screenshots after drawing. + if (moviemode) + M_SaveFrame(); + if (takescreenshot) + M_DoScreenShot(); } } diff --git a/src/i_system.h b/src/i_system.h index a6f4ea70f..f607ec79c 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -72,7 +72,7 @@ void I_Sleep(void); \return void */ -boolean I_FrameCapSleep(const double elapsed); +boolean I_FrameCapSleep(const double frameStart); /** \brief Get events diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 21b262207..2e1bf0c17 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2222,6 +2222,7 @@ double I_GetFrameTime(void) if (cap != frame_rate) { + // Maybe do this in a OnChange function for cv_fpscap? I_InitFrameTime(now, cap); } @@ -2260,23 +2261,24 @@ void I_StartupTimer(void) // void I_Sleep(void) { - if (cv_sleep.value != -1) + if (cv_sleep.value > 0) SDL_Delay(cv_sleep.value); } // // I_FrameCapSleep -// Sleeps for a variable amount of time, depending on how much time the last frame took. +// Sleeps for a variable amount of time, depending on how much time the frame took. // -boolean I_FrameCapSleep(const double elapsed) +boolean I_FrameCapSleep(const double t) { // SDL_Delay(1) gives me a range of around 1.95ms to 2.05ms. // Has a bit extra to be totally safe. const double delayGranularity = 2.1; + double frameMS = 0.0; - double capMS = 0.0; - double elapsedMS = 0.0; - double waitMS = 0.0; + double curTime = 0.0; + double destTime = 0.0; + double sleepTime = 0.0; if (frame_rate == 0) { @@ -2284,46 +2286,29 @@ boolean I_FrameCapSleep(const double elapsed) return false; } - capMS = 1000.0 / frame_rate; // Time of 1 frame, in milliseconds - elapsedMS = elapsed * capMS; // Convert elapsed from frame time to milliseconds. - waitMS = (capMS - elapsedMS); // How many MS to delay by. + curTime = I_GetFrameTime(); + destTime = floor(t) + 1.0; - if (waitMS <= 0.0) + if (curTime >= destTime) { - // Too small of a wait, don't delay. + // We're already behind schedule. return false; } - while (waitMS > 0.0) - { - double sleepStart = I_GetFrameTime(); - double sleepEnd = sleepStart; - double sleepElaspedMS = 0.0; + frameMS = frame_rate * 0.001; // 1ms as frame time + sleepTime = destTime - (delayGranularity * frameMS); - if (waitMS > delayGranularity && cv_sleep.value != -1) + while (curTime < destTime) + { + if (curTime < sleepTime && cv_sleep.value <= 0) { // Wait 1ms at a time (on default settings) // until we're close enough. SDL_Delay(cv_sleep.value); - - sleepEnd = I_GetFrameTime(); - sleepElaspedMS = (sleepEnd - sleepStart) * capMS; - } - else - { - // When we have an extremely fine wait, - // we do this to spin-lock the remaining time. - - while (sleepElaspedMS < waitMS) - { - sleepEnd = I_GetFrameTime(); - sleepElaspedMS = (sleepEnd - sleepStart) * capMS; - } - - break; } - waitMS -= sleepElaspedMS; + // This part will spin-lock the rest. + curTime = I_GetFrameTime(); } // We took our nap. diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index eedb60e09..8d1ea62d4 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1214,7 +1214,7 @@ void I_FinishUpdate(void) if (rendermode == render_none) return; //Alam: No software or OpenGl surface - //SCR_CalculateFPS(); // Moved to main loop + SCR_CalculateFPS(); if (I_SkipFrame()) return; From b98207035d4c8ed55fb458d5bd7e221e5e129206 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 14:16:41 -0400 Subject: [PATCH 049/137] Fix plane interpolation light level flickering --- src/r_bsp.c | 20 ++++++++++++++++++-- src/r_fps.c | 7 ++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/r_bsp.c b/src/r_bsp.c index c9f269816..b8e1d69c5 100644 --- a/src/r_bsp.c +++ b/src/r_bsp.c @@ -836,6 +836,7 @@ static void R_Subsector(size_t num) extracolormap_t *floorcolormap; extracolormap_t *ceilingcolormap; fixed_t floorcenterz, ceilingcenterz; + ffloor_t *rover; #ifdef RANGECHECK if (num >= numsubsectors) @@ -862,7 +863,23 @@ static void R_Subsector(size_t num) // Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps. if (frontsector->ffloors) { - if (frontsector->moved) + boolean anyMoved = frontsector->moved; + + if (anyMoved == false) + { + for (rover = frontsector->ffloors; rover; rover = rover->next) + { + sector_t *controlSec = §ors[rover->secnum]; + + if (controlSec->moved == true) + { + anyMoved = true; + break; + } + } + } + + if (anyMoved == true) { frontsector->numlights = sub->sector->numlights = 0; R_Prep3DFloors(frontsector); @@ -910,7 +927,6 @@ static void R_Subsector(size_t num) ffloor[numffloors].polyobj = NULL; if (frontsector->ffloors) { - ffloor_t *rover; fixed_t heightcheck, planecenterz; for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next) diff --git a/src/r_fps.c b/src/r_fps.c index 732052eac..738df2020 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -455,20 +455,19 @@ void R_UpdateLevelInterpolators(void) for (i = 0; i < levelinterpolators_len; i++) { levelinterpolator_t *interp = levelinterpolators[i]; - + UpdateLevelInterpolatorState(interp); } } void R_ClearLevelInterpolatorState(thinker_t *thinker) { - size_t i; for (i = 0; i < levelinterpolators_len; i++) { levelinterpolator_t *interp = levelinterpolators[i]; - + if (interp->thinker == thinker) { // Do it twice to make the old state match the new @@ -497,6 +496,7 @@ void R_ApplyLevelInterpolators(fixed_t frac) { interp->sectorplane.sector->floorheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac); } + interp->sectorplane.sector->moved = true; break; case LVLINTERP_SectorScroll: if (interp->sectorscroll.ceiling) @@ -551,6 +551,7 @@ void R_RestoreLevelInterpolators(void) { interp->sectorplane.sector->floorheight = interp->sectorplane.bakheight; } + interp->sectorplane.sector->moved = true; break; case LVLINTERP_SectorScroll: if (interp->sectorscroll.ceiling) From 2f467259844d8228ef8621d860ce71b7ec7c6f09 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 14:45:35 -0400 Subject: [PATCH 050/137] Fix flickering plane interpolation for OpenGL in the exact same way Funny OpenGL renderer being at least 50% copy-pasted Software code :) --- src/hardware/hw_main.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index f56856bb4..cafa9ff50 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -2997,6 +2997,7 @@ static void HWR_Subsector(size_t num) INT32 light = 0; extracolormap_t *floorcolormap; extracolormap_t *ceilingcolormap; + ffloor_t *rover; #ifdef PARANOIA //no risk while developing, enough debugging nights! if (num >= addsubsector) @@ -3054,7 +3055,22 @@ static void HWR_Subsector(size_t num) if (gl_frontsector->ffloors) { - if (gl_frontsector->moved) + boolean anyMoved = gl_frontsector->moved; + + if (anyMoved == false) + { + for (rover = gl_frontsector->ffloors; rover; rover = rover->next) + { + sector_t *controlSec = §ors[rover->secnum]; + if (controlSec->moved == true) + { + anyMoved = true; + break; + } + } + } + + if (anyMoved == true) { gl_frontsector->numlights = sub->sector->numlights = 0; R_Prep3DFloors(gl_frontsector); @@ -3133,7 +3149,6 @@ static void HWR_Subsector(size_t num) if (gl_frontsector->ffloors) { /// \todo fix light, xoffs, yoffs, extracolormap ? - ffloor_t * rover; for (rover = gl_frontsector->ffloors; rover; rover = rover->next) { From d476b41dfa23103c30464afee05d1f1f2e98a1ae Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 29 Nov 2021 08:20:27 -0500 Subject: [PATCH 051/137] P_SetOrigin & P_MoveOrigin to replace P_TeleportMove --- src/g_demo.c | 2 +- src/lua_baselib.c | 39 ++++++++++++++++++++++++++++++++++++++- src/lua_mobjlib.c | 2 +- src/m_cheat.c | 6 +++--- src/p_enemy.c | 24 ++++++++++++------------ src/p_local.h | 3 ++- src/p_map.c | 30 ++++++++++++++++++++++++++---- src/p_mobj.c | 2 +- src/p_telept.c | 2 +- 9 files changed, 85 insertions(+), 25 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index e293ad9dc..7a7236945 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -1008,7 +1008,7 @@ void G_ReadMetalTic(mobj_t *metal) oldmetal.x = READFIXED(metal_p); oldmetal.y = READFIXED(metal_p); oldmetal.z = READFIXED(metal_p); - P_TeleportMove(metal, oldmetal.x, oldmetal.y, oldmetal.z); + P_MoveOrigin(metal, oldmetal.x, oldmetal.y, oldmetal.z); oldmetal.x = metal->x; oldmetal.y = metal->y; oldmetal.z = metal->z; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 120ab671e..fc4e321ed 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1783,7 +1783,42 @@ static int lib_pTeleportMove(lua_State *L) INLEVEL if (!thing) return LUA_ErrInvalid(L, "mobj_t"); - lua_pushboolean(L, P_TeleportMove(thing, x, y, z)); + LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin or P_MoveOrigin"); + lua_pushboolean(L, P_SetOrigin(thing, x, y, z)); + LUA_PushUserdata(L, tmthing, META_MOBJ); + P_SetTarget(&tmthing, ptmthing); + return 2; +} + +static int lib_pSetOrigin(lua_State *L) +{ + mobj_t *ptmthing = tmthing; + mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + fixed_t x = luaL_checkfixed(L, 2); + fixed_t y = luaL_checkfixed(L, 3); + fixed_t z = luaL_checkfixed(L, 4); + NOHUD + INLEVEL + if (!thing) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_SetOrigin(thing, x, y, z)); + LUA_PushUserdata(L, tmthing, META_MOBJ); + P_SetTarget(&tmthing, ptmthing); + return 2; +} + +static int lib_pMoveOrigin(lua_State *L) +{ + mobj_t *ptmthing = tmthing; + mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); + fixed_t x = luaL_checkfixed(L, 2); + fixed_t y = luaL_checkfixed(L, 3); + fixed_t z = luaL_checkfixed(L, 4); + NOHUD + INLEVEL + if (!thing) + return LUA_ErrInvalid(L, "mobj_t"); + lua_pushboolean(L, P_MoveOrigin(thing, x, y, z)); LUA_PushUserdata(L, tmthing, META_MOBJ); P_SetTarget(&tmthing, ptmthing); return 2; @@ -4021,6 +4056,8 @@ static luaL_Reg lib[] = { {"P_TryMove",lib_pTryMove}, {"P_Move",lib_pMove}, {"P_TeleportMove",lib_pTeleportMove}, + {"P_SetOrigin",lib_pSetOrigin}, + {"P_MoveOrigin",lib_pMoveOrigin}, {"P_SlideMove",lib_pSlideMove}, {"P_BounceMove",lib_pBounceMove}, {"P_CheckSight", lib_pCheckSight}, diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 953b39000..995cdc444 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -458,7 +458,7 @@ static int mobj_get(lua_State *L) } #define NOSET luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly.", mobj_opt[field]) -#define NOSETPOS luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly. Use " LUA_QL("P_Move") ", " LUA_QL("P_TryMove") ", or " LUA_QL("P_TeleportMove") " instead.", mobj_opt[field]) +#define NOSETPOS luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly. Use " LUA_QL("P_Move") ", " LUA_QL("P_TryMove") ", or " LUA_QL("P_SetOrigin") ", or " LUA_QL("P_MoveOrigin") " instead.", mobj_opt[field]) static int mobj_set(lua_State *L) { mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ)); diff --git a/src/m_cheat.c b/src/m_cheat.c index 82d0b9d5a..1ecf6b497 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -475,7 +475,7 @@ void Command_RTeleport_f(void) CONS_Printf(M_GetText("Teleporting by %d, %d, %d...\n"), intx, inty, FixedInt((intz-p->mo->z))); P_MapStart(); - if (!P_TeleportMove(p->mo, p->mo->x+intx*FRACUNIT, p->mo->y+inty*FRACUNIT, intz)) + if (!P_SetOrigin(p->mo, p->mo->x+intx*FRACUNIT, p->mo->y+inty*FRACUNIT, intz)) CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); else S_StartSound(p->mo, sfx_mixup); @@ -696,7 +696,7 @@ void Command_Teleport_f(void) } P_MapStart(); - if (!P_TeleportMove(p->mo, intx, inty, intz)) + if (!P_SetOrigin(p->mo, intx, inty, intz)) CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n")); else S_StartSound(p->mo, sfx_mixup); @@ -1315,7 +1315,7 @@ void OP_ObjectplaceMovement(player_t *player) if (cmd->forwardmove != 0) { P_Thrust(player->mo, player->mo->angle, (cmd->forwardmove*player->mo->scale/MAXPLMOVE)*cv_speed.value); - P_TeleportMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z); + P_MoveOrigin(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z); player->mo->momx = player->mo->momy = 0; } if (cmd->sidemove != 0) diff --git a/src/p_enemy.c b/src/p_enemy.c index 40aab9ec1..59fe561f3 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -1331,7 +1331,7 @@ void A_FaceStabHurl(mobj_t *actor) hwork->destscale = FixedSqrt(step*basesize); P_SetScale(hwork, hwork->destscale); hwork->fuse = 2; - P_TeleportMove(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<x + P_ReturnThrustX(actor, actor->angle, locvar1*crab->scale), crab->y + P_ReturnThrustY(actor, actor->angle, locvar1*crab->scale), crab->z + locvar2*crab->scale); @@ -2229,7 +2229,7 @@ void A_CrushclawLaunch(mobj_t *actor) fixed_t idx = dx, idy = dy, idz = dz; while (chain) { - P_TeleportMove(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz); + P_MoveOrigin(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz); chain->movefactor = chain->z; idx += dx; idy += dy; @@ -11149,7 +11149,7 @@ void A_VileAttack(mobj_t *actor) // move the fire between the vile and the player //fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); //fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); - P_TeleportMove(fire, + P_MoveOrigin(fire, actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), fire->z); @@ -11194,7 +11194,7 @@ void A_VileAttack(mobj_t *actor) // move the fire between the vile and the player //fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]); //fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]); - P_TeleportMove(fire, + P_MoveOrigin(fire, actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)), fire->z); @@ -11865,12 +11865,12 @@ void A_FlickyCenter(mobj_t *actor) if (actor->target && P_AproxDistance(actor->target->x - originx, actor->target->y - originy) < actor->extravalue1) { actor->extravalue2 = 1; - P_TeleportMove(actor, actor->target->x, actor->target->y, actor->target->z); + P_SetOrigin(actor, actor->target->x, actor->target->y, actor->target->z); } else if(actor->extravalue2) { actor->extravalue2 = 0; - P_TeleportMove(actor, originx, originy, originz); + P_SetOrigin(actor, originx, originy, originz); } } } @@ -12406,7 +12406,7 @@ void A_LightBeamReset(mobj_t *actor) actor->momy = (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/128; actor->momz = (P_SignedRandom()*FRACUNIT)/128; - P_TeleportMove(actor, + P_SetOrigin(actor, actor->spawnpoint->x*FRACUNIT - (P_SignedRandom()*FINESINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2, actor->spawnpoint->y*FRACUNIT + (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2, actor->spawnpoint->z*FRACUNIT + (P_SignedRandom()*FRACUNIT)/2); @@ -12991,7 +12991,7 @@ void A_DoNPCSkid(mobj_t *actor) actor->momy = (2*actor->momy)/3; } - P_TeleportMove(actor, x, y, z); + P_MoveOrigin(actor, x, y, z); // Spawn a particle every 3 tics. if (!(leveltime % 3)) @@ -13332,7 +13332,7 @@ void A_Boss5MakeJunk(mobj_t *actor) if (locvar1 > 0) P_SetMobjState(broked, locvar1); if (!P_MobjWasRemoved(broked)) - P_TeleportMove(broked, broked->x + broked->momx, broked->y + broked->momy, broked->z); + P_MoveOrigin(broked, broked->x + broked->momx, broked->y + broked->momy, broked->z); ang += ANGLE_45; } @@ -14550,7 +14550,7 @@ void A_DragonWing(mobj_t *actor) actor->angle = target->angle + actor->movedir; x = target->x + P_ReturnThrustX(actor, actor->angle, -target->radius); y = target->y + P_ReturnThrustY(actor, actor->angle, -target->radius); - P_TeleportMove(actor, x, y, target->z); + P_MoveOrigin(actor, x, y, target->z); } // Function: A_DragonSegment @@ -14591,7 +14591,7 @@ void A_DragonSegment(mobj_t *actor) zdist = P_ReturnThrustY(target, zangle, radius); actor->angle = hangle; - P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist); + P_MoveOrigin(actor, target->x + xdist, target->y + ydist, target->z + zdist); } // Function: A_ChangeHeight diff --git a/src/p_local.h b/src/p_local.h index ec7e65b71..4dc0ce615 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -414,7 +414,8 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam); boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_Move(mobj_t *actor, fixed_t speed); -boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); +boolean P_SetOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); +boolean P_MoveOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); void P_InitAngle(mobj_t *thing, angle_t newValue); void P_InitPitch(mobj_t *thing, angle_t newValue); void P_InitRoll(mobj_t *thing, angle_t newValue); diff --git a/src/p_map.c b/src/p_map.c index e9d289e2d..1c3915ebd 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -75,7 +75,7 @@ camera_t *mapcampointer; // // P_TeleportMove // -boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) +static boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) { // the move is ok, // so link the thing into its new position @@ -104,11 +104,33 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) thing->floorrover = tmfloorrover; thing->ceilingrover = tmceilingrover; - R_ResetMobjInterpolationState(thing); - return true; } +// P_SetOrigin - P_TeleportMove which RESETS interpolation values. +// +boolean P_SetOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) +{ + boolean result = P_TeleportMove(thing, x, y, z); + + if (result == true) + { + thing->old_x = thing->x; + thing->old_y = thing->y; + thing->old_z = thing->z; + } + + return result; +} + +// +// P_MoveOrigin - P_TeleportMove which KEEPS interpolation values. +// +boolean P_MoveOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) +{ + return P_TeleportMove(thing, x, y, z); +} + // // P_InitAngle - Change an object's angle, including interp values. // @@ -1941,7 +1963,7 @@ static boolean PIT_CheckLine(line_t *ld) cosradius = FixedMul(dist, FINECOSINE(langle>>ANGLETOFINESHIFT)); sinradius = FixedMul(dist, FINESINE(langle>>ANGLETOFINESHIFT)); tmthing->flags |= MF_NOCLIP; - P_TeleportMove(tmthing, result.x + cosradius - tmthing->momx, result.y + sinradius - tmthing->momy, tmthing->z); + P_MoveOrigin(tmthing, result.x + cosradius - tmthing->momx, result.y + sinradius - tmthing->momy, tmthing->z); tmthing->flags &= ~MF_NOCLIP; } #endif diff --git a/src/p_mobj.c b/src/p_mobj.c index eb939c968..462dddffe 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6440,7 +6440,7 @@ void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on y if (dist < source->movefactor) { source->momx = source->momy = source->momz = 0; - P_TeleportMove(source, tx, ty, tz); + P_MoveOrigin(source, tx, ty, tz); } else { diff --git a/src/p_telept.c b/src/p_telept.c index cfd7be1e2..745d52745 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -122,7 +122,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, */ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, boolean flash, boolean dontstopmove) { - if (!P_TeleportMove(thing, x, y, z)) + if (!P_SetOrigin(thing, x, y, z)) return false; if (!dontstopmove) From 579016819438edf9788e5bc67099830b24ab8eaa Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 25 Apr 2022 14:36:54 -0500 Subject: [PATCH 052/137] Convert P_TeleportMove use to origin funcs --- src/b_bot.c | 2 +- src/m_cheat.c | 2 +- src/p_enemy.c | 2 +- src/p_map.c | 4 ++-- src/p_mobj.c | 36 ++++++++++++++++++------------------ src/p_spec.c | 6 +++--- src/p_user.c | 10 +++++----- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/b_bot.c b/src/b_bot.c index 775a13e29..f1df5abbd 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -579,7 +579,7 @@ void B_RespawnBot(INT32 playernum) player->powers[pw_nocontrol] = sonic->player->powers[pw_nocontrol]; player->pflags |= PF_AUTOBRAKE|(sonic->player->pflags & PF_DIRECTIONCHAR); - P_TeleportMove(tails, x, y, z); + P_SetOrigin(tails, x, y, z); if (player->charability == CA_FLY) { P_SetPlayerMobjState(tails, S_PLAY_FLY); diff --git a/src/m_cheat.c b/src/m_cheat.c index 1ecf6b497..a453c9d03 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -1321,7 +1321,7 @@ void OP_ObjectplaceMovement(player_t *player) if (cmd->sidemove != 0) { P_Thrust(player->mo, player->mo->angle-ANGLE_90, (cmd->sidemove*player->mo->scale/MAXPLMOVE)*cv_speed.value); - P_TeleportMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z); + P_MoveOrigin(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z); player->mo->momx = player->mo->momy = 0; } diff --git a/src/p_enemy.c b/src/p_enemy.c index 59fe561f3..e7ed241e6 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -13541,7 +13541,7 @@ void A_DustDevilThink(mobj_t *actor) //Chained thinker for the spiralling dust column. while (layer && !P_MobjWasRemoved(layer)) { angle_t fa = layer->angle >> ANGLETOFINESHIFT; - P_TeleportMove(layer, layer->x + 5 * FixedMul(scale, FINECOSINE(fa)), layer->y + 5 * FixedMul(scale, FINESINE(fa)), layer->z); + P_MoveOrigin(layer, layer->x + 5 * FixedMul(scale, FINECOSINE(fa)), layer->y + 5 * FixedMul(scale, FINESINE(fa)), layer->z); layer->scale = scale; layer->angle += ANG10 / 2; layer->momx = actor->momx; diff --git a/src/p_map.c b/src/p_map.c index 1c3915ebd..de10e2de3 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1201,9 +1201,9 @@ static boolean PIT_CheckThing(mobj_t *thing) return true; // underneath if (tmthing->eflags & MFE_VERTICALFLIP) - P_TeleportMove(thing, thing->x, thing->y, tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale)); + P_SetOrigin(thing, thing->x, thing->y, tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale)); else - P_TeleportMove(thing, thing->x, thing->y, tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale)); + P_SetOrigin(thing, thing->x, thing->y, tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale)); if (thing->flags & MF_SHOOTABLE) P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE); return true; diff --git a/src/p_mobj.c b/src/p_mobj.c index 462dddffe..60823f92d 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4669,7 +4669,7 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz) while ((base = base->tracer)) { for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s) - P_TeleportMove(seg, mobj->x + P_ReturnThrustX(mobj, angle, dist), mobj->y + P_ReturnThrustY(mobj, angle, dist), bz + FixedMul(fz, FixedDiv(s<x + P_ReturnThrustX(mobj, angle, dist), mobj->y + P_ReturnThrustY(mobj, angle, dist), bz + FixedMul(fz, FixedDiv(s<hprev->destscale = FRACUNIT + (2*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2); P_SetScale(mobj->hprev, mobj->hprev->destscale); - P_TeleportMove(mobj->hprev, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->hprev->height/2); + P_MoveOrigin(mobj->hprev, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->hprev->height/2); mobj->hprev->momx = mobj->momx; mobj->hprev->momy = mobj->momy; mobj->hprev->momz = mobj->momz; @@ -7045,7 +7045,7 @@ static void P_UpdateMinecartSegments(mobj_t *mobj) dx = seg->extravalue1; dy = seg->extravalue2; sang = seg->cusval; - P_TeleportMove(seg, x + s*dx + c*dy, y - c*dx + s*dy, z); + P_MoveOrigin(seg, x + s*dx + c*dy, y - c*dx + s*dy, z); seg->angle = ang + FixedAngle(FRACUNIT*sang); seg->flags2 = (seg->flags2 & ~MF2_DONTDRAW) | (mobj->flags2 & MF2_DONTDRAW); seg = seg->tracer; @@ -8648,7 +8648,7 @@ static boolean P_EggRobo1Think(mobj_t *mobj) < mobj->scale) S_StartSound(mobj, mobj->info->seesound); - P_TeleportMove(mobj, + P_MoveOrigin(mobj, (15*(mobj->x >> 4)) + (basex >> 4) + P_ReturnThrustX(mobj, mobj->angle, SPECTATORRADIUS >> 4), (15*(mobj->y >> 4)) + (basey >> 4) + P_ReturnThrustY(mobj, mobj->angle, SPECTATORRADIUS >> 4), mobj->z); @@ -8674,9 +8674,9 @@ static boolean P_EggRobo1Think(mobj_t *mobj) if (!didmove) { if (P_AproxDistance(mobj->x - basex, mobj->y - basey) < mobj->scale) - P_TeleportMove(mobj, basex, basey, mobj->z); + P_MoveOrigin(mobj, basex, basey, mobj->z); else - P_TeleportMove(mobj, + P_MoveOrigin(mobj, (15*(mobj->x >> 4)) + (basex >> 4), (15*(mobj->y >> 4)) + (basey >> 4), mobj->z); @@ -8800,11 +8800,11 @@ static void P_NiGHTSDroneThink(mobj_t *mobj) sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale); } - P_TeleportMove(goalpost, mobj->x, mobj->y, mobj->z + goaloffset); - P_TeleportMove(sparkle, mobj->x, mobj->y, mobj->z + sparkleoffset); + P_MoveOrigin(goalpost, mobj->x, mobj->y, mobj->z + goaloffset); + P_MoveOrigin(sparkle, mobj->x, mobj->y, mobj->z + sparkleoffset); if (goalpost->movefactor != mobj->z || goalpost->friction != mobj->height) { - P_TeleportMove(droneman, mobj->x, mobj->y, mobj->z + dronemanoffset); + P_MoveOrigin(droneman, mobj->x, mobj->y, mobj->z + dronemanoffset); goalpost->movefactor = mobj->z; goalpost->friction = mobj->height; } @@ -8814,12 +8814,12 @@ static void P_NiGHTSDroneThink(mobj_t *mobj) { if (goalpost->x != mobj->x || goalpost->y != mobj->y) { - P_TeleportMove(goalpost, mobj->x, mobj->y, goalpost->z); - P_TeleportMove(sparkle, mobj->x, mobj->y, sparkle->z); + P_MoveOrigin(goalpost, mobj->x, mobj->y, goalpost->z); + P_MoveOrigin(sparkle, mobj->x, mobj->y, sparkle->z); } if (droneman->x != mobj->x || droneman->y != mobj->y) - P_TeleportMove(droneman, mobj->x, mobj->y, + P_MoveOrigin(droneman, mobj->x, mobj->y, droneman->z >= mobj->floorz && droneman->z <= mobj->ceilingz ? droneman->z : mobj->z); } @@ -9019,7 +9019,7 @@ static void P_SaloonDoorThink(mobj_t *mobj) fma = (mobj->angle >> ANGLETOFINESHIFT) & FINEMASK; c = 48*FINECOSINE(fma); s = 48*FINESINE(fma); - P_TeleportMove(mobj, x + c0 + c, y + s0 + s, z); + P_MoveOrigin(mobj, x + c0 + c, y + s0 + s, z); } static void P_PyreFlyThink(mobj_t *mobj) @@ -9461,7 +9461,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) P_RemoveMobj(mobj); return false; } - P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z - mobj->height); + P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z - mobj->height); break; case MT_HAMMER: if (mobj->z <= mobj->floorz) @@ -12535,7 +12535,7 @@ static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj) dronemangoaldiff = max(mobjinfo[MT_NIGHTSDRONE_MAN].height - mobjinfo[MT_NIGHTSDRONE_GOAL].height, 0); if (flip && mobj->height != oldheight) - P_TeleportMove(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight)); + P_MoveOrigin(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight)); if (!flip) { @@ -12604,9 +12604,9 @@ static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj) // correct Z position if (flip) { - P_TeleportMove(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset); - P_TeleportMove(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset); - P_TeleportMove(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset); + P_MoveOrigin(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset); + P_MoveOrigin(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset); + P_MoveOrigin(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset); } // Remember position preference for later diff --git a/src/p_spec.c b/src/p_spec.c index 34dcd917d..ad70f6c88 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2326,7 +2326,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (mo->player) { if (bot) // This might put poor Tails in a wall if he's too far behind! D: But okay, whatever! >:3 - P_TeleportMove(bot, bot->x + x, bot->y + y, bot->z + z); + P_SetOrigin(bot, bot->x + x, bot->y + y, bot->z + z); if (splitscreen && mo->player == &players[secondarydisplayplayer] && camera2.chase) { camera2.x += x; @@ -2828,7 +2828,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // Reset bot too. if (bot) { if (line->flags & ML_NOCLIMB) - P_TeleportMove(bot, mo->x, mo->y, mo->z); + P_SetOrigin(bot, mo->x, mo->y, mo->z); bot->momx = bot->momy = bot->momz = 1; bot->pmomz = 0; bot->player->rmomx = bot->player->rmomy = 1; @@ -2872,7 +2872,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) // (Teleport them to you so they don't break it.) if (bot && (bot->flags2 & MF2_TWOD) != (mo->flags2 & MF2_TWOD)) { bot->flags2 = (bot->flags2 & ~MF2_TWOD) | (mo->flags2 & MF2_TWOD); - P_TeleportMove(bot, mo->x, mo->y, mo->z); + P_SetOrigin(bot, mo->x, mo->y, mo->z); } } break; diff --git a/src/p_user.c b/src/p_user.c index f047499d0..a661308ed 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -7015,7 +7015,7 @@ static void P_MoveNiGHTSToDrone(player_t *player) } player->mo->momx = player->mo->momy = player->mo->momz = 0; - P_TeleportMove(player->mo, player->drone->x, player->drone->y, player->drone->z + zofs); + P_MoveOrigin(player->mo, player->drone->x, player->drone->y, player->drone->z + zofs); P_SetTarget(&player->drone, NULL); } @@ -11097,7 +11097,7 @@ static void P_MinecartThink(player_t *player) } // Move player to minecart. - P_TeleportMove(player->mo, minecart->x - minecart->momx, minecart->y - minecart->momy, minecart->z + max(minecart->momz, 0) + 8*FRACUNIT); + P_MoveOrigin(player->mo, minecart->x - minecart->momx, minecart->y - minecart->momy, minecart->z + max(minecart->momz, 0) + 8*FRACUNIT); if (player->powers[pw_carry] != CR_MINECART) return; player->mo->momx = player->mo->momy = player->mo->momz = 0; @@ -11832,7 +11832,7 @@ void P_PlayerThink(player_t *player) // P_TouchSpecialThing case MT_NIGHTSBUMPER, that position is fudged in the time // between that routine in the previous tic // and reaching here in the current tic - P_TeleportMove(player->mo, player->mo->hnext->x, player->mo->hnext->y + P_MoveOrigin(player->mo, player->mo->hnext->x, player->mo->hnext->y , player->mo->hnext->z + FixedMul(player->mo->hnext->height/4, player->mo->hnext->scale)); P_SetTarget(&player->mo->hnext, NULL); } @@ -12653,7 +12653,7 @@ void P_PlayerAfterThink(player_t *player) player->mo->momx = (chain->x - player->mo->x)*2; player->mo->momy = (chain->y - player->mo->y)*2; player->mo->momz = (chain->z - (player->mo->height-chain->height/2) - player->mo->z)*2; - P_TeleportMove(player->mo, chain->x, chain->y, chain->z - (player->mo->height-chain->height/2)); + P_MoveOrigin(player->mo, chain->x, chain->y, chain->z - (player->mo->height-chain->height/2)); if (!player->powers[pw_flashing]) // handle getting hurt { player->pflags |= PF_JUMPED; @@ -12724,7 +12724,7 @@ void P_PlayerAfterThink(player_t *player) mo->tics = walktics; } - P_TeleportMove(player->mo, rock->x, rock->y, rock->z + ((mo->eflags & MFE_VERTICALFLIP) ? -mo->height : rock->height)); + P_MoveOrigin(player->mo, rock->x, rock->y, rock->z + ((mo->eflags & MFE_VERTICALFLIP) ? -mo->height : rock->height)); break; } case CR_PTERABYTE: // being carried by a Pterabyte From 9f845622cde98f45af17fb1f1c4449e0e95d7f8e Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 25 Apr 2022 14:45:26 -0500 Subject: [PATCH 053/137] Revert "P_InitAngle, to fix angle interpolation on spawning objects" This reverts commit a80c98bd164a2748cbbfad9027b34601185d93f5. --- src/p_enemy.c | 69 ++++++++++++++++++++++++------------------------- src/p_inter.c | 10 ++++---- src/p_local.h | 3 --- src/p_map.c | 24 ----------------- src/p_mobj.c | 70 ++++++++++++++++++++++---------------------------- src/p_saveg.c | 20 +++++++-------- src/p_spec.c | 2 +- src/p_telept.c | 4 +-- src/p_user.c | 2 +- src/r_fps.c | 5 ---- src/r_fps.h | 2 -- 11 files changed, 84 insertions(+), 127 deletions(-) diff --git a/src/p_enemy.c b/src/p_enemy.c index e7ed241e6..6a9971c82 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -1406,7 +1406,7 @@ void A_StatueBurst(mobj_t *actor) if (!locvar1 || !(new = P_SpawnMobjFromMobj(actor, 0, 0, 0, locvar1))) return; - P_InitAngle(new, actor->angle); + new->angle = actor->angle; P_SetTarget(&new->target, actor->target); if (locvar2) P_SetMobjState(new, (statenum_t)locvar2); @@ -2700,8 +2700,8 @@ void A_LobShot(mobj_t *actor) P_SetTarget(&shot->target, actor); // where it came from - P_InitAngle(shot, actor->angle); - an = actor->angle >> ANGLETOFINESHIFT; + shot->angle = an = actor->angle; + an >>= ANGLETOFINESHIFT; dist = P_AproxDistance(actor->target->x - shot->x, actor->target->y - shot->y); @@ -3067,7 +3067,7 @@ void A_Boss1Laser(mobj_t *actor) S_StartSound(actor, mobjinfo[locvar1].seesound); point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); - P_InitAngle(point, actor->angle); + point->angle = actor->angle; point->fuse = dur+1; P_SetTarget(&point->target, actor->target); P_SetTarget(&actor->target, point); @@ -3077,7 +3077,7 @@ void A_Boss1Laser(mobj_t *actor) point = P_SpawnMobj(x, y, z, locvar1); P_SetTarget(&point->target, actor); - P_InitAngle(point, actor->angle); + point->angle = actor->angle; speed = point->radius; point->momz = FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT), speed); point->momx = FixedMul(FINESINE(angle>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(point->angle>>ANGLETOFINESHIFT), speed)); @@ -3086,7 +3086,7 @@ void A_Boss1Laser(mobj_t *actor) for (i = 0; i < 256; i++) { mobj_t *mo = P_SpawnMobj(point->x, point->y, point->z, point->type); - P_InitAngle(mo, point->angle); + mo->angle = point->angle; mo->color = LASERCOLORS[((UINT8)(i + 3*dur) >> 2) % sizeof(LASERCOLORS)]; // codeing P_UnsetThingPosition(mo); mo->flags = MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY; @@ -3118,7 +3118,7 @@ void A_Boss1Laser(mobj_t *actor) if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1 && dur & 1) { point = P_SpawnMobj(x, y, floorz, MT_EGGMOBILE_FIRE); - P_InitAngle(point, actor->angle); + point->angle = actor->angle; point->destscale = actor->scale; P_SetScale(point, point->destscale); P_SetTarget(&point->target, actor); @@ -3970,7 +3970,7 @@ bossjustdie: P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle); + mo2->angle = mo->angle; P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); P_SetObjectMomZ(mo2, 4*FRACUNIT, false); P_SetMobjState(mo2, S_BOSSEGLZ1); @@ -3979,7 +3979,7 @@ bossjustdie: P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle); + mo2->angle = mo->angle; P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); P_SetObjectMomZ(mo2, 4*FRACUNIT, false); P_SetMobjState(mo2, S_BOSSEGLZ2); @@ -3991,7 +3991,7 @@ bossjustdie: P_ReturnThrustX(mo, mo->angle - ANGLE_90, 32<angle - ANGLE_90, 32<angle); + mo2->angle = mo->angle; P_InstaThrust(mo2, mo2->angle - ANGLE_90, 4*mo2->scale); P_SetObjectMomZ(mo2, 4*FRACUNIT, false); P_SetMobjState(mo2, S_BOSSTANK1); @@ -4000,7 +4000,7 @@ bossjustdie: P_ReturnThrustX(mo, mo->angle + ANGLE_90, 32<angle + ANGLE_90, 32<angle); + mo2->angle = mo->angle; P_InstaThrust(mo2, mo2->angle + ANGLE_90, 4*mo2->scale); P_SetObjectMomZ(mo2, 4*FRACUNIT, false); P_SetMobjState(mo2, S_BOSSTANK2); @@ -4008,7 +4008,7 @@ bossjustdie: mo2 = P_SpawnMobjFromMobj(mo, 0, 0, mobjinfo[MT_EGGMOBILE2].height + (32<angle); + mo2->angle = mo->angle; P_SetObjectMomZ(mo2, 4*FRACUNIT, false); mo2->momz += mo->momz; P_SetMobjState(mo2, S_BOSSSPIGOT); @@ -4017,7 +4017,7 @@ bossjustdie: case MT_EGGMOBILE3: { mo2 = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_BOSSJUNK); - P_InitAngle(mo2, mo->angle); + mo2->angle = mo->angle; P_SetMobjState(mo2, S_BOSSSEBH1); } break; @@ -4091,8 +4091,7 @@ bossjustdie: pole->tracer->flags |= MF_NOCLIPTHING; P_SetScale(pole, (pole->destscale = 2*FRACUNIT)); P_SetScale(pole->tracer, (pole->tracer->destscale = 2*FRACUNIT)); - P_InitAngle(pole, mo->tracer->angle); - P_InitAngle(pole->tracer, mo->tracer->angle); + pole->angle = pole->tracer->angle = mo->tracer->angle; pole->tracer->tracer->angle = pole->angle - ANGLE_90; pole->momx = P_ReturnThrustX(pole, pole->angle, speed); pole->momy = P_ReturnThrustY(pole, pole->angle, speed); @@ -6255,7 +6254,7 @@ void A_RockSpawn(mobj_t *actor) mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FALLINGROCK); P_SetMobjState(mo, mobjinfo[type].spawnstate); - P_InitAngle(mo, R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y)); + mo->angle = R_PointToAngle2(line->v2->x, line->v2->y, line->v1->x, line->v1->y); P_InstaThrust(mo, mo->angle, dist + randomoomph); mo->momz = dist + randomoomph; @@ -8313,7 +8312,7 @@ void A_Boss3ShockThink(mobj_t *actor) snew->momx = (actor->momx + snext->momx) >> 1; snew->momy = (actor->momy + snext->momy) >> 1; snew->momz = (actor->momz + snext->momz) >> 1; // is this really needed? - P_InitAngle(snew, (actor->angle + snext->angle) >> 1); + snew->angle = (actor->angle + snext->angle) >> 1; P_SetTarget(&snew->target, actor->target); snew->fuse = actor->fuse; @@ -8469,7 +8468,7 @@ void A_SpawnObjectAbsolute(mobj_t *actor) mo = P_SpawnMobj(x<angle); + mo->angle = actor->angle; if (actor->eflags & MFE_VERTICALFLIP) mo->flags2 |= MF2_OBJECTFLIP; @@ -8511,7 +8510,7 @@ void A_SpawnObjectRelative(mobj_t *actor) (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[type].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), type); // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn - P_InitAngle(mo, actor->angle); + mo->angle = actor->angle; if (actor->eflags & MFE_VERTICALFLIP) mo->flags2 |= MF2_OBJECTFLIP; @@ -9221,7 +9220,7 @@ void A_BossJetFume(mobj_t *actor) P_SetScale(filler, filler->destscale); if (actor->eflags & MFE_VERTICALFLIP) filler->flags2 |= MF2_OBJECTFLIP; - P_InitAngle(filler, actor->angle - ANGLE_180); + filler->angle = actor->angle - ANGLE_180; P_SetTarget(&actor->tracer, filler); }*/ @@ -10983,7 +10982,7 @@ void A_TrapShot(mobj_t *actor) S_StartSound(missile, missile->info->seesound); P_SetTarget(&missile->target, actor); - P_InitAngle(missile, actor->angle); + missile->angle = actor->angle; speed = FixedMul(missile->info->speed, missile->scale); @@ -11562,7 +11561,7 @@ void A_BrakLobShot(mobj_t *actor) S_StartSound(shot, shot->info->seesound); P_SetTarget(&shot->target, actor); // where it came from - P_InitAngle(shot, actor->angle); + shot->angle = actor->angle; // Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle. shot->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(shot->angle >> ANGLETOFINESHIFT)); @@ -11629,7 +11628,7 @@ void A_NapalmScatter(mobj_t *actor) mo = P_SpawnMobj(actor->x, actor->y, actor->z, typeOfShot); P_SetTarget(&mo->target, actor->target); // Transfer target so Brak doesn't hit himself like an idiot - P_InitAngle(mo, fa << ANGLETOFINESHIFT); + mo->angle = fa << ANGLETOFINESHIFT; mo->momx = FixedMul(FINECOSINE(fa),vx); mo->momy = FixedMul(FINESINE(fa),vx); mo->momz = vy; @@ -11653,7 +11652,7 @@ void A_SpawnFreshCopy(mobj_t *actor) newObject = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->type); newObject->flags2 = actor->flags2 & MF2_AMBUSH; - P_InitAngle(newObject, actor->angle); + newObject->angle = actor->angle; newObject->color = actor->color; P_SetTarget(&newObject->target, actor->target); P_SetTarget(&newObject->tracer, actor->tracer); @@ -11687,7 +11686,7 @@ mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz } flicky = P_SpawnMobjFromMobj(actor, offsx, offsy, 0, flickytype); - P_InitAngle(flicky, actor->angle); + flicky->angle = actor->angle; if (flickytype == MT_SEED) flicky->z += P_MobjFlip(actor)*(actor->height - flicky->height)/2; @@ -11837,7 +11836,7 @@ void A_FlickyCenter(mobj_t *actor) else if (actor->flags & MF_SLIDEME) // aimless { actor->tracer->fuse = 0; // less than 2*TICRATE means move aimlessly. - P_InitAngle(actor->tracer, P_RandomKey(180)*ANG2); + actor->tracer->angle = P_RandomKey(180)*ANG2; } else //orbit actor->tracer->fuse = FRACUNIT; @@ -12533,7 +12532,7 @@ void A_ConnectToGround(mobj_t *actor) { work = P_SpawnMobjFromMobj(actor, 0, 0, workz, locvar1); if (work) - P_InitAngle(work, ang); + work->angle = ang; ang += ANGLE_90; workz += workh; } @@ -12579,7 +12578,7 @@ void A_SpawnParticleRelative(mobj_t *actor) (actor->eflags & MFE_VERTICALFLIP) ? ((actor->z + actor->height - mobjinfo[MT_PARTICLE].height) - FixedMul(z<scale)) : (actor->z + FixedMul(z<scale)), MT_PARTICLE); // Spawn objects with an angle matching the spawner's, rather than spawning Eastwards - Monster Iestyn - P_InitAngle(mo, actor->angle); + mo->angle = actor->angle; if (actor->eflags & MFE_VERTICALFLIP) mo->flags2 |= MF2_OBJECTFLIP; @@ -13326,7 +13325,7 @@ void A_Boss5MakeJunk(mobj_t *actor) broked->fuse = TICRATE; else broked->fuse = (((locvar2 & 1) ? 4 : 2)*TICRATE)/3; - P_InitAngle(broked, ang); + broked->angle = ang; P_InstaThrust(broked, ang, ((locvar2 & 2) ? 8 : 5)*actor->scale); P_SetObjectMomZ(broked, (((locvar2) ? 4 : 0) + P_RandomRange(2, 5))< 0) @@ -13405,7 +13404,7 @@ static void P_DustRing(mobjtype_t mobjtype, UINT32 div, fixed_t x, fixed_t y, fi mobjtype ); - P_InitAngle(dust, ang*i + ANGLE_90); + dust->angle = ang*i + ANGLE_90; P_SetScale(dust, FixedMul(initscale, scale)); dust->destscale = FixedMul(4*FRACUNIT + P_RandomFixed(), scale); dust->scalespeed = scale/24; @@ -13759,7 +13758,7 @@ static mobj_t *P_TrainSeg(mobj_t *src, fixed_t x, fixed_t y, fixed_t z, angle_t s->fuse = 16*TICRATE; s->sprite = spr; s->frame = frame|FF_PAPERSPRITE; - P_InitAngle(s, ang); + s->angle = ang; P_Thrust(s, src->angle, 7*FRACUNIT); return s; } @@ -14131,7 +14130,7 @@ void A_SaloonDoorSpawn(mobj_t *actor) // One door... if (!(door = P_SpawnMobjFromMobj(actor, c, s, 0, locvar1))) return; - P_InitAngle(door, ang + ANGLE_180); + door->angle = ang + ANGLE_180; door->extravalue1 = AngleFixed(door->angle); // Origin angle door->extravalue2 = 0; // Angular speed P_SetTarget(&door->tracer, actor); // Origin door @@ -14139,7 +14138,7 @@ void A_SaloonDoorSpawn(mobj_t *actor) // ...two door! if (!(door = P_SpawnMobjFromMobj(actor, -c, -s, 0, locvar1))) return; - P_InitAngle(door, ang); + door->angle = ang; door->extravalue1 = AngleFixed(door->angle); // Origin angle door->extravalue2 = 0; // Angular speed P_SetTarget(&door->tracer, actor); // Origin door @@ -14335,7 +14334,7 @@ void A_SpawnPterabytes(mobj_t *actor) c = FINECOSINE(fa); s = FINESINE(fa); waypoint = P_SpawnMobjFromMobj(actor, FixedMul(c, rad), FixedMul(s, rad), 0, MT_PTERABYTEWAYPOINT); - P_InitAngle(waypoint, ang + ANGLE_90); + waypoint->angle = ang + ANGLE_90; P_SetTarget(&waypoint->tracer, actor); ptera = P_SpawnMobjFromMobj(waypoint, 0, 0, 0, MT_PTERABYTE); ptera->angle = waypoint->angle; @@ -14515,7 +14514,7 @@ void A_DragonbomberSpawn(mobj_t *actor) segment = P_SpawnMobjFromMobj(mo, x, y, 0, MT_DRAGONTAIL); P_SetTarget(&segment->target, mo); P_SetTarget(&mo->tracer, segment); - P_InitAngle(segment, mo->angle); + segment->angle = mo->angle; mo = segment; } for (i = 0; i < 2; i++) // spawn wings diff --git a/src/p_inter.c b/src/p_inter.c index 56ef23578..582cdb0d0 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2749,7 +2749,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget mo->angle = FixedAngle((P_RandomKey(36)*10)<angle); + mo2->angle = mo->angle; P_SetMobjState(mo2, S_BOSSSEBH2); if (++i == 2) // we've already removed 2 of these, let's stop now @@ -2852,7 +2852,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE);\ P_SetMobjState(chunk, target->info->xdeathstate);\ chunk->health = 0;\ - P_InitAngle(chunk, angtweak);\ + chunk->angle = angtweak;\ P_UnsetThingPosition(chunk);\ chunk->flags = MF_NOCLIP;\ chunk->x += xmov;\ @@ -2874,7 +2874,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_SPIKE); P_SetMobjState(chunk, target->info->deathstate); chunk->health = 0; - P_InitAngle(chunk, ang + ANGLE_180); + chunk->angle = ang + ANGLE_180; P_UnsetThingPosition(chunk); chunk->flags = MF_NOCLIP; chunk->x -= xoffs; @@ -2920,7 +2920,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget chunk = P_SpawnMobjFromMobj(target, 0, 0, 0, MT_WALLSPIKE);\ P_SetMobjState(chunk, target->info->xdeathstate);\ chunk->health = 0;\ - P_InitAngle(chunk, target->angle);\ + chunk->angle = target->angle;\ P_UnsetThingPosition(chunk);\ chunk->flags = MF_NOCLIP;\ chunk->x += xmov - forwardxoffs;\ @@ -2946,7 +2946,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget P_SetMobjState(chunk, target->info->deathstate); chunk->health = 0; - P_InitAngle(chunk, target->angle); + chunk->angle = target->angle; P_UnsetThingPosition(chunk); chunk->flags = MF_NOCLIP; chunk->x += forwardxoffs - xoffs; diff --git a/src/p_local.h b/src/p_local.h index 4dc0ce615..7638a04f5 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -416,9 +416,6 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff); boolean P_Move(mobj_t *actor, fixed_t speed); boolean P_SetOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); boolean P_MoveOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z); -void P_InitAngle(mobj_t *thing, angle_t newValue); -void P_InitPitch(mobj_t *thing, angle_t newValue); -void P_InitRoll(mobj_t *thing, angle_t newValue); void P_SlideMove(mobj_t *mo); void P_BounceMove(mobj_t *mo); boolean P_CheckSight(mobj_t *t1, mobj_t *t2); diff --git a/src/p_map.c b/src/p_map.c index de10e2de3..c69b564e3 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -131,30 +131,6 @@ boolean P_MoveOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z) return P_TeleportMove(thing, x, y, z); } -// -// P_InitAngle - Change an object's angle, including interp values. -// -void P_InitAngle(mobj_t *thing, angle_t newValue) -{ - thing->angle = thing->old_angle = newValue; -} - -// -// P_InitPitch - Change an object's pitch, including interp values. -// -void P_InitPitch(mobj_t *thing, angle_t newValue) -{ - thing->pitch = thing->old_pitch = newValue; -} - -// -// P_InitRoll - Change an object's roll, including interp values. -// -void P_InitRoll(mobj_t *thing, angle_t newValue) -{ - thing->roll = thing->old_roll = newValue; -} - // ========================================================================= // MOVEMENT ITERATOR FUNCTIONS // ========================================================================= diff --git a/src/p_mobj.c b/src/p_mobj.c index 60823f92d..35dab0084 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6342,7 +6342,7 @@ void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 numb mobj->z -= mobj->height>>1; // change angle - P_InitAngle(mobj, R_PointToAngle2(mobj->x, mobj->y, x, y)); + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, x, y); // change slope dist = P_AproxDistance(P_AproxDistance(x - mobj->x, y - mobj->y), z - mobj->z); @@ -7226,7 +7226,7 @@ static void P_FlameJetSceneryThink(mobj_t *mobj) flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME); P_SetMobjState(flame, S_FLAMEJETFLAME4); - P_InitAngle(flame, mobj->angle); + flame->angle = mobj->angle; if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side flame->momz = mobj->fuse << (FRACBITS - 2); @@ -10698,7 +10698,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_CRUSHSTACEAN: { mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CRUSHCLAW); - P_InitAngle(bigmeatyclaw, mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270)); + bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);; P_SetTarget(&mobj->tracer, bigmeatyclaw); P_SetTarget(&bigmeatyclaw->tracer, mobj); mobj->reactiontime >>= 1; @@ -10707,7 +10707,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) case MT_BANPYURA: { mobj_t *bigmeatyclaw = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_BANPSPRING); - P_InitAngle(bigmeatyclaw, mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270)); + bigmeatyclaw->angle = mobj->angle + ((mobj->flags2 & MF2_AMBUSH) ? ANGLE_90 : ANGLE_270);; P_SetTarget(&mobj->tracer, bigmeatyclaw); P_SetTarget(&bigmeatyclaw->tracer, mobj); mobj->reactiontime >>= 1; @@ -10829,7 +10829,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_MINECARTEND: P_SetTarget(&mobj->tracer, P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_MINECARTENDSOLID)); - P_InitAngle(mobj->tracer, mobj->angle + ANGLE_90); + mobj->tracer->angle = mobj->angle + ANGLE_90; break; case MT_TORCHFLOWER: { @@ -11462,7 +11462,7 @@ void P_SpawnPlayer(INT32 playernum) mobj = P_SpawnMobj(0, 0, 0, MT_PLAYER); (mobj->player = p)->mo = mobj; - P_InitAngle(mobj, 0); + mobj->angle = 0; // set color translations for player sprites mobj->color = p->skincolor; @@ -11530,12 +11530,6 @@ void P_AfterPlayerSpawn(INT32 playernum) player_t *p = &players[playernum]; mobj_t *mobj = p->mo; - // Update interpolation - mobj->old_x = mobj->x; - mobj->old_y = mobj->y; - mobj->old_z = mobj->z; - mobj->old_angle = mobj->angle; - P_SetPlayerAngle(p, mobj->angle); p->viewheight = 41*p->height/48; @@ -12321,7 +12315,7 @@ static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle) spawnee->friction = mroll;\ spawnee->movefactor = mwidthset;\ spawnee->movecount = dist;\ - P_InitAngle(spawnee, myaw);\ + spawnee->angle = myaw;\ spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\ spawnee->flags2 |= (mflags2apply|moreflags2);\ spawnee->eflags |= meflagsapply;\ @@ -12639,29 +12633,29 @@ static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong) statenum_t rollerstate = strong ? S_REDBOOSTERROLLER : S_YELLOWBOOSTERROLLER; mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG); - P_InitAngle(seg, angle - ANGLE_90); + seg->angle = angle - ANGLE_90; P_SetMobjState(seg, facestate); seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG); - P_InitAngle(seg, angle + ANGLE_90); + seg->angle = angle + ANGLE_90; P_SetMobjState(seg, facestate); seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG); - P_InitAngle(seg, angle); + seg->angle = angle; P_SetMobjState(seg, leftstate); seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG); - P_InitAngle(seg, angle); + seg->angle = angle; P_SetMobjState(seg, rightstate); seg = P_SpawnMobjFromMobj(mobj, 13*(x1 + x2), 13*(y1 + y2), 0, MT_BOOSTERROLLER); - P_InitAngle(seg, angle); + seg->angle = angle; P_SetMobjState(seg, rollerstate); seg = P_SpawnMobjFromMobj(mobj, 13*(x1 - x2), 13*(y1 - y2), 0, MT_BOOSTERROLLER); - P_InitAngle(seg, angle); + seg->angle = angle; P_SetMobjState(seg, rollerstate); seg = P_SpawnMobjFromMobj(mobj, -13*(x1 + x2), -13*(y1 + y2), 0, MT_BOOSTERROLLER); - P_InitAngle(seg, angle); + seg->angle = angle; P_SetMobjState(seg, rollerstate); seg = P_SpawnMobjFromMobj(mobj, -13*(x1 - x2), -13*(y1 - y2), 0, MT_BOOSTERROLLER); - P_InitAngle(seg, angle); + seg->angle = angle; P_SetMobjState(seg, rollerstate); return true; @@ -12877,9 +12871,9 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean case MT_THZTREE: { // Spawn the branches angle_t mobjangle = FixedAngle((mthing->angle % 113) << FRACBITS); - P_InitAngle(P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH), mobjangle + ANGLE_22h); - P_InitAngle(P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH), mobjangle + ANGLE_157h); - P_InitAngle(P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH), mobjangle + ANGLE_270); + P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h; + P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h; + P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; } break; case MT_TUTORIALPLANT: @@ -12905,10 +12899,10 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean case MT_CEZPOLE2: { // Spawn the banner angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS); - P_InitAngle(P_SpawnMobjFromMobj(mobj, + P_SpawnMobjFromMobj(mobj, P_ReturnThrustX(mobj, mobjangle, 4 << FRACBITS), P_ReturnThrustY(mobj, mobjangle, 4 << FRACBITS), - 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2)), mobjangle + ANGLE_90); + 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90; } break; case MT_HHZTREE_TOP: @@ -12917,7 +12911,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj_t* leaf; #define doleaf(x, y) \ leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\ - P_InitAngle(leaf, mobjangle);\ + leaf->angle = mobjangle;\ P_SetMobjState(leaf, leaf->info->seestate);\ mobjangle += ANGLE_90 doleaf(FRACUNIT, 0); @@ -12958,7 +12952,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean fixed_t xoffs = FINECOSINE(fa); fixed_t yoffs = FINESINE(fa); mobj_t* leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF); - P_InitAngle(leaf, angle); + leaf->angle = angle; angle += ANGLE_45; } break; @@ -13084,7 +13078,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), mobj->z, MT_WALLSPIKEBASE); - P_InitAngle(base, mobjangle + ANGLE_90); + base->angle = mobjangle + ANGLE_90; base->destscale = mobj->destscale; P_SetScale(base, mobj->scale); P_SetTarget(&base->target, mobj); @@ -13212,12 +13206,10 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, return mobj; if (doangle) - { - P_InitAngle(mobj, FixedAngle(mthing->angle << FRACBITS)); - } + mobj->angle = FixedAngle(mthing->angle << FRACBITS); - P_InitPitch(mobj, FixedAngle(mthing->pitch << FRACBITS)); - P_InitRoll(mobj, FixedAngle(mthing->roll << FRACBITS)); + mobj->pitch = FixedAngle(mthing->pitch << FRACBITS); + mobj->roll = FixedAngle(mthing->roll << FRACBITS); mthing->mobj = mobj; @@ -13653,7 +13645,7 @@ mobj_t *P_SpawnXYZMissile(mobj_t *source, mobj_t *dest, mobjtype_t type, P_SetTarget(&th->target, source); // where it came from an = R_PointToAngle2(x, y, dest->x, dest->y); - P_InitAngle(th, an); + th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul(speed, FINECOSINE(an)); th->momy = FixedMul(speed, FINESINE(an)); @@ -13715,7 +13707,7 @@ mobj_t *P_SpawnAlteredDirectionMissile(mobj_t *source, mobjtype_t type, fixed_t P_SetTarget(&th->target, source->target); // where it came from an = R_PointToAngle2(0, 0, source->momx, source->momy) + (ANG1*shiftingAngle); - P_InitAngle(th, an); + th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul(speed, FINECOSINE(an)); th->momy = FixedMul(speed, FINESINE(an)); @@ -13780,7 +13772,7 @@ mobj_t *P_SpawnPointMissile(mobj_t *source, fixed_t xa, fixed_t ya, fixed_t za, P_SetTarget(&th->target, source); // where it came from an = R_PointToAngle2(x, y, xa, ya); - P_InitAngle(th, an); + th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul(speed, FINECOSINE(an)); th->momy = FixedMul(speed, FINESINE(an)); @@ -13859,7 +13851,7 @@ mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type) else an = R_PointToAngle2(source->x, source->y, dest->x, dest->y); - P_InitAngle(th, an); + th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul(speed, FINECOSINE(an)); th->momy = FixedMul(speed, FINESINE(an)); @@ -13949,7 +13941,7 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai if (source->player && source->player->charability == CA_FLY) speed = FixedMul(speed, 3*FRACUNIT/2); - P_InitAngle(th, an); + th->angle = an; th->momx = FixedMul(speed, FINECOSINE(an>>ANGLETOFINESHIFT)); th->momy = FixedMul(speed, FINESINE(an>>ANGLETOFINESHIFT)); diff --git a/src/p_saveg.c b/src/p_saveg.c index d493ae013..f1c77b1f8 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -2759,19 +2759,19 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->info = &mobjinfo[mobj->type]; if (diff & MD_POS) { - mobj->x = mobj->old_x = READFIXED(save_p); - mobj->y = mobj->old_y = READFIXED(save_p); - mobj->angle = mobj->old_angle = READANGLE(save_p); - mobj->pitch = mobj->old_pitch = READANGLE(save_p); - mobj->roll = mobj->old_roll = READANGLE(save_p); + mobj->x = READFIXED(save_p); + mobj->y = READFIXED(save_p); + mobj->angle = READANGLE(save_p); + mobj->pitch = READANGLE(save_p); + mobj->roll = READANGLE(save_p); } else { - mobj->x = mobj->old_x = mobj->spawnpoint->x << FRACBITS; - mobj->y = mobj->old_y = mobj->spawnpoint->y << FRACBITS; - mobj->angle = mobj->old_angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT); - mobj->pitch = mobj->old_pitch = FixedAngle(mobj->spawnpoint->pitch*FRACUNIT); - mobj->roll = mobj->old_roll = FixedAngle(mobj->spawnpoint->roll*FRACUNIT); + mobj->x = mobj->spawnpoint->x << FRACBITS; + mobj->y = mobj->spawnpoint->y << FRACBITS; + mobj->angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT); + mobj->pitch = FixedAngle(mobj->spawnpoint->pitch*FRACUNIT); + mobj->roll = FixedAngle(mobj->spawnpoint->roll*FRACUNIT); } if (diff & MD_MOM) { diff --git a/src/p_spec.c b/src/p_spec.c index ad70f6c88..e37fc6a0f 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -3755,7 +3755,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec) if (mobj) { if (line->flags & ML_EFFECT1) - P_InitAngle(mobj, R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y)); + mobj->angle = R_PointToAngle2(line->v1->x, line->v1->y, line->v2->x, line->v2->y); CONS_Debug(DBG_GAMELOGIC, "Linedef Type %d - Spawn Object: %d spawned at (%d, %d, %d)\n", line->special, mobj->type, mobj->x>>FRACBITS, mobj->y>>FRACBITS, mobj->z>>FRACBITS); //TODO: Convert mobj->type to a string somehow. } else diff --git a/src/p_telept.c b/src/p_telept.c index 745d52745..4d10f1df3 100644 --- a/src/p_telept.c +++ b/src/p_telept.c @@ -101,7 +101,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, P_FlashPal(thing->player, PAL_MIXUP, 10); } - P_InitAngle(thing, angle); + thing->angle = angle; thing->momx = thing->momy = thing->momz = 0; @@ -174,7 +174,7 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle P_FlashPal(thing->player, PAL_MIXUP, 10); } - P_InitAngle(thing, angle); + thing->angle = angle; return true; } diff --git a/src/p_user.c b/src/p_user.c index a661308ed..a3e98f516 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -393,7 +393,7 @@ void P_GiveFinishFlags(player_t *player) fixed_t xoffs = FINECOSINE(fa); fixed_t yoffs = FINESINE(fa); mobj_t* flag = P_SpawnMobjFromMobj(player->mo, xoffs, yoffs, 0, MT_FINISHFLAG); - P_InitAngle(flag, angle); + flag->angle = angle; angle += FixedAngle(120*FRACUNIT); P_SetTarget(&flag->target, player->mo); diff --git a/src/r_fps.c b/src/r_fps.c index 738df2020..cc518cc35 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -264,9 +264,6 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) { out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); } - - out->pitch = R_LerpAngle(mobj->old_pitch, mobj->pitch, frac); - out->roll = R_LerpAngle(mobj->old_roll, mobj->roll, frac); } void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out) @@ -275,8 +272,6 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); - out->pitch = 0; - out->roll = 0; } static void AddInterpolator(levelinterpolator_t* interpolator) diff --git a/src/r_fps.h b/src/r_fps.h index 8ce2f3c26..59d3df747 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -54,8 +54,6 @@ typedef struct { fixed_t y; fixed_t z; angle_t angle; - angle_t pitch; - angle_t roll; } interpmobjstate_t; // Level interpolators From 873af23f220124e3054df205bd562328a37282d9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 15:43:36 -0400 Subject: [PATCH 054/137] Waypoint polyobjects interpolate z & children --- src/p_polyobj.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/p_polyobj.c b/src/p_polyobj.c index a553ca235..e80725367 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -2132,8 +2132,10 @@ boolean EV_DoPolyObjMove(polymovedata_t *pmdata) boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) { polyobj_t *po; + polyobj_t *oldpo; polywaypoint_t *th; mobj_t *first = NULL; + INT32 start; if (!(po = Polyobj_GetForNum(pwdata->polyObjNum))) { @@ -2186,6 +2188,23 @@ boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata) // interpolation R_CreateInterpolator_Polyobj(&th->thinker, po); + // T_PolyObjWaypoint is the only polyobject movement + // that can adjust z, so we add these ones too. + R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, false); + R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, true); + + // Most other polyobject functions handle children by recursively + // giving each child another thinker. T_PolyObjWaypoint handles + // it manually though, which means we need to manually give them + // interpolation here instead. + start = 0; + oldpo = po; + while ((po = Polyobj_GetChild(oldpo, &start))) + { + R_CreateInterpolator_Polyobj(&th->thinker, po); + R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, false); + R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, true); + } th->pointnum = first->health; From dbd5ddf95d0e63902954d3e7ef8f63b2a99bac7e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 16:49:07 -0400 Subject: [PATCH 055/137] Add interpolation to more moving plane types Adds interpolation to the following: - Crumbling platforms - Mario blocks - Floatbob platforms (this one works really strangely due to two thinkers, maybe double-check this one?) --- src/p_floor.c | 12 ++++++++++++ src/p_spec.c | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/p_floor.c b/src/p_floor.c index 5fcefd203..e583f8c66 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2303,6 +2303,10 @@ void EV_BounceSector(sector_t *sec, fixed_t momz, line_t *sourceline) bouncer->speed = momz/2; bouncer->distance = FRACUNIT; bouncer->low = true; + + // interpolation + R_CreateInterpolator_SectorPlane(&bouncer->thinker, sec, false); + R_CreateInterpolator_SectorPlane(&bouncer->thinker, sec, true); } // For T_ContinuousFalling special @@ -2384,6 +2388,10 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, crumble->sector->crumblestate = CRUMBLE_ACTIVATED; + // interpolation + R_CreateInterpolator_SectorPlane(&crumble->thinker, sec, false); + R_CreateInterpolator_SectorPlane(&crumble->thinker, sec, true); + TAG_ITER_SECTORS(tag, i) { foundsec = §ors[i]; @@ -2435,6 +2443,10 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) block->ceilingstartheight = block->sector->ceilingheight; block->tag = (INT16)Tag_FGet(§or->tags); + // interpolation + R_CreateInterpolator_SectorPlane(&block->thinker, roversec, false); + R_CreateInterpolator_SectorPlane(&block->thinker, roversec, true); + if (itsamonitor) { oldx = thing->x; diff --git a/src/p_spec.c b/src/p_spec.c index e37fc6a0f..a02fc3726 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -5667,6 +5667,10 @@ static void P_AddFloatThinker(sector_t *sec, UINT16 tag, line_t *sourceline) floater->sector = sec; floater->tag = (INT16)tag; floater->sourceline = sourceline; + + // interpolation + R_CreateInterpolator_SectorPlane(&floater->thinker, sec, false); + R_CreateInterpolator_SectorPlane(&floater->thinker, sec, true); } /** From 6fe25f7dbb243cb153add6e14be37826f3e9bcf5 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 25 Apr 2022 16:39:40 -0500 Subject: [PATCH 056/137] Reset overlays interp states each TryRunTics --- src/p_mobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 35dab0084..0f1353b7c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6901,6 +6901,8 @@ void P_RunOverlays(void) else P_SetThingPosition(mo); P_CheckPosition(mo, mo->x, mo->y); + + R_ResetMobjInterpolationState(mo); } P_SetTarget(&overlaycap, NULL); } From f330374c1fee6609025d820680d4453c5ffcfbbe Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 17:50:07 -0400 Subject: [PATCH 057/137] Interpolate model interpolation (lol) --- src/hardware/hw_drv.h | 2 +- src/hardware/hw_md2.c | 14 +++++++++----- src/hardware/r_opengl/r_opengl.c | 10 +++++----- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/hardware/hw_drv.h b/src/hardware/hw_drv.h index 718774773..3b9b8681c 100644 --- a/src/hardware/hw_drv.h +++ b/src/hardware/hw_drv.h @@ -51,7 +51,7 @@ EXPORT void HWRAPI(ClearMipMapCache) (void); EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value); //Hurdler: added for new development -EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface); +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface); EXPORT void HWRAPI(CreateModelVBOs) (model_t *model); EXPORT void HWRAPI(SetTransform) (FTransform *ptransform); EXPORT INT32 HWRAPI(GetTextureUsed) (void); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 67bed7ee3..ade5ce3cb 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1331,8 +1331,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) { patch_t *gpatch, *blendgpatch; GLPatch_t *hwrPatch = NULL, *hwrBlendPatch = NULL; - INT32 durs = spr->mobj->state->tics; - INT32 tics = spr->mobj->tics; + float durs = (float)spr->mobj->state->tics; + float tics = (float)spr->mobj->tics; const boolean papersprite = (R_ThingIsPaperSprite(spr->mobj) && !R_ThingIsFloorSprite(spr->mobj)); const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj)); const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj)); @@ -1501,8 +1501,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) if (spr->mobj->frame & FF_ANIMATE) { // set duration and tics to be the correct values for FF_ANIMATE states - durs = spr->mobj->state->var2; - tics = spr->mobj->anim_duration; + durs = (float)spr->mobj->state->var2; + tics = (float)spr->mobj->anim_duration; } frame = (spr->mobj->frame & FF_FRAMEMASK); @@ -1526,7 +1526,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) } #ifdef USE_MODEL_NEXTFRAME -#define INTERPOLERATION_LIMIT TICRATE/4 + // Interpolate the model interpolation. (lol) + tics -= FixedToFloat(rendertimefrac); + +#define INTERPOLERATION_LIMIT (TICRATE * 0.25f) + if (cv_glmodelinterpolation.value && tics <= durs && tics <= INTERPOLERATION_LIMIT) { if (durs > INTERPOLERATION_LIMIT) diff --git a/src/hardware/r_opengl/r_opengl.c b/src/hardware/r_opengl/r_opengl.c index 7ec7ee270..a58097c91 100644 --- a/src/hardware/r_opengl/r_opengl.c +++ b/src/hardware/r_opengl/r_opengl.c @@ -2672,7 +2672,7 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model) #define BUFFER_OFFSET(i) ((void*)(i)) -static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) +static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) { static GLRGBAFloat poly = {0,0,0,0}; static GLRGBAFloat tint = {0,0,0,0}; @@ -2701,11 +2701,11 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 scaley = scale; scalez = scale; - if (duration != 0 && duration != -1 && tics != -1) // don't interpolate if instantaneous or infinite in length + if (duration > 0.0 && tics >= 0.0) // don't interpolate if instantaneous or infinite in length { - UINT32 newtime = (duration - tics); // + 1; + float newtime = (duration - tics); // + 1; - pol = (newtime)/(float)duration; + pol = newtime / duration; if (pol > 1.0f) pol = 1.0f; @@ -2977,7 +2977,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 // -----------------+ // HWRAPI DrawModel : Draw a model // -----------------+ -EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) +EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface) { DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface); } From 7dd7cccd79fbeaf82936b3553d66b90d0f89cfde Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 25 Apr 2022 17:11:39 -0500 Subject: [PATCH 058/137] Use interp tracer pos for GL linkdraw --- src/hardware/hw_main.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index cafa9ff50..4944ff5a8 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5378,13 +5378,24 @@ static void HWR_ProjectSprite(mobj_t *thing) if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) { + interpmobjstate_t tracer_interp = {}; + if (! R_ThingVisible(thing->tracer)) return; + if (R_UsingFrameInterpolation() && !paused) + { + R_InterpolateMobjState(thing->tracer, rendertimefrac, &tracer_interp); + } + else + { + R_InterpolateMobjState(thing->tracer, FRACUNIT, &tracer_interp); + } + // calculate tz for tracer, same way it is calculated for this sprite // transform the origin point - tr_x = FIXED_TO_FLOAT(thing->tracer->x) - gl_viewx; - tr_y = FIXED_TO_FLOAT(thing->tracer->y) - gl_viewy; + tr_x = FIXED_TO_FLOAT(tracer_interp.x) - gl_viewx; + tr_y = FIXED_TO_FLOAT(tracer_interp.y) - gl_viewy; // rotation around vertical axis tracertz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin); From f34a61156c1c43289a82a87160986f82062cbd14 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 18:15:59 -0400 Subject: [PATCH 059/137] Papersprite angle interpolation Makes the ending signpost smooth --- src/hardware/hw_main.c | 5 ++--- src/r_things.c | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4944ff5a8..827cef657 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5069,7 +5069,6 @@ static void HWR_ProjectSprite(mobj_t *thing) INT32 heightsec, phs; const boolean splat = R_ThingIsFloorSprite(thing); const boolean papersprite = (R_ThingIsPaperSprite(thing) && !splat); - angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle); float z1, z2; fixed_t spr_width, spr_height; @@ -5275,8 +5274,8 @@ static void HWR_ProjectSprite(mobj_t *thing) if (papersprite) { - rightsin = FIXED_TO_FLOAT(FINESINE((mobjangle)>>ANGLETOFINESHIFT)); - rightcos = FIXED_TO_FLOAT(FINECOSINE((mobjangle)>>ANGLETOFINESHIFT)); + rightsin = FIXED_TO_FLOAT(FINESINE(interp.angle >> ANGLETOFINESHIFT)); + rightcos = FIXED_TO_FLOAT(FINECOSINE(interp.angle >> ANGLETOFINESHIFT)); } else { diff --git a/src/r_things.c b/src/r_things.c index a7df5adef..0e1adf16a 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1742,8 +1742,8 @@ static void R_ProjectSprite(mobj_t *thing) offset2 *= -1; } - cosmul = FINECOSINE(thing->angle>>ANGLETOFINESHIFT); - sinmul = FINESINE(thing->angle>>ANGLETOFINESHIFT); + cosmul = FINECOSINE(interp.angle >> ANGLETOFINESHIFT); + sinmul = FINESINE(interp.angle >> ANGLETOFINESHIFT); tr_x += FixedMul(offset, cosmul); tr_y += FixedMul(offset, sinmul); @@ -1759,7 +1759,7 @@ static void R_ProjectSprite(mobj_t *thing) paperoffset = -paperoffset; paperdistance = -paperdistance; } - centerangle = viewangle - thing->angle; + centerangle = viewangle - interp.angle; tr_x += FixedMul(offset2, cosmul); tr_y += FixedMul(offset2, sinmul); From 8597f3876c57fa22de8b0d1362f6299212720fe0 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 25 Apr 2022 18:33:17 -0500 Subject: [PATCH 060/137] Move intermission emerald bounce to ticker --- src/y_inter.c | 88 ++++++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/src/y_inter.c b/src/y_inter.c index 34e58494f..8b5c9efc7 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -83,6 +83,10 @@ typedef union INT32 passedx3; INT32 passedx4; + INT32 emeraldbounces; + INT32 emeraldmomy; + INT32 emeraldy; + y_bonus_t bonuses[2]; patch_t *bonuspatches[2]; @@ -646,7 +650,6 @@ void Y_IntermissionDrawer(void) } // draw the emeralds - //if (intertic & 1) if (LUA_HudEnabled(hud_intermissionemeralds)) { boolean drawthistic = !(ALL7EMERALDS(emeralds) && (intertic & 1)); @@ -663,10 +666,6 @@ void Y_IntermissionDrawer(void) } else if (em < 7) { - static UINT8 emeraldbounces = 0; - static INT32 emeraldmomy = 20; - static INT32 emeraldy = -40; - if (drawthistic) for (i = 0; i < 7; ++i) { @@ -677,45 +676,15 @@ void Y_IntermissionDrawer(void) emeraldx = 152 + (em-3)*28; - if (intertic <= 1) + if (intertic > 1) { - emeraldbounces = 0; - emeraldmomy = 20; - emeraldy = -40; - } - else - { - if (!stagefailed) + if (stagefailed && data.spec.emeraldy < (vid.height/vid.dupy)+16) { - if (emeraldbounces < 3) - { - emeraldy += (++emeraldmomy); - if (emeraldy > 74) - { - S_StartSound(NULL, sfx_tink); // tink - emeraldbounces++; - emeraldmomy = -(emeraldmomy/2); - emeraldy = 74; - } - } - } - else - { - if (emeraldy < (vid.height/vid.dupy)+16) - { - emeraldy += (++emeraldmomy); - emeraldx += intertic - 6; - } - if (emeraldbounces < 1 && emeraldy > 74) - { - S_StartSound(NULL, sfx_shldls); // nope - emeraldbounces++; - emeraldmomy = -(emeraldmomy/2); - emeraldy = 74; - } + emeraldx += intertic - 6; } + if (drawthistic) - V_DrawScaledPatch(emeraldx, emeraldy, 0, emeraldpics[0][em]); + V_DrawScaledPatch(emeraldx, data.spec.emeraldy, 0, emeraldpics[0][em]); } } } @@ -1153,6 +1122,45 @@ void Y_Ticker(void) S_ChangeMusicInternal("_clear", false); // don't loop it tallydonetic = -1; } + + // emerald bounce + if (intertic <= 1) + { + data.spec.emeraldbounces = 0; + data.spec.emeraldmomy = 20; + data.spec.emeraldy = -40; + } + else + { + if (!stagefailed) + { + if (data.spec.emeraldbounces < 3) + { + data.spec.emeraldy += (++data.spec.emeraldmomy); + if (data.spec.emeraldy > 74) + { + S_StartSound(NULL, sfx_tink); // tink + data.spec.emeraldbounces++; + data.spec.emeraldmomy = -(data.spec.emeraldmomy/2); + data.spec.emeraldy = 74; + } + } + } + else + { + if (data.spec.emeraldy < (vid.height/vid.dupy)+16) + { + data.spec.emeraldy += (++data.spec.emeraldmomy); + } + if (data.spec.emeraldbounces < 1 && data.spec.emeraldy > 74) + { + S_StartSound(NULL, sfx_shldls); // nope + data.spec.emeraldbounces++; + data.spec.emeraldmomy = -(data.spec.emeraldmomy/2); + data.spec.emeraldy = 74; + } + } + } if (intertic < 2*TICRATE) // TWO second pause before tally begins, thank you mazmazz return; From 48b3ea31c43ac7c6191bf18ca043523f400f4404 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 20:14:53 -0400 Subject: [PATCH 061/137] Bring back shadows on polyobjects Also optimizes the method used so rings can show their shadows too. Using just the subsector is a tad bit imprecise admittedly but any more precise methods get really laggy. --- src/r_fps.c | 5 +++ src/r_fps.h | 1 + src/r_things.c | 89 ++++++++++++++++---------------------------------- 3 files changed, 34 insertions(+), 61 deletions(-) diff --git a/src/r_fps.c b/src/r_fps.c index cc518cc35..c4f69415c 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -256,6 +256,8 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); + out->subsector = R_PointInSubsector(out->x, out->y); + if (mobj->player) { out->angle = R_LerpAngle(mobj->player->old_drawangle, mobj->player->drawangle, frac); @@ -271,6 +273,9 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); + + out->subsector = R_PointInSubsector(out->x, out->y); + out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); } diff --git a/src/r_fps.h b/src/r_fps.h index 59d3df747..32c9131fe 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -53,6 +53,7 @@ typedef struct { fixed_t x; fixed_t y; fixed_t z; + subsector_t *subsector; angle_t angle; } interpmobjstate_t; diff --git a/src/r_things.c b/src/r_things.c index 0e1adf16a..716ef199a 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1158,8 +1158,8 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) } halfHeight = interp.z + (thing->height >> 1); - floorz = P_GetFloorZ(thing, thing->subsector->sector, interp.x, interp.y, NULL); - ceilingz = P_GetCeilingZ(thing, thing->subsector->sector, interp.x, interp.y, NULL); + floorz = P_GetFloorZ(thing, interp.subsector->sector, interp.x, interp.y, NULL); + ceilingz = P_GetCeilingZ(thing, interp.subsector->sector, interp.x, interp.y, NULL); #define CHECKZ (isflipped ? z > halfHeight && z < groundz : z < halfHeight && z > groundz) @@ -1195,6 +1195,32 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) } } + // Check polyobjects and see if groundz needs to be altered + { + // This isn't very precise, but the precise method was far too slow. + // (Polies are just naturally pretty flickery anyway :P) + polyobj_t *po = interp.subsector->polyList; + + while (po) + { + if (!(po->flags & POF_RENDERPLANES) || !P_MobjInsidePolyobj(po, thing)) + { + po = (polyobj_t *)(po->link.next); + continue; + } + + // We're inside it! Yess... + z = isflipped ? po->lines[0]->backsector->floorheight : po->lines[0]->backsector->ceilingheight; + if CHECKZ + { + groundz = z; + groundslope = NULL; + } + + po = (polyobj_t *)(po->link.next); + } + } + if (isflipped ? (ceilingz < groundz - (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2))) : (floorz > groundz + (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2)))) { @@ -1202,65 +1228,6 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope) groundslope = NULL; } -#if 0 // Unfortunately, this drops CEZ2 down to sub-17 FPS on my i7. - // NOTE: this section was not updated to reflect reverse gravity support - // Check polyobjects and see if groundz needs to be altered, for rings only because they don't update floorz - if (thing->type == MT_RING) - { - INT32 xl, xh, yl, yh, bx, by; - - xl = (unsigned)(interp.x - thing->radius - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(interp.x + thing->radius - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(interp.y - thing->radius - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(interp.y + thing->radius - bmaporgy)>>MAPBLOCKSHIFT; - - BMBOUNDFIX(xl, xh, yl, yh); - - validcount++; - - for (by = yl; by <= yh; by++) - for (bx = xl; bx <= xh; bx++) - { - INT32 offset; - polymaplink_t *plink; // haleyjd 02/22/06 - - if (bx < 0 || by < 0 || bx >= bmapwidth || by >= bmapheight) - continue; - - offset = by*bmapwidth + bx; - - // haleyjd 02/22/06: consider polyobject lines - plink = polyblocklinks[offset]; - - while (plink) - { - polyobj_t *po = plink->po; - - if (po->validcount != validcount) // if polyobj hasn't been checked - { - po->validcount = validcount; - - if (!P_MobjInsidePolyobj(po, thing) || !(po->flags & POF_RENDERPLANES)) - { - plink = (polymaplink_t *)(plink->link.next); - continue; - } - - // We're inside it! Yess... - z = po->lines[0]->backsector->ceilingheight; - - if (z < halfHeight && z > groundz) - { - groundz = z; - groundslope = NULL; - } - } - plink = (polymaplink_t *)(plink->link.next); - } - } - } -#endif - if (shadowslope != NULL) *shadowslope = groundslope; From fa12c51fcffb0d10b0156d017ebc3b88d2c70ed6 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 20:58:13 -0400 Subject: [PATCH 062/137] Fix a bunch of ticking in hu_ drawing functions --- src/hu_stuff.c | 83 +++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 5d893a551..69bc6910f 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -170,6 +170,8 @@ static INT32 cechoflags = 0; // HEADS UP INIT //====================================================================== +static tic_t resynch_ticker = 0; + #ifndef NONET // just after static void Command_Say_f(void); @@ -382,12 +384,12 @@ static INT16 addy = 0; // use this to make the messages scroll smoothly when one static void HU_removeChatText_Mini(void) { - // MPC: Don't create new arrays, just iterate through an existing one + // MPC: Don't create new arrays, just iterate through an existing one size_t i; - for(i=0;i 0) + chat_scrolltime--; + } + + if (netgame) + { + size_t i = 0; + + // handle spam while we're at it: + for(; (i 0) + stop_spamming[i]--; + } + + // handle chat timers + for (i=0; (i 0) + chat_timers[i]--; + else + HU_removeChatText_Mini(); + } + } + + --cechotimer; + + if (hu_redownloadinggamestate) + resynch_ticker++; } #ifndef NONET @@ -1854,8 +1889,6 @@ static void HU_DrawCEcho(void) echoptr = line; echoptr++; } - - --cechotimer; } static void HU_drawGametype(void) @@ -1917,9 +1950,6 @@ void HU_Drawer(void) // draw chat string plus cursor if (chat_on) { - // count down the scroll timer. - if (chat_scrolltime > 0) - chat_scrolltime--; if (!OLDCHAT) HU_DrawChat(); else @@ -1929,30 +1959,10 @@ void HU_Drawer(void) { typelines = 1; chat_scrolltime = 0; + if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden) HU_drawMiniChat(); // draw messages in a cool fashion. } - - if (netgame) // would handle that in hu_drawminichat, but it's actually kinda awkward when you're typing a lot of messages. (only handle that in netgames duh) - { - size_t i = 0; - - // handle spam while we're at it: - for(; (i 0) - stop_spamming[i]--; - } - - // handle chat timers - for (i=0; (i 0) - chat_timers[i]--; - else - HU_removeChatText_Mini(); - } - } #endif if (cechotimer) @@ -1992,12 +2002,9 @@ void HU_Drawer(void) // draw desynch text if (hu_redownloadinggamestate) { - static UINT32 resynch_ticker = 0; char resynch_text[14]; UINT32 i; - // Animate the dots - resynch_ticker++; strcpy(resynch_text, "Resynching"); for (i = 0; i < (resynch_ticker / 16) % 4; i++) strcat(resynch_text, "."); From 9276637db0867c7d44101e206161700d68ef88bd Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 25 Apr 2022 20:23:35 -0500 Subject: [PATCH 063/137] Revert "Reset overlays interp states each TryRunTics" This reverts commit a71a216faa20e8751b3bd0157354e8d748940c92. --- src/p_mobj.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 0f1353b7c..35dab0084 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -6901,8 +6901,6 @@ void P_RunOverlays(void) else P_SetThingPosition(mo); P_CheckPosition(mo, mo->x, mo->y); - - R_ResetMobjInterpolationState(mo); } P_SetTarget(&overlaycap, NULL); } From 400c6e08912273c9690706c80cfa9295f0756059 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 25 Apr 2022 21:37:41 -0400 Subject: [PATCH 064/137] Move intro ticking out of the drawer --- src/f_finale.c | 115 +++++++++++++++++++------------------------------ 1 file changed, 45 insertions(+), 70 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 2c45aecc9..01d06879a 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -515,9 +515,9 @@ void F_StartIntro(void) } // -// F_IntroDrawScene +// F_IntroDrawer // -static void F_IntroDrawScene(void) +void F_IntroDrawer(void) { boolean highres = true; INT32 cx = 8, cy = 128; @@ -623,24 +623,22 @@ static void F_IntroDrawScene(void) if (intro_curtime > 1 && intro_curtime < (INT32)introscenetime[intro_scenenum]) { V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + if (intro_curtime < TICRATE-5) // Make the text shine! + { sprintf(stjrintro, "STJRI%03u", intro_curtime-1); + } else if (intro_curtime >= TICRATE-6 && intro_curtime < 2*TICRATE-20) // Pause on black screen for just a second + { return; + } else if (intro_curtime == 2*TICRATE-19) { // Fade in the text // The text fade out is automatically handled when switching to a new intro scene strncpy(stjrintro, "STJRI029", 9); - S_ChangeMusicInternal("_stjr", false); - background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY); - wipestyleflags = WSF_FADEIN; - F_WipeStartScreen(); - F_TryColormapFade(31); V_DrawSmallScaledPatch(bgxoffs, 84, 0, background); - F_WipeEndScreen(); - F_RunWipe(0,true); } if (!WipeInAction) // Draw the patch if not in a wipe @@ -839,17 +837,27 @@ static void F_IntroDrawScene(void) V_DrawRightAlignedString(BASEVIDWIDTH-4, BASEVIDHEIGHT-12, V_ALLOWLOWERCASE|(trans< Date: Tue, 26 Apr 2022 10:28:42 -0500 Subject: [PATCH 065/137] Adjust 1up monitor icon z offsets Fixes interpolation issues with 1up monitors. --- src/info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/info.c b/src/info.c index 942934888..be136c2d2 100644 --- a/src/info.c +++ b/src/info.c @@ -770,9 +770,9 @@ state_t states[NUMSTATES] = // 1-Up box sprites (uses player sprite) {SPR_PLAY, SPR2_LIFE, 2, {NULL}, 0, 18, S_PLAY_BOX2}, // S_PLAY_BOX1 - {SPR_NULL, 0, 1, {NULL}, 0, 0, S_PLAY_BOX1}, // S_PLAY_BOX2 + {SPR_NULL, 0, 1, {NULL}, 0, 18, S_PLAY_BOX1}, // S_PLAY_BOX2 {SPR_PLAY, SPR2_LIFE, 4, {NULL}, 0, 4, S_PLAY_ICON2}, // S_PLAY_ICON1 - {SPR_NULL, 0, 12, {NULL}, 0, 0, S_PLAY_ICON3}, // S_PLAY_ICON2 + {SPR_NULL, 0, 12, {NULL}, 0, 4, S_PLAY_ICON3}, // S_PLAY_ICON2 {SPR_PLAY, SPR2_LIFE, 20, {NULL}, 0, 4, S_NULL}, // S_PLAY_ICON3 // Level end sign (uses player sprite) From 4095ef599b4f12098c587fdc4ef8b59c4a00d682 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 26 Apr 2022 11:04:48 -0500 Subject: [PATCH 066/137] Delta time choose player menu animations --- src/m_menu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 0ed7e6882..1b3943f8b 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -175,7 +175,7 @@ static INT32 vidm_column_size; static fixed_t recatkdrawtimer = 0; static fixed_t ntsatkdrawtimer = 0; -static tic_t charseltimer = 0; +static fixed_t charseltimer = 0; static fixed_t char_scroll = 0; #define charscrollamt 128*FRACUNIT @@ -9354,8 +9354,8 @@ static void M_DrawSetupChoosePlayerMenu(void) INT32 x, y; INT32 w = (vid.width/vid.dupx); - if (abs(char_scroll) > FRACUNIT) - char_scroll -= (char_scroll>>2); + if (abs(char_scroll) > FRACUNIT/4) + char_scroll -= FixedMul((char_scroll>>2), renderdeltatics); else // close enough. char_scroll = 0; // just be exact now. @@ -9383,7 +9383,7 @@ static void M_DrawSetupChoosePlayerMenu(void) // Don't render the title map hidetitlemap = true; - charseltimer++; + charseltimer += renderdeltatics; // Background and borders V_DrawFill(0, 0, bgwidth, vid.height, V_SNAPTOTOP|colormap[101]); @@ -9395,7 +9395,7 @@ static void M_DrawSetupChoosePlayerMenu(void) V_DrawFill(0, 0, bw, vid.height, V_NOSCALESTART|col); } - y = (charseltimer%32); + y = (charseltimer / FRACUNIT) % 32; V_DrawMappedPatch(0, y-bgheight, V_SNAPTOTOP, charbg, colormap); V_DrawMappedPatch(0, y, V_SNAPTOTOP, charbg, colormap); V_DrawMappedPatch(0, y+bgheight, V_SNAPTOTOP, charbg, colormap); From f418c6476f76d0b55adb8b7e71f95b2a4f2f7deb Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 26 Apr 2022 13:47:35 -0500 Subject: [PATCH 067/137] Add drawerlib deltaTime function --- src/lua_hudlib.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index c7f2bbc28..cffb0b64f 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1201,6 +1201,14 @@ static int libd_getusertransflag(lua_State *L) return 1; } +// Return the time elapsed for the previous frame, in tics. +static int libd_deltaTime(lua_State *L) +{ + HUDONLY + lua_pushfixed(L, renderdeltatics); + return 1; +} + static luaL_Reg lib_draw[] = { // cache {"patchExists", libd_patchExists}, @@ -1242,6 +1250,7 @@ static luaL_Reg lib_draw[] = { {"renderer", libd_renderer}, {"localTransFlag", libd_getlocaltransflag}, {"userTransFlag", libd_getusertransflag}, + {"deltaTime", libd_deltaTime}, {NULL, NULL} }; From c79df7d58e7cb4785e529316e0fc10a0a7fd85bd Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 26 Apr 2022 15:40:13 -0500 Subject: [PATCH 068/137] Interpolate afterimages further back --- src/d_player.h | 1 + src/p_mobj.h | 4 ++++ src/p_user.c | 8 ++++++++ src/r_fps.c | 13 +++++++++++++ 4 files changed, 26 insertions(+) diff --git a/src/d_player.h b/src/d_player.h index 0111083d0..d27627744 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -383,6 +383,7 @@ typedef struct player_s // fun thing for player sprite angle_t drawangle; angle_t old_drawangle; + angle_t old_drawangle2; // player's ring count INT16 rings; diff --git a/src/p_mobj.h b/src/p_mobj.h index e4c57beec..7e3c30dcd 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -280,6 +280,7 @@ typedef struct mobj_s // Info for drawing: position. fixed_t x, y, z; fixed_t old_x, old_y, old_z; // position interpolation + fixed_t old_x2, old_y2, old_z2; // More list: links in sector (if needed) struct mobj_s *snext; @@ -288,6 +289,7 @@ typedef struct mobj_s // More drawing info: to determine current sprite. angle_t angle, pitch, roll; // orientation angle_t old_angle, old_pitch, old_roll; // orientation interpolation + angle_t old_angle2, old_pitch2, old_roll2; angle_t rollangle; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h @@ -409,6 +411,7 @@ typedef struct precipmobj_s // Info for drawing: position. fixed_t x, y, z; fixed_t old_x, old_y, old_z; // position interpolation + fixed_t old_x2, old_y2, old_z2; // More list: links in sector (if needed) struct precipmobj_s *snext; @@ -417,6 +420,7 @@ typedef struct precipmobj_s // More drawing info: to determine current sprite. angle_t angle, pitch, roll; // orientation angle_t old_angle, old_pitch, old_roll; // orientation interpolation + angle_t old_angle2, old_pitch2, old_roll2; angle_t rollangle; spritenum_t sprite; // used to find patch_t and flip value UINT32 frame; // frame number, plus bits see p_pspr.h diff --git a/src/p_user.c b/src/p_user.c index a3e98f516..feebafa82 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2084,6 +2084,14 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost2->flags2 |= (mobj->player->followmobj->flags2 & MF2_LINKDRAW); } + // Copy interpolation data :) + ghost->old_x = mobj->old_x2; + ghost->old_y = mobj->old_y2; + ghost->old_z = mobj->old_z2; + ghost->old_angle = (mobj->player ? mobj->player->old_drawangle2 : mobj->old_angle2); + ghost->old_pitch = mobj->old_pitch2; + ghost->old_roll = mobj->old_roll2; + return ghost; } diff --git a/src/r_fps.c b/src/r_fps.c index c4f69415c..1bc92c622 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -687,6 +687,12 @@ void R_UpdateMobjInterpolators(void) // void R_ResetMobjInterpolationState(mobj_t *mobj) { + mobj->old_x2 = mobj->old_x; + mobj->old_y2 = mobj->old_y; + mobj->old_z2 = mobj->old_z; + mobj->old_angle2 = mobj->old_angle; + mobj->old_pitch2 = mobj->old_pitch; + mobj->old_roll2 = mobj->old_roll; mobj->old_x = mobj->x; mobj->old_y = mobj->y; mobj->old_z = mobj->z; @@ -696,6 +702,7 @@ void R_ResetMobjInterpolationState(mobj_t *mobj) if (mobj->player) { + mobj->player->old_drawangle2 = mobj->player->old_drawangle; mobj->player->old_drawangle = mobj->player->drawangle; } } @@ -707,6 +714,12 @@ void R_ResetMobjInterpolationState(mobj_t *mobj) // void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj) { + mobj->old_x2 = mobj->old_x; + mobj->old_y2 = mobj->old_y; + mobj->old_z2 = mobj->old_z; + mobj->old_angle2 = mobj->old_angle; + mobj->old_pitch2 = mobj->old_pitch; + mobj->old_roll2 = mobj->old_roll; mobj->old_x = mobj->x; mobj->old_y = mobj->y; mobj->old_z = mobj->z; From a4ea2c27083c5a93ce7f7ca3cc2bf5d225573759 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 26 Apr 2022 16:07:48 -0500 Subject: [PATCH 069/137] Use old sleep in dedicated mode --- src/d_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 9cfd694e7..6aeaf61e5 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -778,7 +778,7 @@ void D_SRB2Loop(void) debugload--; #endif - interp = R_UsingFrameInterpolation(); + interp = R_UsingFrameInterpolation() && !dedicated; doDisplay = screenUpdate = false; ticked = false; @@ -891,10 +891,15 @@ void D_SRB2Loop(void) // Fully completed frame made. frameEnd = I_GetFrameTime(); - if (!singletics) + if (!singletics && !dedicated) { I_FrameCapSleep(frameEnd); } + else if (dedicated) + { + // Preserve the pre-interp sleeping behavior for dedicated mode + I_Sleep(); + } // I_FinishUpdate is now here instead of D_Display, // because it synchronizes it more closely with the frame counter. From aec527cb4c8194d0cee132e7312c9fc50b7dc6df Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 26 Apr 2022 18:26:42 -0500 Subject: [PATCH 070/137] Clamp cechotimer to 0 Fixes issues with cechos staying on-screen and glitching out (NiGHTS items for example). --- src/hu_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 69bc6910f..518f28b50 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -905,7 +905,7 @@ void HU_Ticker(void) } } - --cechotimer; + if (cechotimer > 0) --cechotimer; if (hu_redownloadinggamestate) resynch_ticker++; From 833777d7738f68b451443f954232be63e969225a Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 26 Apr 2022 19:28:51 -0500 Subject: [PATCH 071/137] Revert "Remove unnecessary precipmobj thinker hack" This reverts commit 0e38208620d19ec2ab690740438ac2fc7862a49e. --- src/hardware/hw_main.c | 10 ++++++++++ src/p_mobj.c | 7 ++++--- src/p_mobj.h | 2 ++ src/r_things.c | 13 ++++++++++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 827cef657..747d3402b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5614,6 +5614,16 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height); vis->precip = true; + + // okay... this is a hack, but weather isn't networked, so it should be ok + if (!(thing->precipflags & PCF_THUNK)) + { + if (thing->precipflags & PCF_RAIN) + P_RainThinker(thing); + else + P_SnowThinker(thing); + thing->precipflags |= PCF_THUNK; + } } #endif diff --git a/src/p_mobj.c b/src/p_mobj.c index 35dab0084..b5c83468a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4022,7 +4022,8 @@ void P_RecalcPrecipInSector(sector_t *sector) // void P_NullPrecipThinker(precipmobj_t *mobj) { - (void)mobj; + //(void)mobj; + mobj->precipflags &= ~PCF_THUNK; } void P_SnowThinker(precipmobj_t *mobj) @@ -10963,14 +10964,14 @@ static inline precipmobj_t *P_SpawnRainMobj(fixed_t x, fixed_t y, fixed_t z, mob { precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); mo->precipflags |= PCF_RAIN; - mo->thinker.function.acp1 = (actionf_p1)P_RainThinker; + //mo->thinker.function.acp1 = (actionf_p1)P_RainThinker; return mo; } static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) { precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type); - mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker; + //mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker; return mo; } diff --git a/src/p_mobj.h b/src/p_mobj.h index 7e3c30dcd..498eeb8a6 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -269,6 +269,8 @@ typedef enum { PCF_MOVINGFOF = 8, // Is rain. PCF_RAIN = 16, + // Ran the thinker this tic. + PCF_THUNK = 32, } precipflag_t; // Map Object definition. diff --git a/src/r_things.c b/src/r_things.c index 716ef199a..9d2f9f4df 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2264,7 +2264,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) if (thing->subsector->sector->cullheight) { if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt)) - return; + goto weatherthink; } // store information in a vissprite @@ -2318,6 +2318,17 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) // Fullbright vis->colormap = colormaps; + +weatherthink: + // okay... this is a hack, but weather isn't networked, so it should be ok + if (!(thing->precipflags & PCF_THUNK)) + { + if (thing->precipflags & PCF_RAIN) + P_RainThinker(thing); + else + P_SnowThinker(thing); + thing->precipflags |= PCF_THUNK; + } } // R_AddSprites From 9b4e485686bdd679ad7d1bf578ba87cac01c8e1a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 17:02:35 -0400 Subject: [PATCH 072/137] Fix frame pacing when game lags behind The frame timestamp should've been made at the start of the frame, not the end. --- src/d_main.c | 3 ++- src/sdl/i_system.c | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 6aeaf61e5..eb01edd9d 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -755,6 +755,8 @@ void D_SRB2Loop(void) for (;;) { + frameEnd = I_GetFrameTime(); + if (lastwipetic) { oldentertics = lastwipetic; @@ -890,7 +892,6 @@ void D_SRB2Loop(void) LUA_Step(); // Fully completed frame made. - frameEnd = I_GetFrameTime(); if (!singletics && !dedicated) { I_FrameCapSleep(frameEnd); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 2e1bf0c17..05386e9b5 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2157,8 +2157,14 @@ static void UpdateElapsedTics(void) tic_t I_GetTime(void) { + float f = 0.0f; + UpdateElapsedTics(); - return (tic_t) floor(elapsed_tics); + + // This needs kept in a separate variable before converting + // to tic_t, due to stupid -Wbad-function-cast error. + f = floor(elapsed_tics); + return (tic_t)f; } float I_GetTimeFrac(void) From c3340959dedb7b8386a358705f0cb0bc473b494f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 17:22:39 -0400 Subject: [PATCH 073/137] Fix I_FrameCapSleep not respecting cpusleep Jonathan Joestar bruh --- src/sdl/i_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 05386e9b5..db1f099cd 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2306,7 +2306,7 @@ boolean I_FrameCapSleep(const double t) while (curTime < destTime) { - if (curTime < sleepTime && cv_sleep.value <= 0) + if (curTime < sleepTime && cv_sleep.value > 0) { // Wait 1ms at a time (on default settings) // until we're close enough. From eb6b1f375a47232c617ec4b94e696f076a495729 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 17:31:52 -0400 Subject: [PATCH 074/137] Allow dedicated to use precise sleep timing again Instead of only using one old sleep, just enforce framerate cap to match TICRATE. --- src/d_main.c | 7 +------ src/r_fps.c | 7 +++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index eb01edd9d..6912ec988 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -892,15 +892,10 @@ void D_SRB2Loop(void) LUA_Step(); // Fully completed frame made. - if (!singletics && !dedicated) + if (!singletics) { I_FrameCapSleep(frameEnd); } - else if (dedicated) - { - // Preserve the pre-interp sleeping behavior for dedicated mode - I_Sleep(); - } // I_FinishUpdate is now here instead of D_Display, // because it synchronizes it more closely with the frame counter. diff --git a/src/r_fps.c b/src/r_fps.c index 1bc92c622..45f301551 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -42,6 +42,13 @@ consvar_t cv_fpscap = CVAR_INIT ("fpscap", "Match refresh rate", CV_SAVE, fpscap UINT32 R_GetFramerateCap(void) { + if (rendermode == render_none) + { + // If we're not rendering (dedicated server), + // we shouldn't be using any interpolation. + return TICRATE; + } + if (cv_fpscap.value == 0) { // 0: Match refresh rate From c3923adc3f5cd52bdc33114acf4b7837c3fa70c6 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 27 Apr 2022 17:08:40 -0500 Subject: [PATCH 075/137] Make Lua TeleportMove call MoveOrigin --- src/lua_baselib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lua_baselib.c b/src/lua_baselib.c index fc4e321ed..d06badc12 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1783,8 +1783,8 @@ static int lib_pTeleportMove(lua_State *L) INLEVEL if (!thing) return LUA_ErrInvalid(L, "mobj_t"); - LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin or P_MoveOrigin"); - lua_pushboolean(L, P_SetOrigin(thing, x, y, z)); + LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin\" or \"P_MoveOrigin"); + lua_pushboolean(L, P_MoveOrigin(thing, x, y, z)); LUA_PushUserdata(L, tmthing, META_MOBJ); P_SetTarget(&tmthing, ptmthing); return 2; From 0503c853ccdcf59345b2d86da848122b6196a123 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 27 Apr 2022 18:19:00 -0500 Subject: [PATCH 076/137] Reset Metal fume interp state on appear --- src/p_user.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/p_user.c b/src/p_user.c index feebafa82..b715babf5 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -20,6 +20,7 @@ #include "d_net.h" #include "g_game.h" #include "p_local.h" +#include "r_fps.h" #include "r_main.h" #include "s_sound.h" #include "r_skins.h" @@ -11344,6 +11345,7 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) tic_t dashmode = min(player->dashmode, DASHMODE_MAX); boolean underwater = mo->eflags & MFE_UNDERWATER; statenum_t stat = fume->state-states; + boolean resetinterp = false; if (panim != PA_WALK && panim != PA_RUN && panim != PA_DASH) // turn invisible when not in a coherent movement state { @@ -11395,6 +11397,7 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) { P_SetMobjState(fume, (stat = fume->info->seestate)); P_SetScale(fume, mo->scale); + resetinterp = true; } if (dashmode > DASHMODE_THRESHOLD && stat != fume->info->seestate) // If in dashmode, grow really big and flash @@ -11438,6 +11441,7 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume) fume->y = mo->y + P_ReturnThrustY(fume, angle, dist); fume->z = mo->z + heightoffset - (fume->height >> 1); P_SetThingPosition(fume); + if (resetinterp) R_ResetMobjInterpolationState(fume); // If dashmode is high enough, spawn a trail if (player->normalspeed >= skins[player->skin].normalspeed*2) From c83d1be21ffd31d127b9559570462a742ecb9498 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 29 Mar 2022 20:51:58 -0400 Subject: [PATCH 077/137] Add interpdebug --- src/d_main.c | 13 ++++--------- src/r_fps.c | 2 ++ src/r_fps.h | 1 + src/r_main.c | 1 + src/st_stuff.c | 22 ++++++++++++++++++++++ src/st_stuff.h | 2 ++ 6 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 6912ec988..7a8ae5f0f 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -841,17 +841,12 @@ void D_SRB2Loop(void) tictime = entertime; } + dbg_entertime = entertime; + dbg_prevtime = prevtime; + dbg_tictime = tictime; + if (!(paused || P_AutoPause())) { -#if 0 - CONS_Printf("prevtime = %f\n", prevtime); - CONS_Printf("entertime = %f\n", entertime); - CONS_Printf("tictime = %f\n", tictime); - CONS_Printf("entertime - prevtime = %f\n", entertime - prevtime); - CONS_Printf("entertime - tictime = %f\n", entertime - tictime); - CONS_Printf("========\n"); -#endif - if (entertime - prevtime >= 1.0f) { // Lagged for more frames than a gametic... diff --git a/src/r_fps.c b/src/r_fps.c index 45f301551..6307d83a1 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -40,6 +40,8 @@ static CV_PossibleValue_t fpscap_cons_t[] = { }; consvar_t cv_fpscap = CVAR_INIT ("fpscap", "Match refresh rate", CV_SAVE, fpscap_cons_t, NULL); +consvar_t cv_interpdebug = CVAR_INIT ("interpdebug", "Off", 0, CV_OnOff, NULL); + UINT32 R_GetFramerateCap(void) { if (rendermode == render_none) diff --git a/src/r_fps.h b/src/r_fps.h index 32c9131fe..4a0750c3a 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -20,6 +20,7 @@ #include "r_state.h" extern consvar_t cv_fpscap; +extern consvar_t cv_interpdebug; UINT32 R_GetFramerateCap(void); boolean R_UsingFrameInterpolation(void); diff --git a/src/r_main.c b/src/r_main.c index 896b6a29b..a3bddf44f 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1625,4 +1625,5 @@ void R_RegisterEngineStuff(void) // Frame interpolation/uncapped CV_RegisterVar(&cv_fpscap); + CV_RegisterVar(&cv_interpdebug); } diff --git a/src/st_stuff.c b/src/st_stuff.c index 6c9a0eeca..535c68ee8 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -45,6 +45,8 @@ #include "lua_hud.h" #include "lua_hook.h" +#include "r_fps.h" + UINT16 objectsdrawn = 0; // @@ -621,6 +623,24 @@ static void ST_drawDebugInfo(void) #undef VFLAGS } +float dbg_entertime = 0.0f, dbg_prevtime = 0.0f, dbg_tictime = 0.0f; +static void ST_DrawInterpDebug(void) +{ + // TODO: when the devmode situation stops sucking eggs, + // remove cv_interpdebug and use DBG_RENDER instead. + if (!cv_interpdebug.value || !R_UsingFrameInterpolation()) + { + return; + } + + V_DrawRightAlignedString(312, 8, V_MONOSPACE, va("enter - tic: %.3f", dbg_entertime - dbg_tictime)); + V_DrawRightAlignedString(312, 16, V_MONOSPACE, va("enter - prev: %.3f", dbg_entertime - dbg_prevtime)); + + V_DrawRightAlignedString(312, 24, V_MONOSPACE, va("tic: %.3f", dbg_tictime)); + V_DrawRightAlignedString(312, 32, V_MONOSPACE, va("prev: %.3f", dbg_prevtime)); + V_DrawRightAlignedString(312, 40, V_MONOSPACE, va("enter: %.3f", dbg_entertime)); +} + static void ST_drawScore(void) { if (F_GetPromptHideHud(hudinfo[HUD_SCORE].y)) @@ -2755,6 +2775,8 @@ static void ST_overlayDrawer(void) ST_drawInput(); ST_drawDebugInfo(); + + ST_DrawInterpDebug(); } void ST_Drawer(void) diff --git a/src/st_stuff.h b/src/st_stuff.h index c59bc2ac6..0956bbb7d 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -55,6 +55,8 @@ void ST_preDrawTitleCard(void); void ST_preLevelTitleCardDrawer(void); void ST_drawWipeTitleCard(void); +extern float dbg_entertime, dbg_prevtime, dbg_tictime; + extern tic_t lt_ticker, lt_lasttic; extern tic_t lt_exitticker, lt_endtime; From f2a19b29d98807ebf8557341ffe3c064ae568753 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 18:59:54 -0400 Subject: [PATCH 078/137] Put interpdebug stuff in perfstats instead --- src/d_main.c | 7 ++++--- src/m_perfstats.c | 20 ++++++++++++++++++-- src/r_fps.c | 4 +++- src/r_fps.h | 5 ++++- src/r_main.c | 1 - src/st_stuff.c | 20 -------------------- src/st_stuff.h | 2 -- 7 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 7a8ae5f0f..850da2f1a 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -841,9 +841,10 @@ void D_SRB2Loop(void) tictime = entertime; } - dbg_entertime = entertime; - dbg_prevtime = prevtime; - dbg_tictime = tictime; + // I looked at the possibility of putting in a float drawer for + // perfstats and it's very complicated, so we'll just do this instead... + ps_interp_frac.value.p = (precise_t)((entertime - tictime) * 1000.0f); + ps_interp_lag.value.p = (precise_t)((entertime - prevtime) * 1000.0f); if (!(paused || P_AutoPause())) { diff --git a/src/m_perfstats.c b/src/m_perfstats.c index 9fc41000d..f58959f1d 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -17,6 +17,7 @@ #include "i_system.h" #include "z_zone.h" #include "p_local.h" +#include "r_fps.h" #ifdef HWRENDER #include "hardware/hw_main.h" @@ -122,6 +123,12 @@ perfstatrow_t commoncounter_rows[] = { {0} }; +perfstatrow_t interpolation_rows[] = { + {"intpfrc", "Interp frac: ", &ps_interp_frac, PS_TIME}, + {"intplag", "Interp lag: ", &ps_interp_lag, PS_TIME}, + {0} +}; + #ifdef HWRENDER perfstatrow_t batchcount_rows[] = { {"polygon", "Polygons: ", &ps_hw_numpolys, 0}, @@ -473,6 +480,9 @@ static void PS_UpdateFrameStats(void) if (PS_IsLevelActive()) PS_UpdateRowHistories(commoncounter_rows, true); + if (R_UsingFrameInterpolation()) + PS_UpdateRowHistories(interpolation_rows, true); + #ifdef HWRENDER if (rendermode == render_opengl && cv_glbatching.value) { @@ -634,7 +644,7 @@ static void PS_DrawRenderStats(void) { const boolean hires = PS_HighResolution(); const int half_row = hires ? 5 : 4; - int x, y; + int x, y, cy = 10; PS_DrawDescriptorHeader(); @@ -645,7 +655,7 @@ static void PS_DrawRenderStats(void) if (PS_IsLevelActive()) { x = hires ? 115 : 90; - PS_DrawPerfRows(x, 10, V_BLUEMAP, commoncounter_rows); + cy = PS_DrawPerfRows(x, 10, V_BLUEMAP, commoncounter_rows) + half_row; #ifdef HWRENDER if (rendermode == render_opengl && cv_glbatching.value) @@ -659,6 +669,12 @@ static void PS_DrawRenderStats(void) } #endif } + + if (R_UsingFrameInterpolation()) + { + x = hires ? 115 : 90; + PS_DrawPerfRows(x, cy, V_ROSYMAP, interpolation_rows); + } } static void PS_DrawGameLogicStats(void) diff --git a/src/r_fps.c b/src/r_fps.c index 6307d83a1..b4b11a43a 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -22,6 +22,7 @@ #include "r_state.h" #include "z_zone.h" #include "console.h" // con_startup_loadprogress +#include "m_perfstats.h" // ps_metric_t #ifdef HWRENDER #include "hardware/hw_main.h" // for cv_glshearing #endif @@ -40,7 +41,8 @@ static CV_PossibleValue_t fpscap_cons_t[] = { }; consvar_t cv_fpscap = CVAR_INIT ("fpscap", "Match refresh rate", CV_SAVE, fpscap_cons_t, NULL); -consvar_t cv_interpdebug = CVAR_INIT ("interpdebug", "Off", 0, CV_OnOff, NULL); +ps_metric_t ps_interp_frac = {0}; +ps_metric_t ps_interp_lag = {0}; UINT32 R_GetFramerateCap(void) { diff --git a/src/r_fps.h b/src/r_fps.h index 4a0750c3a..cf66d72f9 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -18,9 +18,12 @@ #include "m_fixed.h" #include "p_local.h" #include "r_state.h" +#include "m_perfstats.h" // ps_metric_t extern consvar_t cv_fpscap; -extern consvar_t cv_interpdebug; + +extern ps_metric_t ps_interp_frac; +extern ps_metric_t ps_interp_lag; UINT32 R_GetFramerateCap(void); boolean R_UsingFrameInterpolation(void); diff --git a/src/r_main.c b/src/r_main.c index a3bddf44f..896b6a29b 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1625,5 +1625,4 @@ void R_RegisterEngineStuff(void) // Frame interpolation/uncapped CV_RegisterVar(&cv_fpscap); - CV_RegisterVar(&cv_interpdebug); } diff --git a/src/st_stuff.c b/src/st_stuff.c index 535c68ee8..6ab310252 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -623,24 +623,6 @@ static void ST_drawDebugInfo(void) #undef VFLAGS } -float dbg_entertime = 0.0f, dbg_prevtime = 0.0f, dbg_tictime = 0.0f; -static void ST_DrawInterpDebug(void) -{ - // TODO: when the devmode situation stops sucking eggs, - // remove cv_interpdebug and use DBG_RENDER instead. - if (!cv_interpdebug.value || !R_UsingFrameInterpolation()) - { - return; - } - - V_DrawRightAlignedString(312, 8, V_MONOSPACE, va("enter - tic: %.3f", dbg_entertime - dbg_tictime)); - V_DrawRightAlignedString(312, 16, V_MONOSPACE, va("enter - prev: %.3f", dbg_entertime - dbg_prevtime)); - - V_DrawRightAlignedString(312, 24, V_MONOSPACE, va("tic: %.3f", dbg_tictime)); - V_DrawRightAlignedString(312, 32, V_MONOSPACE, va("prev: %.3f", dbg_prevtime)); - V_DrawRightAlignedString(312, 40, V_MONOSPACE, va("enter: %.3f", dbg_entertime)); -} - static void ST_drawScore(void) { if (F_GetPromptHideHud(hudinfo[HUD_SCORE].y)) @@ -2775,8 +2757,6 @@ static void ST_overlayDrawer(void) ST_drawInput(); ST_drawDebugInfo(); - - ST_DrawInterpDebug(); } void ST_Drawer(void) diff --git a/src/st_stuff.h b/src/st_stuff.h index 0956bbb7d..c59bc2ac6 100644 --- a/src/st_stuff.h +++ b/src/st_stuff.h @@ -55,8 +55,6 @@ void ST_preDrawTitleCard(void); void ST_preLevelTitleCardDrawer(void); void ST_drawWipeTitleCard(void); -extern float dbg_entertime, dbg_prevtime, dbg_tictime; - extern tic_t lt_ticker, lt_lasttic; extern tic_t lt_exitticker, lt_endtime; From bb6d4d10b584c92082d6c95e0b0626542a25a2d3 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 29 Mar 2022 21:58:14 -0400 Subject: [PATCH 079/137] Add timescale cvar Slow the game down to debug animations / interpolation problems! Speed it up if you need to get somewhere quickly while mapping! --- src/screen.h | 3 +++ src/sdl/i_system.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/screen.h b/src/screen.h index bfb9e7fbf..8a8bda376 100644 --- a/src/screen.h +++ b/src/screen.h @@ -194,6 +194,9 @@ extern UINT8 *scr_borderpatch; // patch used to fill the view borders extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_renderer, cv_fullscreen; // wait for page flipping to end or not extern consvar_t cv_vidwait; +#ifdef DEVELOP +extern consvar_t cv_timescale; +#endif // Initialize the screen void SCR_Startup(void); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index db1f099cd..8d04a8783 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2147,6 +2147,16 @@ static double tic_frequency; static Uint64 tic_epoch; static double elapsed_tics; +#ifdef DEVELOP // Tied behind DEVELOP, until sv_cheats is made better +static void UpdateTicFreq(void) +{ + tic_frequency = (timer_frequency / (double)NEWTICRATE) / FIXED_TO_FLOAT(cv_timescale.value); +} + +static CV_PossibleValue_t timescale_cons_t[] = {{FRACUNIT/20, "MIN"}, {20*FRACUNIT, "MAX"}, {0, NULL}}; +consvar_t cv_timescale = CVAR_INIT ("timescale", "1.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_CALL, timescale_cons_t, UpdateTicFreq); +#endif + static void UpdateElapsedTics(void) { const Uint64 now = SDL_GetPerformanceCounter(); @@ -2251,6 +2261,10 @@ double I_GetFrameTime(void) // void I_StartupTimer(void) { +#ifdef DEVELOP + CV_RegisterVar(&cv_timescale); +#endif + timer_frequency = SDL_GetPerformanceFrequency(); tic_epoch = SDL_GetPerformanceCounter(); From a76968c6d9ba69d702121d0fcad46fac12d992e9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 19:18:17 -0400 Subject: [PATCH 080/137] Enable timescale outside of DEVELOP builds It has NETVAR, so it should be fine -- put an end to useful debugging features excluded in multiplayer! --- src/screen.h | 2 -- src/sdl/i_system.c | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/screen.h b/src/screen.h index 8a8bda376..da27aa8f0 100644 --- a/src/screen.h +++ b/src/screen.h @@ -194,9 +194,7 @@ extern UINT8 *scr_borderpatch; // patch used to fill the view borders extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_renderer, cv_fullscreen; // wait for page flipping to end or not extern consvar_t cv_vidwait; -#ifdef DEVELOP extern consvar_t cv_timescale; -#endif // Initialize the screen void SCR_Startup(void); diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 8d04a8783..afd13910c 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2147,15 +2147,13 @@ static double tic_frequency; static Uint64 tic_epoch; static double elapsed_tics; -#ifdef DEVELOP // Tied behind DEVELOP, until sv_cheats is made better static void UpdateTicFreq(void) { - tic_frequency = (timer_frequency / (double)NEWTICRATE) / FIXED_TO_FLOAT(cv_timescale.value); + tic_frequency = (timer_frequency / (double)NEWTICRATE) / FixedToFloat(cv_timescale.value); } static CV_PossibleValue_t timescale_cons_t[] = {{FRACUNIT/20, "MIN"}, {20*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_timescale = CVAR_INIT ("timescale", "1.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_CALL, timescale_cons_t, UpdateTicFreq); -#endif static void UpdateElapsedTics(void) { @@ -2261,9 +2259,7 @@ double I_GetFrameTime(void) // void I_StartupTimer(void) { -#ifdef DEVELOP CV_RegisterVar(&cv_timescale); -#endif timer_frequency = SDL_GetPerformanceFrequency(); tic_epoch = SDL_GetPerformanceCounter(); From f66cedf1fc3c8ab2155e97cdd47c19f2b2c7b9c8 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 19:27:32 -0400 Subject: [PATCH 081/137] Force interpolation when timescale != 1.0 --- src/r_fps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_fps.c b/src/r_fps.c index b4b11a43a..d3a996207 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -70,7 +70,7 @@ UINT32 R_GetFramerateCap(void) boolean R_UsingFrameInterpolation(void) { - return (R_GetFramerateCap() != TICRATE); // maybe use ">" instead? + return (R_GetFramerateCap() != TICRATE || cv_timescale.value < FRACUNIT); } static viewvars_t p1view_old; From 813ed81a37dda29e3d959a73cce1fd3568218814 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 27 Apr 2022 19:52:11 -0500 Subject: [PATCH 082/137] Reset old_z in MT_LOCKON think Fixes interpolation artifacting due to spawn pos. --- src/p_mobj.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index b5c83468a..88c269b26 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7800,6 +7800,9 @@ static void P_MobjSceneryThink(mobj_t *mobj) mobj->z = mobj->target->z + mobj->target->height + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale); else mobj->z = mobj->target->z - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale) - mobj->height; + + mobj->old_z = mobj->z; + break; case MT_LOCKONINF: if (!(mobj->flags2 & MF2_STRONGBOX)) @@ -7811,6 +7814,9 @@ static void P_MobjSceneryThink(mobj_t *mobj) mobj->z = mobj->threshold + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->scale); else mobj->z = mobj->threshold - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->scale); + + mobj->old_z = mobj->z; + break; case MT_DROWNNUMBERS: if (!P_DrownNumbersSceneryThink(mobj)) From 71ee468bf3d9ec98b35234d3b91eef3dfeb40c00 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 21:39:27 -0400 Subject: [PATCH 083/137] Fix cutscenes in interp --- src/f_finale.c | 51 +++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/f_finale.c b/src/f_finale.c index 01d06879a..832c0ecb3 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -3834,11 +3834,27 @@ boolean F_ContinueResponder(event_t *event) static INT32 scenenum, cutnum; static INT32 picxpos, picypos, picnum, pictime, picmode, numpics, pictoloop; static INT32 textxpos, textypos; -static boolean dofadenow = false, cutsceneover = false; +static boolean cutsceneover = false; static boolean runningprecutscene = false, precutresetplayer = false; static void F_AdvanceToNextScene(void) { + if (rendermode != render_none) + { + F_WipeStartScreen(); + + // Fade to any palette color you want. + if (cutscenes[cutnum]->scene[scenenum].fadecolor) + { + V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,cutscenes[cutnum]->scene[scenenum].fadecolor); + + F_WipeEndScreen(); + F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true); + + F_WipeStartScreen(); + } + } + // Don't increment until after endcutscene check // (possible overflow / bad patch names from the one tic drawn before the fade) if (scenenum+1 >= cutscenes[cutnum]->numscenes) @@ -3846,6 +3862,7 @@ static void F_AdvanceToNextScene(void) F_EndCutScene(); return; } + ++scenenum; timetonext = 0; @@ -3861,7 +3878,6 @@ static void F_AdvanceToNextScene(void) cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0); // Fade to the next - dofadenow = true; F_NewCutscene(cutscenes[cutnum]->scene[scenenum].text); picnum = 0; @@ -3871,6 +3887,14 @@ static void F_AdvanceToNextScene(void) textypos = cutscenes[cutnum]->scene[scenenum].textypos; animtimer = pictime = cutscenes[cutnum]->scene[scenenum].picduration[picnum]; + + if (rendermode != render_none) + { + F_CutsceneDrawer(); + + F_WipeEndScreen(); + F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true); + } } // See also G_AfterIntermission, the only other place which handles intra-map/ending transitions @@ -3945,21 +3969,6 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset // void F_CutsceneDrawer(void) { - if (dofadenow && rendermode != render_none) - { - F_WipeStartScreen(); - - // Fade to any palette color you want. - if (cutscenes[cutnum]->scene[scenenum].fadecolor) - { - V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,cutscenes[cutnum]->scene[scenenum].fadecolor); - - F_WipeEndScreen(); - F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true); - - F_WipeStartScreen(); - } - } V_DrawFill(0,0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); if (cutscenes[cutnum]->scene[scenenum].picname[picnum][0] != '\0') @@ -3972,12 +3981,6 @@ void F_CutsceneDrawer(void) W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY)); } - if (dofadenow && rendermode != render_none) - { - F_WipeEndScreen(); - F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true); - } - V_DrawString(textxpos, textypos, V_ALLOWLOWERCASE, cutscene_disptext); } @@ -3994,8 +3997,6 @@ void F_CutsceneTicker(void) finalecount++; cutscene_boostspeed = 0; - dofadenow = false; - for (i = 0; i < MAXPLAYERS; i++) { if (netgame && i != serverplayer && !IsPlayerAdmin(i)) From f6c1e49b273ce563244e8c36c3b5697e7bea6c9d Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 22:07:17 -0400 Subject: [PATCH 084/137] Fix boss1 laser in interp --- src/r_things.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index 9d2f9f4df..fa6baddec 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1814,23 +1814,25 @@ static void R_ProjectSprite(mobj_t *thing) if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY) { + interpmobjstate_t tracer_interp = {0}; fixed_t linkscale; thing = thing->tracer; - if (R_UsingFrameInterpolation() && !paused) - { - R_InterpolateMobjState(thing, rendertimefrac, &interp); - } - else - { - R_InterpolateMobjState(thing, FRACUNIT, &interp); - } if (! R_ThingVisible(thing)) return; - tr_x = (interp.x + sort_x) - viewx; - tr_y = (interp.y + sort_y) - viewy; + if (R_UsingFrameInterpolation() && !paused) + { + R_InterpolateMobjState(thing, rendertimefrac, &tracer_interp); + } + else + { + R_InterpolateMobjState(thing, FRACUNIT, &tracer_interp); + } + + tr_x = (tracer_interp.x + sort_x) - viewx; + tr_y = (tracer_interp.y + sort_y) - viewy; tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); linkscale = FixedDiv(projectiony, tz); From 51553e7f75442c74e1aefa1ba0f9fd94f735f919 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 27 Apr 2022 21:39:47 -0500 Subject: [PATCH 085/137] Interpolate mobj scale --- src/hardware/hw_main.c | 2 +- src/p_mobj.h | 2 ++ src/r_fps.c | 3 +++ src/r_fps.h | 1 + src/r_things.c | 4 +++- 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 747d3402b..013f60ed4 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5112,7 +5112,7 @@ static void HWR_ProjectSprite(mobj_t *thing) R_InterpolateMobjState(thing, FRACUNIT, &interp); } - this_scale = FIXED_TO_FLOAT(thing->scale); + this_scale = FIXED_TO_FLOAT(interp.scale); spritexscale = FIXED_TO_FLOAT(thing->spritexscale); spriteyscale = FIXED_TO_FLOAT(thing->spriteyscale); diff --git a/src/p_mobj.h b/src/p_mobj.h index 498eeb8a6..e20920181 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -377,6 +377,8 @@ typedef struct mobj_s UINT32 mobjnum; // A unique number for this mobj. Used for restoring pointers on save games. fixed_t scale; + fixed_t old_scale; // interpolation + fixed_t old_scale2; fixed_t destscale; fixed_t scalespeed; diff --git a/src/r_fps.c b/src/r_fps.c index d3a996207..a897ee555 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -266,6 +266,7 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); + out->scale = R_LerpFixed(mobj->old_scale, mobj->scale, frac); out->subsector = R_PointInSubsector(out->x, out->y); @@ -704,12 +705,14 @@ void R_ResetMobjInterpolationState(mobj_t *mobj) mobj->old_angle2 = mobj->old_angle; mobj->old_pitch2 = mobj->old_pitch; mobj->old_roll2 = mobj->old_roll; + mobj->old_scale2 = mobj->old_scale; mobj->old_x = mobj->x; mobj->old_y = mobj->y; mobj->old_z = mobj->z; mobj->old_angle = mobj->angle; mobj->old_pitch = mobj->pitch; mobj->old_roll = mobj->roll; + mobj->old_scale = mobj->scale; if (mobj->player) { diff --git a/src/r_fps.h b/src/r_fps.h index cf66d72f9..9a2d1d26d 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -59,6 +59,7 @@ typedef struct { fixed_t z; subsector_t *subsector; angle_t angle; + fixed_t scale; } interpmobjstate_t; // Level interpolators diff --git a/src/r_things.c b/src/r_things.c index fa6baddec..32ef455fe 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1481,7 +1481,7 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t gz = 0, gzt = 0; INT32 heightsec, phs; INT32 light = 0; - fixed_t this_scale = thing->scale; + fixed_t this_scale; fixed_t spritexscale, spriteyscale; // rotsprite @@ -1506,6 +1506,8 @@ static void R_ProjectSprite(mobj_t *thing) R_InterpolateMobjState(thing, FRACUNIT, &interp); } + this_scale = interp.scale; + // transform the origin point tr_x = interp.x - viewx; tr_y = interp.y - viewy; From d2282c98cce95ca99403b47a56ef56bf46741dc7 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 22:42:47 -0400 Subject: [PATCH 086/137] Precalculate refresh rate Slower PCs can have issue querying mode over and over. This might kinda suck for windowed mode if you have different refresh rate displays but oh well --- src/sdl/i_video.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 8d1ea62d4..d7747048d 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -1602,6 +1602,27 @@ boolean VID_CheckRenderer(void) return rendererchanged; } +static UINT32 refresh_rate; +static UINT32 VID_GetRefreshRate(void) +{ + int index = SDL_GetWindowDisplayIndex(window); + SDL_DisplayMode m; + + if (SDL_WasInit(SDL_INIT_VIDEO) == 0) + { + // Video not init yet. + return 0; + } + + if (SDL_GetCurrentDisplayMode(index, &m) != 0) + { + // Error has occurred. + return 0; + } + + return m.refresh_rate; +} + INT32 VID_SetMode(INT32 modeNum) { SDLdoUngrabMouse(); @@ -1622,6 +1643,8 @@ INT32 VID_SetMode(INT32 modeNum) src_rect.w = vid.width; src_rect.h = vid.height; + refresh_rate = VID_GetRefreshRate(); + VID_CheckRenderer(); return SDL_TRUE; } @@ -1971,20 +1994,10 @@ void I_GetCursorPosition(INT32 *x, INT32 *y) UINT32 I_GetRefreshRate(void) { - int index = SDL_GetWindowDisplayIndex(window); - SDL_DisplayMode m; - - if (SDL_WasInit(SDL_INIT_VIDEO) == 0) - { - // Video not init yet. - return 0; - } - - if (SDL_GetDesktopDisplayMode(index, &m) != 0) - { - // Error has occurred. - return 0; - } - - return m.refresh_rate; + // Moved to VID_GetRefreshRate. + // Precalculating it like that won't work as + // well for windowed mode since you can drag + // the window around, but very slow PCs might have + // trouble querying mode over and over again. + return refresh_rate; } From 5a7a63c2cc512c0db9eede506142d857378cd05e Mon Sep 17 00:00:00 2001 From: katsy Date: Thu, 28 Apr 2022 17:21:45 -0500 Subject: [PATCH 087/137] Fix interp scaling crashing software --- src/r_things.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_things.c b/src/r_things.c index 32ef455fe..da608ef12 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -2069,7 +2069,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->xscale = FixedMul(spritexscale, xscale); //SoM: 4/17/2000 vis->scale = FixedMul(spriteyscale, yscale); //<thingscale = oldthing->scale; + vis->thingscale = this_scale; vis->spritexscale = spritexscale; vis->spriteyscale = spriteyscale; From 34eebcb4b8f64fe2602cf84ec0d07c39343a994e Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 28 Apr 2022 18:36:10 -0500 Subject: [PATCH 088/137] Reset interp scale when Lua sets .scale --- src/lua_mobjlib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 995cdc444..2aec48c90 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -767,6 +767,7 @@ static int mobj_set(lua_State *L) scale = FRACUNIT/100; mo->destscale = scale; P_SetScale(mo, scale); + mo->old_scale = scale; break; } case mobj_destscale: From 50b0c29db947b934810884874e7c17071bf0364e Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 28 Apr 2022 18:46:02 -0500 Subject: [PATCH 089/137] Disable angle interp on fresh mobjs --- src/p_mobj.c | 2 ++ src/p_mobj.h | 1 + src/r_fps.c | 6 ++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 88c269b26..10084e06b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10593,6 +10593,8 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Tells MobjCheckWater that the water height was not set. mobj->watertop = INT32_MAX; + mobj->resetinterp = true; + if (z == ONFLOORZ) { mobj->z = mobj->floorz; diff --git a/src/p_mobj.h b/src/p_mobj.h index e20920181..5f65d6a72 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -393,6 +393,7 @@ typedef struct mobj_s struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?) + boolean resetinterp; // if true, some fields should not be interpolated (see R_InterpolateMobjState implementation) boolean colorized; // Whether the mobj uses the rainbow colormap boolean mirrored; // The object's rotations will be mirrored left to right, e.g., see frame AL from the right and AR from the left fixed_t shadowscale; // If this object casts a shadow, and the size relative to radius diff --git a/src/r_fps.c b/src/r_fps.c index a897ee555..cce704245 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -272,11 +272,11 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) if (mobj->player) { - out->angle = R_LerpAngle(mobj->player->old_drawangle, mobj->player->drawangle, frac); + out->angle = mobj->resetinterp ? mobj->player->drawangle : R_LerpAngle(mobj->player->old_drawangle, mobj->player->drawangle, frac); } else { - out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac); + out->angle = mobj->resetinterp ? mobj->angle : R_LerpAngle(mobj->old_angle, mobj->angle, frac); } } @@ -719,6 +719,8 @@ void R_ResetMobjInterpolationState(mobj_t *mobj) mobj->player->old_drawangle2 = mobj->player->old_drawangle; mobj->player->old_drawangle = mobj->player->drawangle; } + + mobj->resetinterp = false; } // From 687d98eb4a502e32b8c301bbe7a97f2a302e9b8a Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 28 Apr 2022 20:07:07 -0500 Subject: [PATCH 090/137] Fix interp scale crash for hires sprites --- src/r_things.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/r_things.c b/src/r_things.c index da608ef12..1deedfbe1 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1499,11 +1499,11 @@ static void R_ProjectSprite(mobj_t *thing) // do interpolation if (R_UsingFrameInterpolation() && !paused) { - R_InterpolateMobjState(thing, rendertimefrac, &interp); + R_InterpolateMobjState(oldthing, rendertimefrac, &interp); } else { - R_InterpolateMobjState(thing, FRACUNIT, &interp); + R_InterpolateMobjState(oldthing, FRACUNIT, &interp); } this_scale = interp.scale; @@ -2069,7 +2069,7 @@ static void R_ProjectSprite(mobj_t *thing) vis->xscale = FixedMul(spritexscale, xscale); //SoM: 4/17/2000 vis->scale = FixedMul(spriteyscale, yscale); //<thingscale = this_scale; + vis->thingscale = interp.scale; vis->spritexscale = spritexscale; vis->spriteyscale = spriteyscale; From 1aebf41e828b3888f383e28ec92405233cfbeaea Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 28 Apr 2022 20:14:04 -0500 Subject: [PATCH 091/137] Interp shadow scales --- src/hardware/hw_main.c | 14 ++++++++++++-- src/r_things.c | 18 ++++++++++++++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 013f60ed4..9b82aa3af 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5288,14 +5288,24 @@ static void HWR_ProjectSprite(mobj_t *thing) if (thing->renderflags & RF_SHADOWEFFECTS) { mobj_t *caster = thing->target; + interpmobjstate_t casterinterp = {}; + + if (R_UsingFrameInterpolation() && !paused) + { + R_InterpolateMobjState(caster, rendertimefrac, &casterinterp); + } + else + { + R_InterpolateMobjState(caster, FRACUNIT, &casterinterp); + } if (caster && !P_MobjWasRemoved(caster)) { fixed_t groundz = R_GetShadowZ(thing, NULL); - fixed_t floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + caster->z - groundz); + fixed_t floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + casterinterp.z - groundz); shadowheight = FIXED_TO_FLOAT(floordiff); - shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, caster->scale)); + shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, casterinterp.scale)); if (splat) spritexscale *= shadowscale; diff --git a/src/r_things.c b/src/r_things.c index 1deedfbe1..7abb1d926 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1362,7 +1362,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->gy = interp.y; shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + patch->height * shadowyscale / 2; shadow->gz = shadow->gzt - patch->height * shadowyscale; - shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale)); + shadow->texturemid = FixedMul(interp.scale, FixedDiv(shadow->gzt - viewz, shadowyscale)); if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES) shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale); shadow->scalestep = 0; @@ -1375,7 +1375,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, shadow->xscale = FixedMul(xscale, shadowxscale); //SoM: 4/17/2000 shadow->scale = FixedMul(yscale, shadowyscale); - shadow->thingscale = thing->scale; + shadow->thingscale = interp.scale; shadow->sector = vis->sector; shadow->szt = (INT16)((centeryfrac - FixedMul(shadow->gzt - viewz, yscale))>>FRACBITS); shadow->sz = (INT16)((centeryfrac - FixedMul(shadow->gz - viewz, yscale))>>FRACBITS); @@ -1905,6 +1905,16 @@ static void R_ProjectSprite(mobj_t *thing) if (shadoweffects) { mobj_t *caster = thing->target; + interpmobjstate_t casterinterp = {}; + + if (R_UsingFrameInterpolation() && !paused) + { + R_InterpolateMobjState(caster, rendertimefrac, &casterinterp); + } + else + { + R_InterpolateMobjState(caster, FRACUNIT, &casterinterp); + } if (caster && !P_MobjWasRemoved(caster)) { @@ -1913,9 +1923,9 @@ static void R_ProjectSprite(mobj_t *thing) if (abs(groundz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes - floordiff = abs((isflipped ? caster->height : 0) + caster->z - groundz); + floordiff = abs((isflipped ? caster->height : 0) + casterinterp.z - groundz); trans += ((floordiff / (100*FRACUNIT)) + 3); - shadowscale = FixedMul(FRACUNIT - floordiff/640, caster->scale); + shadowscale = FixedMul(FRACUNIT - floordiff/640, casterinterp.scale); } else trans += 3; From 5d4f7f2ad26dd3254d4caede0673f0e38d38ffe6 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 28 Apr 2022 20:39:37 -0500 Subject: [PATCH 092/137] Copy interp state in P_SpawnMobjFromMobj --- src/p_mobj.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 10084e06b..3fe50c34f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -14012,5 +14012,29 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo newmobj->destscale = mobj->destscale; P_SetScale(newmobj, mobj->scale); + + newmobj->old_x2 = mobj->old_x2 + xofs; + newmobj->old_y2 = mobj->old_y2 + yofs; + newmobj->old_z2 = mobj->old_z2 + yofs; + newmobj->old_x = mobj->old_x + xofs; + newmobj->old_y = mobj->old_y + yofs; + newmobj->old_z = mobj->old_z + yofs; + + // This angle hack is needed for Lua scripts that set the angle after + // spawning, to avoid erroneous interpolation. + if (mobj->player) + { + newmobj->old_angle2 = mobj->player->old_drawangle2; + newmobj->old_angle = mobj->player->old_drawangle; + } + else + { + newmobj->old_angle2 = mobj->old_angle2; + newmobj->old_angle = mobj->old_angle; + } + + newmobj->old_scale2 = mobj->old_scale2; + newmobj->old_scale = mobj->old_scale; + return newmobj; } From 7c41564362f57498ddeeb956a9e348821689b117 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 27 Apr 2022 23:18:30 -0400 Subject: [PATCH 093/137] Fix multiplayer character select --- src/m_menu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 1b3943f8b..d32782ed1 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -11850,7 +11850,7 @@ static void M_HandleConnectIP(INT32 choice) // ======================== // Tails 03-02-2002 -static UINT8 multi_tics; +static fixed_t multi_tics; static UINT8 multi_frame; static UINT8 multi_spr2; @@ -11918,10 +11918,11 @@ static void M_DrawSetupMultiPlayerMenu(void) y += 11; // anim the player in the box - if (--multi_tics <= 0) + multi_tics -= renderdeltatics; + while (multi_tics <= 0) { multi_frame++; - multi_tics = 4; + multi_tics += 4*FRACUNIT; } #define charw 74 @@ -12192,7 +12193,7 @@ static void M_SetupMultiPlayer(INT32 choice) (void)choice; multi_frame = 0; - multi_tics = 4; + multi_tics = 4*FRACUNIT; strcpy(setupm_name, cv_playername.string); // set for player 1 @@ -12236,7 +12237,7 @@ static void M_SetupMultiPlayer2(INT32 choice) (void)choice; multi_frame = 0; - multi_tics = 4; + multi_tics = 4*FRACUNIT; strcpy (setupm_name, cv_playername2.string); // set for splitscreen secondary player From 42ebf163e604455aff3041132f1550b50807c8f5 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 28 Apr 2022 21:07:06 -0500 Subject: [PATCH 094/137] Don't interpolate mobj state if frac = 1.0 --- src/r_fps.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/r_fps.c b/src/r_fps.c index cce704245..40b9c767d 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -263,6 +263,17 @@ angle_t R_InterpolateAngle(angle_t from, angle_t to) void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) { + if (frac == FRACUNIT) + { + out->x = mobj->x; + out->y = mobj->y; + out->z = mobj->z; + out->scale = mobj->scale; + out->subsector = mobj->subsector; + out->angle = mobj->player ? mobj->player->drawangle : mobj->angle; + return; + } + out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); @@ -282,6 +293,16 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out) { + if (frac == FRACUNIT) + { + out->x = mobj->x; + out->y = mobj->y; + out->z = mobj->z; + out->subsector = mobj->subsector; + out->angle = mobj->angle; + return; + } + out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); From 8f43b5afd07114ac08471ee94bf3fad22593cf64 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 28 Apr 2022 22:32:35 -0500 Subject: [PATCH 095/137] Fix Mario block item placement --- src/p_floor.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/p_floor.c b/src/p_floor.c index e583f8c66..5c0df0f96 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -2455,9 +2455,9 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) } P_UnsetThingPosition(thing); - thing->x = sector->soundorg.x; - thing->y = sector->soundorg.y; - thing->z = topheight; + thing->x = thing->old_x = sector->soundorg.x; + thing->y = thing->old_y = sector->soundorg.y; + thing->z = thing->old_z = topheight; thing->momz = FixedMul(6*FRACUNIT, thing->scale); P_SetThingPosition(thing); if (thing->flags & MF_SHOOTABLE) @@ -2478,9 +2478,9 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) if (itsamonitor && thing) { P_UnsetThingPosition(thing); - thing->x = oldx; - thing->y = oldy; - thing->z = oldz; + thing->x = thing->old_x = oldx; + thing->y = thing->old_y = oldy; + thing->z = thing->old_z = oldz; thing->momx = 1; thing->momy = 1; P_SetThingPosition(thing); From 1259f1be40fe6237fbebf8969a3f9a45d447a91e Mon Sep 17 00:00:00 2001 From: Eidolon Date: Fri, 29 Apr 2022 14:21:30 -0500 Subject: [PATCH 096/137] Interpolate spritescale/offset x/y --- src/hardware/hw_main.c | 18 +++++++++--------- src/p_mobj.c | 7 +++++-- src/p_mobj.h | 4 ++++ src/r_fps.c | 29 ++++++++++++++++++++++++++++- src/r_fps.h | 4 ++++ src/r_things.c | 12 ++++++------ 6 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 9b82aa3af..6e193fccd 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -5084,9 +5084,6 @@ static void HWR_ProjectSprite(mobj_t *thing) if (!thing) return; - if (thing->spritexscale < 1 || thing->spriteyscale < 1) - return; - INT32 blendmode; if (thing->frame & FF_BLENDMASK) blendmode = ((thing->frame & FF_BLENDMASK) >> FF_BLENDSHIFT) + 1; @@ -5112,9 +5109,12 @@ static void HWR_ProjectSprite(mobj_t *thing) R_InterpolateMobjState(thing, FRACUNIT, &interp); } + if (interp.spritexscale < 1 || interp.spriteyscale < 1) + return; + this_scale = FIXED_TO_FLOAT(interp.scale); - spritexscale = FIXED_TO_FLOAT(thing->spritexscale); - spriteyscale = FIXED_TO_FLOAT(thing->spriteyscale); + spritexscale = FIXED_TO_FLOAT(interp.spritexscale); + spriteyscale = FIXED_TO_FLOAT(interp.spriteyscale); // transform the origin point tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx; @@ -5258,8 +5258,8 @@ static void HWR_ProjectSprite(mobj_t *thing) if (thing->renderflags & RF_ABSOLUTEOFFSETS) { - spr_offset = thing->spritexoffset; - spr_topoffset = thing->spriteyoffset; + spr_offset = interp.spritexoffset; + spr_topoffset = interp.spriteyoffset; } else { @@ -5268,8 +5268,8 @@ static void HWR_ProjectSprite(mobj_t *thing) if ((thing->renderflags & RF_FLIPOFFSETS) && flip) flipoffset = -1; - spr_offset += thing->spritexoffset * flipoffset; - spr_topoffset += thing->spriteyoffset * flipoffset; + spr_offset += interp.spritexoffset * flipoffset; + spr_topoffset += interp.spriteyoffset * flipoffset; } if (papersprite) diff --git a/src/p_mobj.c b/src/p_mobj.c index 3fe50c34f..f48319aed 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -10593,8 +10593,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // Tells MobjCheckWater that the water height was not set. mobj->watertop = INT32_MAX; - mobj->resetinterp = true; - if (z == ONFLOORZ) { mobj->z = mobj->floorz; @@ -14032,9 +14030,14 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo newmobj->old_angle2 = mobj->old_angle2; newmobj->old_angle = mobj->old_angle; } + newmobj->resetinterp = true; newmobj->old_scale2 = mobj->old_scale2; newmobj->old_scale = mobj->old_scale; + newmobj->old_spritexscale = mobj->old_spritexscale; + newmobj->old_spriteyscale = mobj->old_spriteyscale; + newmobj->old_spritexoffset = mobj->old_spritexoffset; + newmobj->old_spriteyoffset = mobj->old_spriteyoffset; return newmobj; } diff --git a/src/p_mobj.h b/src/p_mobj.h index 5f65d6a72..ad000d6d8 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -302,6 +302,8 @@ typedef struct mobj_s INT32 blendmode; // blend mode fixed_t spritexscale, spriteyscale; fixed_t spritexoffset, spriteyoffset; + fixed_t old_spritexscale, old_spriteyscale; + fixed_t old_spritexoffset, old_spriteyoffset; struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by struct msecnode_s *touching_sectorlist; // a linked list of sectors where this object appears @@ -436,6 +438,8 @@ typedef struct precipmobj_s INT32 blendmode; // blend mode fixed_t spritexscale, spriteyscale; fixed_t spritexoffset, spriteyoffset; + fixed_t old_spritexscale, old_spriteyscale; + fixed_t old_spritexoffset, old_spriteyoffset; struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears diff --git a/src/r_fps.c b/src/r_fps.c index 40b9c767d..b4ec5439c 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -271,13 +271,21 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) out->scale = mobj->scale; out->subsector = mobj->subsector; out->angle = mobj->player ? mobj->player->drawangle : mobj->angle; + out->spritexscale = mobj->spritexscale; + out->spriteyscale = mobj->spriteyscale; + out->spritexoffset = mobj->spritexoffset; + out->spriteyoffset = mobj->spriteyoffset; return; } out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); - out->scale = R_LerpFixed(mobj->old_scale, mobj->scale, frac); + out->scale = mobj->resetinterp ? mobj->scale : R_LerpFixed(mobj->old_scale, mobj->scale, frac); + out->spritexscale = mobj->resetinterp ? mobj->spritexscale : R_LerpFixed(mobj->old_spritexscale, mobj->spritexscale, frac); + out->spriteyscale = mobj->resetinterp ? mobj->spriteyscale : R_LerpFixed(mobj->old_spriteyscale, mobj->spriteyscale, frac); + out->spritexoffset = mobj->resetinterp ? mobj->spritexoffset : R_LerpFixed(mobj->old_spritexoffset, mobj->spritexoffset, frac); + out->spriteyoffset = mobj->resetinterp ? mobj->spriteyoffset : R_LerpFixed(mobj->old_spriteyoffset, mobj->spriteyoffset, frac); out->subsector = R_PointInSubsector(out->x, out->y); @@ -298,14 +306,24 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst out->x = mobj->x; out->y = mobj->y; out->z = mobj->z; + out->scale = FRACUNIT; out->subsector = mobj->subsector; out->angle = mobj->angle; + out->spritexscale = mobj->spritexscale; + out->spriteyscale = mobj->spriteyscale; + out->spritexoffset = mobj->spritexoffset; + out->spriteyoffset = mobj->spriteyoffset; return; } out->x = R_LerpFixed(mobj->old_x, mobj->x, frac); out->y = R_LerpFixed(mobj->old_y, mobj->y, frac); out->z = R_LerpFixed(mobj->old_z, mobj->z, frac); + out->scale = FRACUNIT; + out->spritexscale = R_LerpFixed(mobj->old_spritexscale, mobj->spritexscale, frac); + out->spriteyscale = R_LerpFixed(mobj->old_spriteyscale, mobj->spriteyscale, frac); + out->spritexoffset = R_LerpFixed(mobj->old_spritexoffset, mobj->spritexoffset, frac); + out->spriteyoffset = R_LerpFixed(mobj->old_spriteyoffset, mobj->spriteyoffset, frac); out->subsector = R_PointInSubsector(out->x, out->y); @@ -672,6 +690,7 @@ void R_AddMobjInterpolator(mobj_t *mobj) interpolated_mobjs_len += 1; R_ResetMobjInterpolationState(mobj); + mobj->resetinterp = true; } void R_RemoveMobjInterpolator(mobj_t *mobj) @@ -734,6 +753,10 @@ void R_ResetMobjInterpolationState(mobj_t *mobj) mobj->old_pitch = mobj->pitch; mobj->old_roll = mobj->roll; mobj->old_scale = mobj->scale; + mobj->old_spritexscale = mobj->spritexscale; + mobj->old_spriteyscale = mobj->spriteyscale; + mobj->old_spritexoffset = mobj->spritexoffset; + mobj->old_spriteyoffset = mobj->spriteyoffset; if (mobj->player) { @@ -761,4 +784,8 @@ void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj) mobj->old_y = mobj->y; mobj->old_z = mobj->z; mobj->old_angle = mobj->angle; + mobj->old_spritexscale = mobj->spritexscale; + mobj->old_spriteyscale = mobj->spriteyscale; + mobj->old_spritexoffset = mobj->spritexoffset; + mobj->old_spriteyoffset = mobj->spriteyoffset; } diff --git a/src/r_fps.h b/src/r_fps.h index 9a2d1d26d..97d6022b7 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -60,6 +60,10 @@ typedef struct { subsector_t *subsector; angle_t angle; fixed_t scale; + fixed_t spritexscale; + fixed_t spriteyscale; + fixed_t spritexoffset; + fixed_t spriteyoffset; } interpmobjstate_t; // Level interpolators diff --git a/src/r_things.c b/src/r_things.c index 7abb1d926..241bc7490 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1671,15 +1671,15 @@ static void R_ProjectSprite(mobj_t *thing) flip = !flip != !hflip; // calculate edges of the shape - spritexscale = thing->spritexscale; - spriteyscale = thing->spriteyscale; + spritexscale = interp.spritexscale; + spriteyscale = interp.spriteyscale; if (spritexscale < 1 || spriteyscale < 1) return; if (thing->renderflags & RF_ABSOLUTEOFFSETS) { - spr_offset = thing->spritexoffset; - spr_topoffset = thing->spriteyoffset; + spr_offset = interp.spritexoffset; + spr_topoffset = interp.spriteyoffset; } else { @@ -1688,8 +1688,8 @@ static void R_ProjectSprite(mobj_t *thing) if ((thing->renderflags & RF_FLIPOFFSETS) && flip) flipoffset = -1; - spr_offset += thing->spritexoffset * flipoffset; - spr_topoffset += thing->spriteyoffset * flipoffset; + spr_offset += interp.spritexoffset * flipoffset; + spr_topoffset += interp.spriteyoffset * flipoffset; } if (flip) From 56261d3e1e1040b9610828d37d3d9e6f1142a209 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Fri, 29 Apr 2022 17:19:09 -0500 Subject: [PATCH 097/137] Fix offset copies for SpawnMobjFromMobj THANKS SAL --- src/p_mobj.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index f48319aed..82859188c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -14013,10 +14013,10 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo newmobj->old_x2 = mobj->old_x2 + xofs; newmobj->old_y2 = mobj->old_y2 + yofs; - newmobj->old_z2 = mobj->old_z2 + yofs; + newmobj->old_z2 = mobj->old_z2 + zofs; newmobj->old_x = mobj->old_x + xofs; newmobj->old_y = mobj->old_y + yofs; - newmobj->old_z = mobj->old_z + yofs; + newmobj->old_z = mobj->old_z + zofs; // This angle hack is needed for Lua scripts that set the angle after // spawning, to avoid erroneous interpolation. @@ -14030,7 +14030,6 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo newmobj->old_angle2 = mobj->old_angle2; newmobj->old_angle = mobj->old_angle; } - newmobj->resetinterp = true; newmobj->old_scale2 = mobj->old_scale2; newmobj->old_scale = mobj->old_scale; From 82310e0ae2973459279b3bdc084cc82776dd0da5 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 30 Apr 2022 01:50:12 -0500 Subject: [PATCH 098/137] Add Lua HUD drawlists Buffers draw calls between tics to ensure hooks run at the originally intended rate. --- src/Sourcefile | 1 + src/d_main.c | 2 + src/f_finale.c | 12 +- src/hu_stuff.c | 13 +- src/lua_hook.h | 5 +- src/lua_hooklib.c | 7 +- src/lua_hud.h | 9 +- src/lua_hudlib.c | 144 ++++++++-- src/lua_hudlib_drawlist.c | 572 ++++++++++++++++++++++++++++++++++++++ src/lua_hudlib_drawlist.h | 152 ++++++++++ src/r_main.c | 1 + src/r_main.h | 4 +- src/st_stuff.c | 23 +- src/y_inter.c | 14 +- 14 files changed, 931 insertions(+), 28 deletions(-) create mode 100644 src/lua_hudlib_drawlist.c create mode 100644 src/lua_hudlib_drawlist.h diff --git a/src/Sourcefile b/src/Sourcefile index ef9fbdc13..fa82f86da 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -96,4 +96,5 @@ lua_taglib.c lua_polyobjlib.c lua_blockmaplib.c lua_hudlib.c +lua_hudlib_drawlist.c lua_inputlib.c diff --git a/src/d_main.c b/src/d_main.c index 850da2f1a..8b4de45e9 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -826,6 +826,8 @@ void D_SRB2Loop(void) doDisplay = true; } + + renderisnewtic = true; } if (interp) diff --git a/src/f_finale.c b/src/f_finale.c index 832c0ecb3..4ddcaff5f 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -227,6 +227,8 @@ static tic_t cutscene_lasttextwrite = 0; // STJR Intro char stjrintro[9] = "STJRI000"; +static huddrawlist_h luahuddrawlist_title; + // // This alters the text string cutscene_disptext. // Use the typical string drawing functions to display it. @@ -2278,6 +2280,9 @@ void F_InitMenuPresValues(void) M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "RECATTBG" : "TITLESKY"); M_SetMenuCurFadeValue(16); M_SetMenuCurTitlePics(); + + LUA_HUD_DestroyDrawList(luahuddrawlist_title); + luahuddrawlist_title = LUA_HUD_CreateDrawList(); } // @@ -3397,7 +3402,12 @@ void F_TitleScreenDrawer(void) } luahook: - LUA_HUDHOOK(title); + if (renderisnewtic) + { + LUA_HUD_ClearDrawList(luahuddrawlist_title); + LUA_HUDHOOK(title, luahuddrawlist_title); + } + LUA_HUD_DrawList(luahuddrawlist_title); } // separate animation timer for backgrounds, since we also count diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 518f28b50..c4067d7d8 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -48,6 +48,7 @@ #endif #include "lua_hud.h" +#include "lua_hudlib_drawlist.h" #include "lua_hook.h" // coords are scaled @@ -166,6 +167,8 @@ static tic_t cechotimer = 0; static tic_t cechoduration = 5*TICRATE; static INT32 cechoflags = 0; +static huddrawlist_h luahuddrawlist_scores; + //====================================================================== // HEADS UP INIT //====================================================================== @@ -334,6 +337,8 @@ void HU_Init(void) // set shift translation table shiftxform = english_shiftxform; + + luahuddrawlist_scores = LUA_HUD_CreateDrawList(); } static inline void HU_Stop(void) @@ -1989,7 +1994,13 @@ void HU_Drawer(void) } else HU_DrawCoopOverlay(); - LUA_HUDHOOK(scores); + + if (renderisnewtic) + { + LUA_HUD_ClearDrawList(luahuddrawlist_scores); + LUA_HUDHOOK(scores, luahuddrawlist_scores); + } + LUA_HUD_DrawList(luahuddrawlist_scores); } if (gamestate != GS_LEVEL) diff --git a/src/lua_hook.h b/src/lua_hook.h index fc6a5f4ee..5a14294c3 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -14,6 +14,7 @@ #include "d_player.h" #include "s_sound.h" #include "d_event.h" +#include "lua_hudlib_drawlist.h" /* Do you know what an 'X Macro' is? Such a macro is called over each element of @@ -110,12 +111,12 @@ ENUM (STRING_HOOK); /* dead simple, LUA_HOOK(GameQuit) */ #define LUA_HOOK(type) LUA_HookVoid(HOOK(type)) -#define LUA_HUDHOOK(type) LUA_HookHUD(HUD_HOOK(type)) +#define LUA_HUDHOOK(type,drawlist) LUA_HookHUD(HUD_HOOK(type),(drawlist)) extern boolean hook_cmd_running; void LUA_HookVoid(int hook); -void LUA_HookHUD(int hook); +void LUA_HookHUD(int hook, huddrawlist_h drawlist); int LUA_HookMobj(mobj_t *, int hook); int LUA_Hook2Mobj(mobj_t *, mobj_t *, int hook); diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 48980f4a4..0b24b7b53 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -641,7 +641,7 @@ int LUA_HookKey(event_t *event, int hook_type) return hook.status; } -void LUA_HookHUD(int hook_type) +void LUA_HookHUD(int hook_type, huddrawlist_h list) { const hook_t * map = &hudHookIds[hook_type]; Hook_State hook; @@ -650,12 +650,15 @@ void LUA_HookHUD(int hook_type) start_hook_stack(); begin_hook_values(&hook); - LUA_SetHudHook(hook_type); + LUA_SetHudHook(hook_type, list); hud_running = true; // local hook init_hook_call(&hook, 0, res_none); call_mapped(&hook, map); hud_running = false; + + lua_pushnil(gL); + lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST"); } } diff --git a/src/lua_hud.h b/src/lua_hud.h index ad2b51d3e..0d629d233 100644 --- a/src/lua_hud.h +++ b/src/lua_hud.h @@ -10,6 +10,11 @@ /// \file lua_hud.h /// \brief HUD enable/disable flags for Lua scripting +#ifndef __LUA_HUD_H__ +#define __LUA_HUD_H__ + +#include "lua_hudlib_drawlist.h" + enum hud { hud_stagetitle = 0, hud_textspectator, @@ -47,4 +52,6 @@ extern boolean hud_running; boolean LUA_HudEnabled(enum hud option); -void LUA_SetHudHook(int hook); +void LUA_SetHudHook(int hook, huddrawlist_h list); + +#endif // __LUA_HUD_H__ diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index cffb0b64f..d049bcfe2 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -645,7 +645,8 @@ static int libd_draw(lua_State *L) { INT32 x, y, flags; patch_t *patch; - const UINT8 *colormap = NULL; + UINT8 *colormap = NULL; + huddrawlist_h list; HUDONLY x = luaL_checkinteger(L, 1); @@ -659,7 +660,14 @@ static int libd_draw(lua_State *L) flags &= ~V_PARAMMASK; // Don't let crashes happen. - V_DrawFixedPatch(x< maxstrength) return luaL_error(L, "%s fade strength %d out of range (0 - %d)", ((color & 0xFF00) ? "COLORMAP" : "TRANSMAP"), strength, maxstrength); + lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST"); + list = (huddrawlist_h) lua_touserdata(L, -1); + lua_pop(L, 1); + if (strength == maxstrength) // Allow as a shortcut for drawfill... { - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color)); + if (LUA_HUD_IsDrawListValid(list)) + LUA_HUD_AddDrawFill(list, 0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color)); + else + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color)); return 0; } - V_DrawFadeScreen(color, strength); + if (LUA_HUD_IsDrawListValid(list)) + LUA_HUD_AddFadeScreen(list, color, strength); + else + V_DrawFadeScreen(color, strength); + return 0; } @@ -1365,10 +1472,13 @@ boolean LUA_HudEnabled(enum hud option) return false; } -void LUA_SetHudHook(int hook) +void LUA_SetHudHook(int hook, huddrawlist_h list) { lua_getref(gL, lib_draw_ref); + lua_pushlightuserdata(gL, list); + lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST"); + switch (hook) { case HUD_HOOK(game): { diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c new file mode 100644 index 000000000..bcf132ec6 --- /dev/null +++ b/src/lua_hudlib_drawlist.c @@ -0,0 +1,572 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2014-2016 by John "JTE" Muniz. +// Copyright (C) 2014-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file lua_hudlib_drawlist.c +/// \brief a data structure for managing cached drawlists for the Lua hud lib + +#include "lua_hudlib_drawlist.h" + +#include + +#include "v_video.h" +#include "z_zone.h" + +enum drawitem_e { + DI_Draw = 0, + DI_DrawScaled, + DI_DrawStretched, + DI_DrawCropped, + DI_DrawNum, + DI_DrawPaddedNum, + DI_DrawFill, + DI_DrawString, + DI_DrawNameTag, + DI_DrawScaledNameTag, + DI_DrawLevelTitle, + DI_FadeScreen, + DI_MAX, +}; + +// A single draw item with all possible arguments needed for a draw call. +typedef struct drawitem_s { + enum drawitem_e type; + fixed_t x; + fixed_t y; + fixed_t w; + fixed_t h; + INT32 c; + fixed_t scale; + fixed_t hscale; + fixed_t vscale; + patch_t *patch; + INT32 flags; + UINT16 basecolor; + UINT16 outlinecolor; + UINT8 *colormap; + UINT8 *basecolormap; + UINT8 *outlinecolormap; + fixed_t sx; + fixed_t sy; + INT32 num; + INT32 digits; + const char *str; + UINT16 color; + UINT8 strength; + INT32 align; +} drawitem_t; + +// The internal structure of a drawlist. +struct huddrawlist_s { + drawitem_t *items; + size_t items_capacity; + size_t items_len; + char *strbuf; + size_t strbuf_capacity; + size_t strbuf_len; +}; + +// alignment types for v.drawString +enum align { + align_left = 0, + align_center, + align_right, + align_fixed, + align_fixedcenter, + align_fixedright, + align_small, + align_smallfixed, + align_smallfixedcenter, + align_smallfixedright, + align_smallcenter, + align_smallright, + align_smallthin, + align_smallthincenter, + align_smallthinright, + align_smallthinfixed, + align_smallthinfixedcenter, + align_smallthinfixedright, + align_thin, + align_thinfixed, + align_thinfixedcenter, + align_thinfixedright, + align_thincenter, + align_thinright +}; + +huddrawlist_h LUA_HUD_CreateDrawList(void) +{ + huddrawlist_h drawlist; + + drawlist = (huddrawlist_h) Z_CallocAlign(sizeof(struct huddrawlist_s), PU_STATIC, NULL, 64); + drawlist->items = NULL; + drawlist->items_capacity = 0; + drawlist->items_len = 0; + drawlist->strbuf = NULL; + drawlist->strbuf_capacity = 0; + drawlist->strbuf_len = 0; + + return drawlist; +} + +void LUA_HUD_ClearDrawList(huddrawlist_h list) +{ + // rather than deallocate, we'll just save the existing allocation and empty + // it out for reuse + + // this memset probably isn't necessary + if (list->items) + { + memset(list->items, 0, sizeof(drawitem_t) * list->items_capacity); + } + + list->items_len = 0; + + if (list->strbuf) + { + list->strbuf[0] = 0; + } + list->strbuf_len = 0; +} + +void LUA_HUD_DestroyDrawList(huddrawlist_h list) +{ + if (list == NULL) return; + + if (list->items) + { + Z_Free(list->items); + } + Z_Free(list); +} + +boolean LUA_HUD_IsDrawListValid(huddrawlist_h list) +{ + if (!list) return false; + + // that's all we can really do to check the validity of the handle right now + return true; +} + +static size_t AllocateDrawItem(huddrawlist_h list) +{ + if (!list) I_Error("can't allocate draw item: invalid list"); + if (list->items_capacity <= list->items_len + 1) + { + if (list->items_capacity == 0) list->items_capacity = 128; + else list->items_capacity *= 2; + list->items = (drawitem_t *) Z_ReallocAlign(list->items, sizeof(struct drawitem_s) * list->items_capacity, PU_STATIC, NULL, 64); + } + + return list->items_len++; +} + +// copy string to list's internal string buffer +// lua can deallocate the string before we get to use it, so it's important to +// keep our own copy +static const char *CopyString(huddrawlist_h list, const char* str) +{ + size_t lenstr; + + if (!list) I_Error("can't allocate string; invalid list"); + lenstr = strlen(str); + if (list->strbuf_capacity <= list->strbuf_len + lenstr + 1) + { + if (list->strbuf_capacity == 0) list->strbuf_capacity = 256; + else list->strbuf_capacity *= 2; + list->strbuf = (char*) Z_ReallocAlign(list->strbuf, sizeof(char) * list->strbuf_capacity, PU_STATIC, NULL, 8); + } + const char *result = (const char *) &list->strbuf[list->strbuf_len]; + strncpy(&list->strbuf[list->strbuf_len], str, lenstr + 1); + list->strbuf_len += lenstr + 1; + return result; +} + +void LUA_HUD_AddDraw( + huddrawlist_h list, + INT32 x, + INT32 y, + patch_t *patch, + INT32 flags, + UINT8 *colormap +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_Draw; + item->x = x; + item->y = y; + item->patch = patch; + item->flags = flags; + item->colormap = colormap; +} + +void LUA_HUD_AddDrawScaled( + huddrawlist_h list, + fixed_t x, + fixed_t y, + fixed_t scale, + patch_t *patch, + INT32 flags, + UINT8 *colormap +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawScaled; + item->x = x; + item->y = y; + item->scale = scale; + item->patch = patch; + item->flags = flags; + item->colormap = colormap; +} + +void LUA_HUD_AddDrawStretched( + huddrawlist_h list, + fixed_t x, + fixed_t y, + fixed_t hscale, + fixed_t vscale, + patch_t *patch, + INT32 flags, + UINT8 *colormap +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawStretched; + item->x = x; + item->y = y; + item->hscale = hscale; + item->vscale = vscale; + item->patch = patch; + item->flags = flags; + item->colormap = colormap; +} + +void LUA_HUD_AddDrawCropped( + huddrawlist_h list, + fixed_t x, + fixed_t y, + fixed_t hscale, + fixed_t vscale, + patch_t *patch, + INT32 flags, + UINT8 *colormap, + fixed_t sx, + fixed_t sy, + fixed_t w, + fixed_t h +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawCropped; + item->x = x; + item->y = y; + item->hscale = hscale; + item->vscale = vscale; + item->patch = patch; + item->flags = flags; + item->colormap = colormap; + item->sx = sx; + item->sy = sy; + item->w = w; + item->h = h; +} + +void LUA_HUD_AddDrawNum( + huddrawlist_h list, + INT32 x, + INT32 y, + INT32 num, + INT32 flags +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawNum; + item->x = x; + item->y = y; + item->num = num; + item->flags = flags; +} + +void LUA_HUD_AddDrawPaddedNum( + huddrawlist_h list, + INT32 x, + INT32 y, + INT32 num, + INT32 digits, + INT32 flags +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawPaddedNum; + item->x = x; + item->y = y; + item->num = num; + item->digits = digits; + item->flags = flags; +} + +void LUA_HUD_AddDrawFill( + huddrawlist_h list, + INT32 x, + INT32 y, + INT32 w, + INT32 h, + INT32 c +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawFill; + item->x = x; + item->y = y; + item->w = w; + item->h = h; + item->c = c; +} + +void LUA_HUD_AddDrawString( + huddrawlist_h list, + fixed_t x, + fixed_t y, + const char *str, + INT32 flags, + INT32 align +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawString; + item->x = x; + item->y = y; + item->str = CopyString(list, str); + item->flags = flags; + item->align = align; +} + +void LUA_HUD_AddDrawNameTag( + huddrawlist_h list, + INT32 x, + INT32 y, + const char *str, + INT32 flags, + UINT16 basecolor, + UINT16 outlinecolor, + UINT8 *basecolormap, + UINT8 *outlinecolormap +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawNameTag; + item->x = x; + item->y = y; + item->str = CopyString(list, str); + item->flags = flags; + item->basecolor = basecolor; + item->outlinecolor = outlinecolor; + item->basecolormap = basecolormap; + item->outlinecolormap = outlinecolormap; +} + +void LUA_HUD_AddDrawScaledNameTag( + huddrawlist_h list, + fixed_t x, + fixed_t y, + const char *str, + INT32 flags, + fixed_t scale, + UINT16 basecolor, + UINT16 outlinecolor, + UINT8 *basecolormap, + UINT8 *outlinecolormap +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawScaledNameTag; + item->x = x; + item->y = y; + item->str = CopyString(list, str); + item->flags = flags; + item->scale = scale; + item->basecolor = basecolor; + item->outlinecolor = outlinecolor; + item->basecolormap = basecolormap; + item->outlinecolormap = outlinecolormap; +} + +void LUA_HUD_AddDrawLevelTitle( + huddrawlist_h list, + INT32 x, + INT32 y, + const char *str, + INT32 flags +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_DrawLevelTitle; + item->x = x; + item->y = y; + item->str = CopyString(list, str); + item->flags = flags; +} + +void LUA_HUD_AddFadeScreen( + huddrawlist_h list, + UINT16 color, + UINT8 strength +) +{ + size_t i = AllocateDrawItem(list); + drawitem_t *item = &list->items[i]; + item->type = DI_FadeScreen; + item->color = color; + item->strength = strength; +} + +void LUA_HUD_DrawList(huddrawlist_h list) +{ + size_t i; + + if (!list) I_Error("HUD drawlist invalid"); + if (list->items_len <= 0) return; + if (!list->items) I_Error("HUD drawlist->items invalid"); + + for (i = 0; i < list->items_len; i++) + { + drawitem_t *item = &list->items[i]; + + switch (item->type) + { + case DI_Draw: + V_DrawFixedPatch(item->x<y<flags, item->patch, item->colormap); + break; + case DI_DrawScaled: + V_DrawFixedPatch(item->x, item->y, item->scale, item->flags, item->patch, item->colormap); + break; + case DI_DrawStretched: + V_DrawStretchyFixedPatch(item->x, item->y, item->hscale, item->vscale, item->flags, item->patch, item->colormap); + break; + case DI_DrawCropped: + V_DrawCroppedPatch(item->x, item->y, item->hscale, item->vscale, item->flags, item->patch, item->colormap, item->sx, item->sy, item->w, item->h); + break; + case DI_DrawNum: + V_DrawTallNum(item->x, item->y, item->flags, item->num); + break; + case DI_DrawPaddedNum: + V_DrawPaddedTallNum(item->x, item->y, item->flags, item->num, item->digits); + break; + case DI_DrawFill: + V_DrawFill(item->x, item->y, item->w, item->h, item->c); + break; + case DI_DrawString: + switch(item->align) + { + // hu_font + case align_left: + V_DrawString(item->x, item->y, item->flags, item->str); + break; + case align_center: + V_DrawCenteredString(item->x, item->y, item->flags, item->str); + break; + case align_right: + V_DrawRightAlignedString(item->x, item->y, item->flags, item->str); + break; + case align_fixed: + V_DrawStringAtFixed(item->x, item->y, item->flags, item->str); + break; + case align_fixedcenter: + V_DrawCenteredStringAtFixed(item->x, item->y, item->flags, item->str); + break; + case align_fixedright: + V_DrawRightAlignedStringAtFixed(item->x, item->y, item->flags, item->str); + break; + // hu_font, 0.5x scale + case align_small: + V_DrawSmallString(item->x, item->y, item->flags, item->str); + break; + case align_smallfixed: + V_DrawSmallStringAtFixed(item->x, item->y, item->flags, item->str); + break; + case align_smallfixedcenter: + V_DrawCenteredSmallStringAtFixed(item->x, item->y, item->flags, item->str); + break; + case align_smallfixedright: + V_DrawRightAlignedSmallStringAtFixed(item->x, item->y, item->flags, item->str); + break; + case align_smallcenter: + V_DrawCenteredSmallString(item->x, item->y, item->flags, item->str); + break; + case align_smallright: + V_DrawRightAlignedSmallString(item->x, item->y, item->flags, item->str); + break; + case align_smallthin: + V_DrawSmallThinString(item->x, item->y, item->flags, item->str); + break; + case align_smallthincenter: + V_DrawCenteredSmallThinString(item->x, item->y, item->flags, item->str); + break; + case align_smallthinright: + V_DrawRightAlignedSmallThinString(item->x, item->y, item->flags, item->str); + break; + case align_smallthinfixed: + V_DrawSmallThinStringAtFixed(item->x, item->y, item->flags, item->str); + break; + case align_smallthinfixedcenter: + V_DrawCenteredSmallThinStringAtFixed(item->x, item->y, item->flags, item->str); + break; + case align_smallthinfixedright: + V_DrawRightAlignedSmallThinStringAtFixed(item->x, item->y, item->flags, item->str); + break; + // tny_font + case align_thin: + V_DrawThinString(item->x, item->y, item->flags, item->str); + break; + case align_thincenter: + V_DrawCenteredThinString(item->x, item->y, item->flags, item->str); + break; + case align_thinright: + V_DrawRightAlignedThinString(item->x, item->y, item->flags, item->str); + break; + case align_thinfixed: + V_DrawThinStringAtFixed(item->x, item->y, item->flags, item->str); + break; + case align_thinfixedcenter: + V_DrawCenteredThinStringAtFixed(item->x, item->y, item->flags, item->str); + break; + case align_thinfixedright: + V_DrawRightAlignedThinStringAtFixed(item->x, item->y, item->flags, item->str); + break; + } + break; + case DI_DrawNameTag: + V_DrawNameTag(item->x, item->y, item->flags, FRACUNIT, item->basecolormap, item->outlinecolormap, item->str); + break; + case DI_DrawScaledNameTag: + V_DrawNameTag(FixedInt(item->x), FixedInt(item->y), item->flags, item->scale, item->basecolormap, item->outlinecolormap, item->str); + break; + case DI_DrawLevelTitle: + V_DrawLevelTitle(item->x, item->y, item->flags, item->str); + break; + case DI_FadeScreen: + V_DrawFadeScreen(item->color, item->strength); + break; + default: + I_Error("can't draw draw list item: invalid draw list item type"); + continue; + } + } +} diff --git a/src/lua_hudlib_drawlist.h b/src/lua_hudlib_drawlist.h new file mode 100644 index 000000000..5e97b5c26 --- /dev/null +++ b/src/lua_hudlib_drawlist.h @@ -0,0 +1,152 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 2022-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file lua_hudlib_drawlist.h +/// \brief a data structure for managing cached drawlists for the Lua hud lib + +// The idea behinds this module is to cache drawcall information into an ordered +// list to repeat the same draw operations in later frames. It's used to ensure +// that the HUD hooks from Lua are called at precisely 35hz to avoid problems +// with variable framerates in existing Lua addons. + +#ifndef __LUA_HUDLIB_DRAWLIST__ +#define __LUA_HUDLIB_DRAWLIST__ + +#include "doomtype.h" +#include "r_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct huddrawlist_s *huddrawlist_h; + +// Create a new drawlist. Returns a handle to it. +huddrawlist_h LUA_HUD_CreateDrawList(void); +// Clears the draw list. +void LUA_HUD_ClearDrawList(huddrawlist_h list); +// Destroys the drawlist, invalidating the given handle +void LUA_HUD_DestroyDrawList(huddrawlist_h list); +boolean LUA_HUD_IsDrawListValid(huddrawlist_h list); + +void LUA_HUD_AddDraw( + huddrawlist_h list, + INT32 x, + INT32 y, + patch_t *patch, + INT32 flags, + UINT8 *colormap +); +void LUA_HUD_AddDrawScaled( + huddrawlist_h list, + fixed_t x, + fixed_t y, + fixed_t scale, + patch_t *patch, + INT32 flags, + UINT8 *colormap +); +void LUA_HUD_AddDrawStretched( + huddrawlist_h list, + fixed_t x, + fixed_t y, + fixed_t hscale, + fixed_t vscale, + patch_t *patch, + INT32 flags, + UINT8 *colormap +); +void LUA_HUD_AddDrawCropped( + huddrawlist_h list, + fixed_t x, + fixed_t y, + fixed_t hscale, + fixed_t vscale, + patch_t *patch, + INT32 flags, + UINT8 *colormap, + fixed_t sx, + fixed_t sy, + fixed_t w, + fixed_t h +); +void LUA_HUD_AddDrawNum( + huddrawlist_h list, + INT32 x, + INT32 y, + INT32 num, + INT32 flags +); +void LUA_HUD_AddDrawPaddedNum( + huddrawlist_h list, + INT32 x, + INT32 y, + INT32 num, + INT32 digits, + INT32 flags +); +void LUA_HUD_AddDrawFill( + huddrawlist_h list, + INT32 x, + INT32 y, + INT32 w, + INT32 h, + INT32 c +); +void LUA_HUD_AddDrawString( + huddrawlist_h list, + fixed_t x, + fixed_t y, + const char *str, + INT32 flags, + INT32 align +); +void LUA_HUD_AddDrawNameTag( + huddrawlist_h list, + INT32 x, + INT32 y, + const char *str, + INT32 flags, + UINT16 basecolor, + UINT16 outlinecolor, + UINT8 *basecolormap, + UINT8 *outlinecolormap +); +void LUA_HUD_AddDrawScaledNameTag( + huddrawlist_h list, + fixed_t x, + fixed_t y, + const char *str, + INT32 flags, + fixed_t scale, + UINT16 basecolor, + UINT16 outlinecolor, + UINT8 *basecolormap, + UINT8 *outlinecolormap +); +void LUA_HUD_AddDrawLevelTitle( + huddrawlist_h list, + INT32 x, + INT32 y, + const char *str, + INT32 flags +); +void LUA_HUD_AddFadeScreen( + huddrawlist_h list, + UINT16 color, + UINT8 strength +); + +// Draws the given draw list +void LUA_HUD_DrawList(huddrawlist_h list); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __LUA_HUDLIB_DRAWLIST__ diff --git a/src/r_main.c b/src/r_main.c index 896b6a29b..fa2313363 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -78,6 +78,7 @@ mobj_t *r_viewmobj; fixed_t rendertimefrac; fixed_t renderdeltatics; +boolean renderisnewtic; // // precalculated math tables diff --git a/src/r_main.h b/src/r_main.h index ccbc0ad8c..94103ceed 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -38,7 +38,9 @@ extern size_t validcount, linecount, loopcount, framecount; // The fraction of a tic being drawn (for interpolation between two tics) extern fixed_t rendertimefrac; // Evaluated delta tics for this frame (how many tics since the last frame) -extern fixed_t renderdeltatics;; +extern fixed_t renderdeltatics; +// The current render is a new logical tic +extern boolean renderisnewtic; // // Lighting LUT. diff --git a/src/st_stuff.c b/src/st_stuff.c index 6ab310252..fcdde5826 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -43,6 +43,7 @@ #endif #include "lua_hud.h" +#include "lua_hudlib_drawlist.h" #include "lua_hook.h" #include "r_fps.h" @@ -163,6 +164,9 @@ hudinfo_t hudinfo[NUMHUDITEMS] = { 288, 176, V_SNAPTORIGHT|V_SNAPTOBOTTOM}, // HUD_POWERUPS }; +static huddrawlist_h luahuddrawlist_game; +static huddrawlist_h luahuddrawlist_titlecard; + // // STATUS BAR CODE // @@ -422,6 +426,9 @@ void ST_Init(void) return; ST_LoadGraphics(); + + luahuddrawlist_game = LUA_HUD_CreateDrawList(); + luahuddrawlist_titlecard = LUA_HUD_CreateDrawList(); } // change the status bar too, when pressing F12 while viewing a demo. @@ -1404,7 +1411,12 @@ void ST_drawTitleCard(void) lt_lasttic = lt_ticker; luahook: - LUA_HUDHOOK(titlecard); + if (renderisnewtic) + { + LUA_HUD_ClearDrawList(luahuddrawlist_titlecard); + LUA_HUDHOOK(titlecard, luahuddrawlist_titlecard); + } + LUA_HUD_DrawList(luahuddrawlist_titlecard); } // @@ -2744,7 +2756,14 @@ static void ST_overlayDrawer(void) ST_drawPowerupHUD(); // same as it ever was... if (!(netgame || multiplayer) || !hu_showscores) - LUA_HUDHOOK(game); + { + if (renderisnewtic) + { + LUA_HUD_ClearDrawList(luahuddrawlist_game); + LUA_HUDHOOK(game, luahuddrawlist_game); + } + LUA_HUD_DrawList(luahuddrawlist_game); + } // draw level title Tails if (stagetitle && (!WipeInAction) && (!WipeStageTitle)) diff --git a/src/y_inter.c b/src/y_inter.c index 8b5c9efc7..4f7b0499d 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -38,6 +38,7 @@ #include "lua_hook.h" // IntermissionThinker hook #include "lua_hud.h" +#include "lua_hudlib_drawlist.h" #ifdef HWRENDER #include "hardware/hw_main.h" @@ -165,6 +166,8 @@ static INT32 endtic = -1; intertype_t intertype = int_none; intertype_t intermissiontypes[NUMGAMETYPES]; +static huddrawlist_h luahuddrawlist_intermission; + static void Y_RescaleScreenBuffer(void); static void Y_AwardCoopBonuses(void); static void Y_AwardSpecialStageBonus(void); @@ -433,7 +436,13 @@ void Y_IntermissionDrawer(void) else if (bgtile) V_DrawPatchFill(bgtile); - LUA_HUDHOOK(intermission); + if (renderisnewtic) + { + LUA_HUD_ClearDrawList(luahuddrawlist_intermission); + LUA_HUDHOOK(intermission, luahuddrawlist_intermission); + } + LUA_HUD_DrawList(luahuddrawlist_intermission); + if (!LUA_HudEnabled(hud_intermissiontally)) goto skiptallydrawer; @@ -1591,6 +1600,9 @@ void Y_StartIntermission(void) default: break; } + + LUA_HUD_DestroyDrawList(luahuddrawlist_intermission); + luahuddrawlist_intermission = LUA_HUD_CreateDrawList(); } // From a41d0428128f481a10b0193253ead4df8fa0ab89 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 30 Apr 2022 01:57:46 -0500 Subject: [PATCH 099/137] Rename drawerlib deltaTime to getDeltaTime --- src/lua_hudlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index d049bcfe2..0a4d0dcde 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1309,7 +1309,7 @@ static int libd_getusertransflag(lua_State *L) } // Return the time elapsed for the previous frame, in tics. -static int libd_deltaTime(lua_State *L) +static int libd_getDeltaTime(lua_State *L) { HUDONLY lua_pushfixed(L, renderdeltatics); @@ -1357,7 +1357,7 @@ static luaL_Reg lib_draw[] = { {"renderer", libd_renderer}, {"localTransFlag", libd_getlocaltransflag}, {"userTransFlag", libd_getusertransflag}, - {"deltaTime", libd_deltaTime}, + {"getDeltaTime", libd_getDeltaTime}, {NULL, NULL} }; From dcbe929baa76acce33f5ad287207adb729cd5422 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 30 Apr 2022 13:53:56 -0500 Subject: [PATCH 100/137] Make renderisnewtic is false between tics I know what I'm doing! I swear --- src/d_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/d_main.c b/src/d_main.c index 8b4de45e9..ec5b354cd 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -829,6 +829,10 @@ void D_SRB2Loop(void) renderisnewtic = true; } + else + { + renderisnewtic = false; + } if (interp) { From e79654a33ade129573495f4c573555a4a7d39018 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 30 Apr 2022 16:33:23 -0500 Subject: [PATCH 101/137] Completely refactor timing system Time is now tracked internally in the game using I_GetPreciseTime and I_UpdateTime. I_Time now pulls from this internal timer. The system code no longer needs to keep track of time itself. This significantly improves frame and tic timing in interp mode, resulting in a much smoother image with essentially no judder at any framerate. --- src/Sourcefile | 1 + src/android/i_system.c | 12 ------ src/d_clisrv.c | 1 + src/d_main.c | 68 ++++++++++++--------------------- src/d_net.c | 1 + src/d_netcmd.c | 1 + src/d_netfil.c | 1 + src/dummy/i_system.c | 10 ----- src/f_finale.c | 1 + src/f_wipe.c | 1 + src/g_demo.c | 1 + src/g_game.c | 1 + src/i_system.h | 12 ++---- src/i_time.c | 86 ++++++++++++++++++++++++++++++++++++++++++ src/i_time.h | 51 +++++++++++++++++++++++++ src/m_menu.c | 1 + src/m_misc.c | 1 + src/p_setup.c | 1 + src/screen.c | 1 + src/sdl/i_system.c | 56 ++++++--------------------- src/w_wad.c | 1 + src/win32/win_sys.c | 8 ++-- 22 files changed, 193 insertions(+), 124 deletions(-) create mode 100644 src/i_time.c create mode 100644 src/i_time.h diff --git a/src/Sourcefile b/src/Sourcefile index fa82f86da..de90bb609 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -18,6 +18,7 @@ am_map.c command.c console.c hu_stuff.c +i_time.c y_inter.c st_stuff.c m_aatree.c diff --git a/src/android/i_system.c b/src/android/i_system.c index 7256bac34..e6e840ac0 100644 --- a/src/android/i_system.c +++ b/src/android/i_system.c @@ -82,18 +82,6 @@ INT64 current_time_in_ps() { return (t.tv_sec * (INT64)1000000) + t.tv_usec; } -tic_t I_GetTime(void) -{ - INT64 since_start = current_time_in_ps() - start_time; - return (since_start*TICRATE)/1000000; -} - -fixed_t I_GetTimeFrac(void) -{ - //stub - return 0; -} - void I_Sleep(void){} void I_GetEvent(void){} diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 74f3dd959..ac0ccc054 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -15,6 +15,7 @@ #include //for unlink #endif +#include "i_time.h" #include "i_net.h" #include "i_system.h" #include "i_video.h" diff --git a/src/d_main.c b/src/d_main.c index ec5b354cd..b2f10988a 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -40,6 +40,7 @@ #include "hu_stuff.h" #include "i_sound.h" #include "i_system.h" +#include "i_time.h" #include "i_threads.h" #include "i_video.h" #include "m_argv.h" @@ -695,10 +696,9 @@ tic_t rendergametic; void D_SRB2Loop(void) { - tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS; + tic_t realtics = 0, rendertimeout = INFTICS; static lumpnum_t gstartuplumpnum; - boolean ticked = false; boolean interp = false; boolean doDisplay = false; boolean screenUpdate = false; @@ -715,7 +715,7 @@ void D_SRB2Loop(void) I_DoStartupMouse(); #endif - oldentertics = I_GetTime(); + I_UpdateTime(cv_timescale.value); // end of loading screen: CONS_Printf() will no more call FinishUpdate() con_refresh = false; @@ -757,17 +757,18 @@ void D_SRB2Loop(void) { frameEnd = I_GetFrameTime(); + I_UpdateTime(cv_timescale.value); + + // Can't guarantee that I_UpdateTime won't be called inside TryRunTics + // so capture the realtics for later use + realtics = g_time.realtics; + if (lastwipetic) { - oldentertics = lastwipetic; + // oldentertics = lastwipetic; lastwipetic = 0; } - // get real tics - entertic = I_GetTime(); - realtics = entertic - oldentertics; - oldentertics = entertic; - if (demoplayback && gamestate == GS_LEVEL) { // Nicer place to put this. @@ -782,7 +783,6 @@ void D_SRB2Loop(void) interp = R_UsingFrameInterpolation() && !dedicated; doDisplay = screenUpdate = false; - ticked = false; #ifdef HW3SOUND HW3S_BeginFrameUpdate(); @@ -798,16 +798,16 @@ void D_SRB2Loop(void) realtics = 1; // process tics (but maybe not if realtic == 0) - ticked = TryRunTics(realtics); + TryRunTics(realtics); if (lastdraw || singletics || gametic > rendergametic) { rendergametic = gametic; - rendertimeout = entertic+TICRATE/17; + rendertimeout = g_time.time + TICRATE/17; doDisplay = true; } - else if (rendertimeout < entertic) // in case the server hang or netsplit + else if (rendertimeout < g_time.time) // in case the server hang or netsplit { // Lagless camera! Yay! if (gamestate == GS_LEVEL && netgame) @@ -836,41 +836,21 @@ void D_SRB2Loop(void) if (interp) { - static float tictime = 0.0f; - static float prevtime = 0.0f; - float entertime = I_GetTimeFrac(); - - fixed_t entertimefrac = FRACUNIT; - - if (ticked) - { - tictime = entertime; - } - // I looked at the possibility of putting in a float drawer for // perfstats and it's very complicated, so we'll just do this instead... - ps_interp_frac.value.p = (precise_t)((entertime - tictime) * 1000.0f); - ps_interp_lag.value.p = (precise_t)((entertime - prevtime) * 1000.0f); + ps_interp_frac.value.p = (precise_t)((FIXED_TO_FLOAT(g_time.timefrac)) * 1000.0f); + ps_interp_lag.value.p = (precise_t)((FIXED_TO_FLOAT(g_time.deltaseconds)) * 1000.0f); + + renderdeltatics = g_time.deltatics; if (!(paused || P_AutoPause())) { - if (entertime - prevtime >= 1.0f) - { - // Lagged for more frames than a gametic... - // No need for interpolation. - entertimefrac = FRACUNIT; - } - else - { - entertimefrac = min(FRACUNIT, FLOAT_TO_FIXED(entertime - tictime)); - } - - // renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based - renderdeltatics = FloatToFixed(entertime - prevtime); - rendertimefrac = entertimefrac; + rendertimefrac = g_time.timefrac; + } + else + { + rendertimefrac = FRACUNIT; } - - prevtime = entertime; } else { @@ -1398,8 +1378,8 @@ void D_SRB2Main(void) //---------------------------------------------------- READY TIME // we need to check for dedicated before initialization of some subsystems - CONS_Printf("I_StartupTimer()...\n"); - I_StartupTimer(); + CONS_Printf("I_InitializeTime()...\n"); + I_InitializeTime(); // Make backups of some SOCcable tables. P_BackupTables(); diff --git a/src/d_net.c b/src/d_net.c index 5e5c10889..c2a86481f 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -18,6 +18,7 @@ #include "doomdef.h" #include "g_game.h" +#include "i_time.h" #include "i_net.h" #include "i_system.h" #include "m_argv.h" diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9b14e0913..024f4fede 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -16,6 +16,7 @@ #include "console.h" #include "command.h" +#include "i_time.h" #include "i_system.h" #include "g_game.h" #include "hu_stuff.h" diff --git a/src/d_netfil.c b/src/d_netfil.c index 37fb7265f..edbef30bb 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -35,6 +35,7 @@ #include "doomstat.h" #include "d_main.h" #include "g_game.h" +#include "i_time.h" #include "i_net.h" #include "i_system.h" #include "m_argv.h" diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c index f3d0bc5e8..d11e8e576 100644 --- a/src/dummy/i_system.c +++ b/src/dummy/i_system.c @@ -11,16 +11,6 @@ UINT32 I_GetFreeMem(UINT32 *total) return 0; } -tic_t I_GetTime(void) -{ - return 0; -} - -fixed_t I_GetTimeFrac(void) -{ - return 0; -} - void I_Sleep(void){} void I_GetEvent(void){} diff --git a/src/f_finale.c b/src/f_finale.c index 4ddcaff5f..a26600101 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -20,6 +20,7 @@ #include "hu_stuff.h" #include "r_local.h" #include "s_sound.h" +#include "i_time.h" #include "i_video.h" #include "v_video.h" #include "w_wad.h" diff --git a/src/f_wipe.c b/src/f_wipe.c index 43b7180b7..612d2ab83 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -24,6 +24,7 @@ #include "w_wad.h" #include "z_zone.h" +#include "i_time.h" #include "i_system.h" #include "i_threads.h" #include "m_menu.h" diff --git a/src/g_demo.c b/src/g_demo.c index 7a7236945..9a0d5a293 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -17,6 +17,7 @@ #include "d_player.h" #include "d_clisrv.h" #include "p_setup.h" +#include "i_time.h" #include "i_system.h" #include "m_random.h" #include "p_local.h" diff --git a/src/g_game.c b/src/g_game.c index 8eb731b1f..dfc5fadd5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -19,6 +19,7 @@ #include "f_finale.h" #include "p_setup.h" #include "p_saveg.h" +#include "i_time.h" #include "i_system.h" #include "am_map.h" #include "m_random.h" diff --git a/src/i_system.h b/src/i_system.h index f607ec79c..bf4627d54 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -42,14 +42,6 @@ extern UINT8 keyboard_started; */ UINT32 I_GetFreeMem(UINT32 *total); -/** \brief Called by D_SRB2Loop, returns current time in game tics. -*/ -tic_t I_GetTime(void); - -/** \brief Get the current time in game tics, including fractions. -*/ -float I_GetTimeFrac(void); - /** \brief Returns precise time value for performance measurement. */ precise_t I_GetPreciseTime(void); @@ -58,6 +50,10 @@ precise_t I_GetPreciseTime(void); */ int I_PreciseToMicros(precise_t d); +/** \brief Calculates the elapsed microseconds between two precise_t. + */ +double I_PreciseElapsedSeconds(precise_t before, precise_t after); + /** \brief Get the current time in rendering tics, including fractions. */ double I_GetFrameTime(void); diff --git a/src/i_time.c b/src/i_time.c new file mode 100644 index 000000000..93f9b3410 --- /dev/null +++ b/src/i_time.c @@ -0,0 +1,86 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file i_time.c +/// \brief Timing for the system layer. + +#include "i_time.h" + +#include "command.h" +#include "doomtype.h" +#include "m_fixed.h" +#include "i_system.h" + +timestate_t g_time; + +static CV_PossibleValue_t timescale_cons_t[] = {{FRACUNIT/20, "MIN"}, {20*FRACUNIT, "MAX"}, {0, NULL}}; +consvar_t cv_timescale = CVAR_INIT ("timescale", "1.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, timescale_cons_t, NULL); + +static precise_t enterprecise, oldenterprecise; +static fixed_t entertic, oldentertics; +static double tictimer; + +tic_t I_GetTime(void) +{ + return g_time.time; +} + +void I_InitializeTime(void) +{ + g_time.time = 0; + g_time.timefrac = 0; + g_time.realtics = 0; + g_time.deltaseconds = 0; + g_time.ticrate = FLOAT_TO_FIXED(TICRATE); + + enterprecise = 0; + oldenterprecise = 0; + tictimer = 0.0; + + CV_RegisterVar(&cv_timescale); + + // I_StartupTimer is preserved for potential subsystems that need to setup + // timing information for I_GetPreciseTime and sleeping + I_StartupTimer(); +} + +void I_UpdateTime(fixed_t timescale) +{ + double ticratescaled; + double elapsedseconds; + tic_t realtics; + + // get real tics + ticratescaled = (double)TICRATE * FIXED_TO_FLOAT(timescale); + + enterprecise = I_GetPreciseTime(); + elapsedseconds = I_PreciseElapsedSeconds(oldenterprecise, enterprecise); + tictimer += elapsedseconds; + while (tictimer > 1.0/ticratescaled) + { + entertic += 1; + tictimer -= 1.0/ticratescaled; + } + realtics = entertic - oldentertics; + oldentertics = entertic; + oldenterprecise = enterprecise; + + // Update global time state + g_time.time += realtics; + { + double fractional, integral; + fractional = modf(tictimer * ticratescaled, &integral); + g_time.timefrac = FLOAT_TO_FIXED(fractional); + } + g_time.realtics = realtics; + g_time.deltatics = FLOAT_TO_FIXED(elapsedseconds * ticratescaled); + g_time.deltaseconds = FLOAT_TO_FIXED(elapsedseconds); + g_time.ticrate = FLOAT_TO_FIXED(ticratescaled); +} diff --git a/src/i_time.h b/src/i_time.h new file mode 100644 index 000000000..077174756 --- /dev/null +++ b/src/i_time.h @@ -0,0 +1,51 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file i_time.h +/// \brief Timing for the system layer. + +#ifndef __I_TIME_H__ +#define __I_TIME_H__ + +#include "command.h" +#include "doomtype.h" +#include "m_fixed.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct timestate_s { + tic_t time; + fixed_t timefrac; + fixed_t realtics; + fixed_t deltatics; + fixed_t deltaseconds; + fixed_t ticrate; +} timestate_t; + +extern timestate_t g_time; +extern consvar_t cv_timescale; + +/** \brief Called by D_SRB2Loop, returns current time in game tics. +*/ +tic_t I_GetTime(void); + +/** \brief Initializes timing system. +*/ +void I_InitializeTime(void); + +void I_UpdateTime(fixed_t timescale); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __I_TIME_H__ diff --git a/src/m_menu.c b/src/m_menu.c index d32782ed1..0c0f90386 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -32,6 +32,7 @@ // Data. #include "sounds.h" #include "s_sound.h" +#include "i_time.h" #include "i_system.h" #include "i_threads.h" diff --git a/src/m_misc.c b/src/m_misc.c index d7d6d6bbb..a400865f3 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -36,6 +36,7 @@ #include "v_video.h" #include "z_zone.h" #include "g_input.h" +#include "i_time.h" #include "i_video.h" #include "d_main.h" #include "m_argv.h" diff --git a/src/p_setup.c b/src/p_setup.c index 0e7432bbf..20c6952d9 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -21,6 +21,7 @@ #include "p_spec.h" #include "p_saveg.h" +#include "i_time.h" #include "i_sound.h" // for I_PlayCD().. #include "i_video.h" // for I_FinishUpdate().. #include "r_sky.h" diff --git a/src/screen.c b/src/screen.c index 6ad36273b..62b1fe05c 100644 --- a/src/screen.c +++ b/src/screen.c @@ -15,6 +15,7 @@ #include "screen.h" #include "console.h" #include "am_map.h" +#include "i_time.h" #include "i_system.h" #include "i_video.h" #include "r_local.h" diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index afd13910c..de7369236 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -170,6 +170,7 @@ static char returnWadPath[256]; #include "../doomdef.h" #include "../m_misc.h" +#include "../i_time.h" #include "../i_video.h" #include "../i_sound.h" #include "../i_system.h" @@ -2143,44 +2144,6 @@ ticcmd_t *I_BaseTiccmd2(void) static Uint64 timer_frequency; -static double tic_frequency; -static Uint64 tic_epoch; -static double elapsed_tics; - -static void UpdateTicFreq(void) -{ - tic_frequency = (timer_frequency / (double)NEWTICRATE) / FixedToFloat(cv_timescale.value); -} - -static CV_PossibleValue_t timescale_cons_t[] = {{FRACUNIT/20, "MIN"}, {20*FRACUNIT, "MAX"}, {0, NULL}}; -consvar_t cv_timescale = CVAR_INIT ("timescale", "1.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_CALL, timescale_cons_t, UpdateTicFreq); - -static void UpdateElapsedTics(void) -{ - const Uint64 now = SDL_GetPerformanceCounter(); - - elapsed_tics += (now - tic_epoch) / tic_frequency; - tic_epoch = now; // moving epoch -} - -tic_t I_GetTime(void) -{ - float f = 0.0f; - - UpdateElapsedTics(); - - // This needs kept in a separate variable before converting - // to tic_t, due to stupid -Wbad-function-cast error. - f = floor(elapsed_tics); - return (tic_t)f; -} - -float I_GetTimeFrac(void) -{ - UpdateElapsedTics(); - return elapsed_tics; -} - // // I_GetPreciseTime // returns time in precise_t @@ -2201,6 +2164,11 @@ int I_PreciseToMicros(precise_t d) return (int)(UINT64)(d / (timer_frequency / 1000000.0)); } +double I_PreciseElapsedSeconds(precise_t before, precise_t after) +{ + return (after - before) / (double)timer_frequency; +} + // // I_GetFrameTime // returns time in 1/fpscap second tics @@ -2259,15 +2227,9 @@ double I_GetFrameTime(void) // void I_StartupTimer(void) { - CV_RegisterVar(&cv_timescale); - timer_frequency = SDL_GetPerformanceFrequency(); - tic_epoch = SDL_GetPerformanceCounter(); - tic_frequency = timer_frequency / (double)NEWTICRATE; - elapsed_tics = 0.0; - - I_InitFrameTime(tic_epoch, R_GetFramerateCap()); + I_InitFrameTime(0, R_GetFramerateCap()); elapsed_frames = 0.0; } @@ -2279,6 +2241,10 @@ void I_Sleep(void) { if (cv_sleep.value > 0) SDL_Delay(cv_sleep.value); + + // I_Sleep is still called in a number of places + // we need to update the internal time state to make this work + I_UpdateTime(cv_timescale.value); } // diff --git a/src/w_wad.c b/src/w_wad.c index 0a8f630a8..b24614647 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -59,6 +59,7 @@ #include "r_textures.h" #include "r_patch.h" #include "r_picformats.h" +#include "i_time.h" #include "i_system.h" #include "i_video.h" // rendermode #include "md5.h" diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 393b913da..7e6f82a29 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -35,6 +35,7 @@ #include #include "../m_misc.h" +#include "../i_time.h" #include "../i_video.h" #include "../i_sound.h" #include "../i_system.h" @@ -262,15 +263,12 @@ tic_t I_GetTime(void) return newtics; } -fixed_t I_GetTimeFrac(void) -{ - return 0; -} - void I_Sleep(void) { if (cv_sleep.value != -1) Sleep(cv_sleep.value); + + I_UpdateTime(cv_timescale.value); } // should move to i_video From c0865e4faacf9627dd953c49f37077217d0cceb5 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 30 Apr 2022 17:59:32 -0500 Subject: [PATCH 102/137] Ensure mobj interpolators reset on level load --- src/p_setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_setup.c b/src/p_setup.c index 20c6952d9..8fbd2e4ae 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4487,6 +4487,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (rendermode != render_none) { R_ResetViewInterpolation(); + R_UpdateMobjInterpolators(); + R_UpdateMobjInterpolators(); } // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap... From 48d8c835407d7f5eb43cfcc1467e74b35eda27df Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 30 Apr 2022 19:10:07 -0500 Subject: [PATCH 103/137] Ensure view is not interpolated on first frame --- src/p_setup.c | 11 ++++------- src/r_fps.c | 8 ++++---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 8fbd2e4ae..267bcc175 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4484,13 +4484,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_MapEnd(); // tmthing is no longer needed from this point onwards - if (rendermode != render_none) - { - R_ResetViewInterpolation(); - R_UpdateMobjInterpolators(); - R_UpdateMobjInterpolators(); - } - // Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap... if (!titlemapinaction) { @@ -4519,6 +4512,10 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_MapEnd(); // just in case MapLoad modifies tmthing } + R_ResetViewInterpolation(); + R_ResetViewInterpolation(); + R_UpdateMobjInterpolators(); + // No render mode or reloading gamestate, stop here. if (rendermode == render_none || reloadinggamestate) return true; diff --git a/src/r_fps.c b/src/r_fps.c index b4ec5439c..008ed07d5 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -83,7 +83,7 @@ static viewvars_t sky2view_old; static viewvars_t sky2view_new; static viewvars_t *oldview = &p1view_old; -static boolean oldview_valid = false; +static int oldview_invalid = 0; viewvars_t *newview = &p1view_new; @@ -165,7 +165,7 @@ void R_InterpolateView(fixed_t frac) if (frac > FRACUNIT) frac = FRACUNIT; - if (oldview_valid == false) + if (oldview_invalid != 0) { // interpolate from newview to newview prevview = newview; @@ -201,12 +201,12 @@ void R_UpdateViewInterpolation(void) p2view_old = p2view_new; sky1view_old = sky1view_new; sky2view_old = sky2view_new; - oldview_valid = true; + if (oldview_invalid) oldview_invalid--; } void R_ResetViewInterpolation(void) { - oldview_valid = false; + oldview_invalid++; } void R_SetViewContext(enum viewcontext_e _viewcontext) From 7d7564b7f945d0eb26b968ec90a301ea2a8bd019 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 30 Apr 2022 21:56:42 -0500 Subject: [PATCH 104/137] Disable sprite offset interpolation (for now) --- src/r_fps.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/r_fps.c b/src/r_fps.c index 008ed07d5..10e3cc10b 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -284,8 +284,11 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out) out->scale = mobj->resetinterp ? mobj->scale : R_LerpFixed(mobj->old_scale, mobj->scale, frac); out->spritexscale = mobj->resetinterp ? mobj->spritexscale : R_LerpFixed(mobj->old_spritexscale, mobj->spritexscale, frac); out->spriteyscale = mobj->resetinterp ? mobj->spriteyscale : R_LerpFixed(mobj->old_spriteyscale, mobj->spriteyscale, frac); - out->spritexoffset = mobj->resetinterp ? mobj->spritexoffset : R_LerpFixed(mobj->old_spritexoffset, mobj->spritexoffset, frac); - out->spriteyoffset = mobj->resetinterp ? mobj->spriteyoffset : R_LerpFixed(mobj->old_spriteyoffset, mobj->spriteyoffset, frac); + + // Sprite offsets are not interpolated until we have a way to interpolate them explicitly in Lua. + // It seems existing mods visually break more often than not if it is interpolated. + out->spritexoffset = mobj->spritexoffset; + out->spriteyoffset = mobj->spriteyoffset; out->subsector = R_PointInSubsector(out->x, out->y); From f0d7d8467f2b7a3e7169c8522dccddca07f60f9d Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sun, 1 May 2022 00:32:46 -0500 Subject: [PATCH 105/137] Refactor timing code even more System layer is greatly simplified and framecap logic has been moved internally. I_Sleep now takes a sleep duration and I_SleepDuration generically implements a precise sleep with spin loop. --- src/android/i_system.c | 12 +++++- src/d_clisrv.c | 5 ++- src/d_main.c | 58 +++++++++++++++++++--------- src/d_net.c | 5 ++- src/dummy/i_system.c | 10 ++++- src/f_finale.c | 5 ++- src/f_wipe.c | 5 ++- src/g_game.c | 5 ++- src/i_system.h | 29 +++++++------- src/i_time.c | 47 +++++++++++++++++++---- src/i_time.h | 11 ++++-- src/lua_baselib.c | 4 +- src/m_anigif.c | 4 +- src/m_menu.c | 3 +- src/m_perfstats.c | 8 ++-- src/p_setup.c | 5 ++- src/screen.c | 4 +- src/sdl/i_system.c | 87 ++---------------------------------------- src/win32/win_sys.c | 21 ++++++++-- 19 files changed, 176 insertions(+), 152 deletions(-) diff --git a/src/android/i_system.c b/src/android/i_system.c index e6e840ac0..1fba4d825 100644 --- a/src/android/i_system.c +++ b/src/android/i_system.c @@ -82,7 +82,17 @@ INT64 current_time_in_ps() { return (t.tv_sec * (INT64)1000000) + t.tv_usec; } -void I_Sleep(void){} +void I_Sleep(UINT32 ms){} + +precise_t I_GetPreciseTime(void) +{ + return 0; +} + +UINT64 I_GetPrecisePrecision(void) +{ + return 1000000; +} void I_GetEvent(void){} diff --git a/src/d_clisrv.c b/src/d_clisrv.c index ac0ccc054..3068f2314 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2442,7 +2442,10 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic #endif } else - I_Sleep(); + { + I_Sleep(cv_sleep.value); + I_UpdateTime(cv_timescale.value); + } return true; } diff --git a/src/d_main.c b/src/d_main.c index b2f10988a..3f539128e 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -696,15 +696,15 @@ tic_t rendergametic; void D_SRB2Loop(void) { - tic_t realtics = 0, rendertimeout = INFTICS; + tic_t entertic = 0, oldentertics = 0, realtics = 0, rendertimeout = INFTICS; + double deltatics = 0.0; + double deltasecs = 0.0; static lumpnum_t gstartuplumpnum; boolean interp = false; boolean doDisplay = false; boolean screenUpdate = false; - double frameEnd = 0.0; - if (dedicated) server = true; @@ -716,6 +716,7 @@ void D_SRB2Loop(void) #endif I_UpdateTime(cv_timescale.value); + oldentertics = I_GetTime(); // end of loading screen: CONS_Printf() will no more call FinishUpdate() con_refresh = false; @@ -755,20 +756,30 @@ void D_SRB2Loop(void) for (;;) { - frameEnd = I_GetFrameTime(); + // capbudget is the minimum precise_t duration of a single loop iteration + precise_t capbudget; + precise_t enterprecise = I_GetPreciseTime(); + precise_t finishprecise = enterprecise; + + { + // Casting the return value of a function is bad practice (apparently) + double budget = round((1.0 / R_GetFramerateCap()) * I_GetPrecisePrecision()); + capbudget = (precise_t) budget; + } I_UpdateTime(cv_timescale.value); - // Can't guarantee that I_UpdateTime won't be called inside TryRunTics - // so capture the realtics for later use - realtics = g_time.realtics; - if (lastwipetic) { - // oldentertics = lastwipetic; + oldentertics = lastwipetic; lastwipetic = 0; } + // get real tics + entertic = I_GetTime(); + realtics = entertic - oldentertics; + oldentertics = entertic; + if (demoplayback && gamestate == GS_LEVEL) { // Nicer place to put this. @@ -803,11 +814,11 @@ void D_SRB2Loop(void) if (lastdraw || singletics || gametic > rendergametic) { rendergametic = gametic; - rendertimeout = g_time.time + TICRATE/17; + rendertimeout = entertic + TICRATE/17; doDisplay = true; } - else if (rendertimeout < g_time.time) // in case the server hang or netsplit + else if (rendertimeout < entertic) // in case the server hang or netsplit { // Lagless camera! Yay! if (gamestate == GS_LEVEL && netgame) @@ -839,9 +850,9 @@ void D_SRB2Loop(void) // I looked at the possibility of putting in a float drawer for // perfstats and it's very complicated, so we'll just do this instead... ps_interp_frac.value.p = (precise_t)((FIXED_TO_FLOAT(g_time.timefrac)) * 1000.0f); - ps_interp_lag.value.p = (precise_t)((FIXED_TO_FLOAT(g_time.deltaseconds)) * 1000.0f); + ps_interp_lag.value.p = (precise_t)((deltasecs) * 1000.0f); - renderdeltatics = g_time.deltatics; + renderdeltatics = FLOAT_TO_FIXED(deltatics); if (!(paused || P_AutoPause())) { @@ -873,12 +884,6 @@ void D_SRB2Loop(void) LUA_Step(); - // Fully completed frame made. - if (!singletics) - { - I_FrameCapSleep(frameEnd); - } - // I_FinishUpdate is now here instead of D_Display, // because it synchronizes it more closely with the frame counter. if (screenUpdate == true) @@ -888,6 +893,21 @@ void D_SRB2Loop(void) PS_STOP_TIMING(ps_swaptime); } + // Fully completed frame made. + finishprecise = I_GetPreciseTime(); + if (!singletics) + { + INT64 elapsed = (INT64)(finishprecise - enterprecise); + if (elapsed > 0 && (INT64)capbudget > elapsed) + { + I_SleepDuration(capbudget - (finishprecise - enterprecise)); + } + } + // Capture the time once more to get the real delta time. + finishprecise = I_GetPreciseTime(); + deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision(); + deltatics = deltasecs * NEWTICRATE; + // Only take screenshots after drawing. if (moviemode) M_SaveFrame(); diff --git a/src/d_net.c b/src/d_net.c index c2a86481f..a7e1eb16d 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -615,7 +615,10 @@ void Net_WaitAllAckReceived(UINT32 timeout) while (timeout > I_GetTime() && !Net_AllAcksReceived()) { while (tictac == I_GetTime()) - I_Sleep(); + { + I_Sleep(cv_sleep.value); + I_UpdateTime(cv_timescale.value); + } tictac = I_GetTime(); HGetPacket(); Net_AckTicker(); diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c index d11e8e576..34fb587ab 100644 --- a/src/dummy/i_system.c +++ b/src/dummy/i_system.c @@ -11,7 +11,15 @@ UINT32 I_GetFreeMem(UINT32 *total) return 0; } -void I_Sleep(void){} +void I_Sleep(UINT32 ms){} + +precise_t I_GetPreciseTime(void) { + return 0; +} + +UINT64 I_GetPrecisePrecision(void) { + return 1000000; +} void I_GetEvent(void){} diff --git a/src/f_finale.c b/src/f_finale.c index a26600101..1fb078b64 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -915,7 +915,10 @@ void F_IntroTicker(void) while (quittime > nowtime) { while (!((nowtime = I_GetTime()) - lasttime)) - I_Sleep(); + { + I_Sleep(cv_sleep.value); + I_UpdateTime(cv_timescale.value); + } lasttime = nowtime; I_OsPolling(); diff --git a/src/f_wipe.c b/src/f_wipe.c index 612d2ab83..ab869ca60 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -556,7 +556,10 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) // wait loop while (!((nowtime = I_GetTime()) - lastwipetic)) - I_Sleep(); + { + I_Sleep(cv_sleep.value); + I_UpdateTime(cv_timescale.value); + } lastwipetic = nowtime; // Wipe styles diff --git a/src/g_game.c b/src/g_game.c index dfc5fadd5..1ea75844d 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1905,7 +1905,10 @@ void G_PreLevelTitleCard(void) { // draw loop while (!((nowtime = I_GetTime()) - lasttime)) - I_Sleep(); + { + I_Sleep(cv_sleep.value); + I_UpdateTime(cv_timescale.value); + } lasttime = nowtime; ST_runTitleCard(); diff --git a/src/i_system.h b/src/i_system.h index bf4627d54..7153aa735 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -42,33 +42,32 @@ extern UINT8 keyboard_started; */ UINT32 I_GetFreeMem(UINT32 *total); -/** \brief Returns precise time value for performance measurement. +/** \brief Returns precise time value for performance measurement. The precise + time should be a monotonically increasing counter, and will wrap. + precise_t is internally represented as an unsigned integer and + integer arithmetic may be used directly between values of precise_t. */ precise_t I_GetPreciseTime(void); -/** \brief Converts a precise_t to microseconds and casts it to a 32 bit integer. +/** \brief Get the precision of precise_t in units per second. Invocations of + this function for the program's duration MUST return the same value. */ -int I_PreciseToMicros(precise_t d); - -/** \brief Calculates the elapsed microseconds between two precise_t. - */ -double I_PreciseElapsedSeconds(precise_t before, precise_t after); +UINT64 I_GetPrecisePrecision(void); /** \brief Get the current time in rendering tics, including fractions. */ double I_GetFrameTime(void); -/** \brief Sleeps by the value of cv_sleep +/** \brief Sleeps for the given duration in milliseconds. Depending on the + operating system's scheduler, the calling thread may give up its + time slice for a longer duration. The implementation should give a + best effort to sleep for the given duration, without spin-locking. + Calling code should check the current precise time after sleeping + and not assume the thread has slept for the expected duration. \return void */ -void I_Sleep(void); - -/** \brief Sleeps for a variable amount of time, depending on how much time the last frame took. - - \return void -*/ -boolean I_FrameCapSleep(const double frameStart); +void I_Sleep(UINT32 ms); /** \brief Get events diff --git a/src/i_time.c b/src/i_time.c index 93f9b3410..c86973f6e 100644 --- a/src/i_time.c +++ b/src/i_time.c @@ -13,8 +13,11 @@ #include "i_time.h" +#include + #include "command.h" #include "doomtype.h" +#include "d_netcmd.h" #include "m_fixed.h" #include "i_system.h" @@ -36,9 +39,6 @@ void I_InitializeTime(void) { g_time.time = 0; g_time.timefrac = 0; - g_time.realtics = 0; - g_time.deltaseconds = 0; - g_time.ticrate = FLOAT_TO_FIXED(TICRATE); enterprecise = 0; oldenterprecise = 0; @@ -61,7 +61,7 @@ void I_UpdateTime(fixed_t timescale) ticratescaled = (double)TICRATE * FIXED_TO_FLOAT(timescale); enterprecise = I_GetPreciseTime(); - elapsedseconds = I_PreciseElapsedSeconds(oldenterprecise, enterprecise); + elapsedseconds = (double)(enterprecise - oldenterprecise) / I_GetPrecisePrecision(); tictimer += elapsedseconds; while (tictimer > 1.0/ticratescaled) { @@ -79,8 +79,39 @@ void I_UpdateTime(fixed_t timescale) fractional = modf(tictimer * ticratescaled, &integral); g_time.timefrac = FLOAT_TO_FIXED(fractional); } - g_time.realtics = realtics; - g_time.deltatics = FLOAT_TO_FIXED(elapsedseconds * ticratescaled); - g_time.deltaseconds = FLOAT_TO_FIXED(elapsedseconds); - g_time.ticrate = FLOAT_TO_FIXED(ticratescaled); +} + +void I_SleepDuration(precise_t duration) +{ + UINT64 precision = I_GetPrecisePrecision(); + INT32 sleepvalue = cv_sleep.value; + UINT64 delaygranularity; + precise_t cur; + precise_t dest; + + { + double gran = round(((double)(precision / 1000) * sleepvalue * 2.1)); + delaygranularity = (UINT64)gran; + } + + cur = I_GetPreciseTime(); + dest = cur + duration; + + // the reason this is not dest > cur is because the precise counter may wrap + // two's complement arithmetic is our friend here, though! + // e.g. cur 0xFFFFFFFFFFFFFFFE = -2, dest 0x0000000000000001 = 1 + // 0x0000000000000001 - 0xFFFFFFFFFFFFFFFE = 3 + while ((INT64)(dest - cur) > 0) + { + // If our cv_sleep value exceeds the remaining sleep duration, use the + // hard sleep function. + if (sleepvalue > 0 && (dest - cur) > delaygranularity) + { + I_Sleep(sleepvalue); + } + + // Otherwise, this is a spinloop. + + cur = I_GetPreciseTime(); + } } diff --git a/src/i_time.h b/src/i_time.h index 077174756..cab36133b 100644 --- a/src/i_time.h +++ b/src/i_time.h @@ -25,10 +25,6 @@ extern "C" { typedef struct timestate_s { tic_t time; fixed_t timefrac; - fixed_t realtics; - fixed_t deltatics; - fixed_t deltaseconds; - fixed_t ticrate; } timestate_t; extern timestate_t g_time; @@ -44,6 +40,13 @@ void I_InitializeTime(void); void I_UpdateTime(fixed_t timescale); +/** \brief Block for at minimum the duration specified. This function makes a + best effort not to oversleep, and will spinloop if sleeping would + take too long. However, callers should still check the current time + after this returns. +*/ +void I_SleepDuration(precise_t duration); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/lua_baselib.c b/src/lua_baselib.c index d06badc12..c53c83d0c 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -31,7 +31,7 @@ #include "m_misc.h" // M_MapNumber #include "b_bot.h" // B_UpdateBotleader #include "d_clisrv.h" // CL_RemovePlayer -#include "i_system.h" // I_GetPreciseTime, I_PreciseToMicros +#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision #include "lua_script.h" #include "lua_libs.h" @@ -3917,7 +3917,7 @@ static int lib_gTicsToMilliseconds(lua_State *L) static int lib_getTimeMicros(lua_State *L) { - lua_pushinteger(L, I_PreciseToMicros(I_GetPreciseTime())); + lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000)); return 1; } diff --git a/src/m_anigif.c b/src/m_anigif.c index b3a1d0fe2..41765e6e1 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -608,7 +608,7 @@ static void GIF_framewrite(void) { // golden's attempt at creating a "dynamic delay" UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise). - gif_delayus += I_PreciseToMicros(I_GetPreciseTime() - gif_prevframetime); // increase delay by how much time was spent between last measurement + gif_delayus += (I_GetPreciseTime() - gif_prevframetime) / (I_GetPrecisePrecision() / 1000000); // increase delay by how much time was spent between last measurement if (gif_delayus/1000 >= mingifdelay) // delay is big enough to be able to effect gif frame delay? { @@ -621,7 +621,7 @@ static void GIF_framewrite(void) { float delayf = ceil(100.0f/NEWTICRATE); - delay = (UINT16)I_PreciseToMicros((I_GetPreciseTime() - gif_prevframetime))/10/1000; + delay = (UINT16)((I_GetPreciseTime() - gif_prevframetime)) / (I_GetPrecisePrecision() / 1000000) /10/1000; if (delay < (UINT16)(delayf)) delay = (UINT16)(delayf); diff --git a/src/m_menu.c b/src/m_menu.c index 0c0f90386..ecbebe5f4 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -13569,7 +13569,8 @@ void M_QuitResponse(INT32 ch) { V_DrawScaledPatch(0, 0, 0, W_CachePatchName("GAMEQUIT", PU_PATCH)); // Demo 3 Quit Screen Tails 06-16-2001 I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001 - I_Sleep(); + I_Sleep(cv_sleep.value); + I_UpdateTime(cv_timescale.value); } } I_Quit(); diff --git a/src/m_perfstats.c b/src/m_perfstats.c index f58959f1d..9f65a7616 100644 --- a/src/m_perfstats.c +++ b/src/m_perfstats.c @@ -268,7 +268,7 @@ static INT32 PS_GetMetricAverage(ps_metric_t *metric, boolean time_metric) for (i = 0; i < cv_ps_samplesize.value; i++) { if (time_metric) - sum += I_PreciseToMicros(*((precise_t*)history_read_pos)); + sum += (*((precise_t*)history_read_pos)) / (I_GetPrecisePrecision() / 1000000); else sum += *((INT32*)history_read_pos); history_read_pos += value_size; @@ -288,7 +288,7 @@ static INT32 PS_GetMetricMinOrMax(ps_metric_t *metric, boolean time_metric, bool { INT32 value; if (time_metric) - value = I_PreciseToMicros(*((precise_t*)history_read_pos)); + value = (*((precise_t*)history_read_pos)) / (I_GetPrecisePrecision() / 1000000); else value = *((INT32*)history_read_pos); @@ -316,7 +316,7 @@ static INT32 PS_GetMetricSD(ps_metric_t *metric, boolean time_metric) { INT64 value; if (time_metric) - value = I_PreciseToMicros(*((precise_t*)history_read_pos)); + value = (*((precise_t*)history_read_pos)) / (I_GetPrecisePrecision() / 1000000); else value = *((INT32*)history_read_pos); @@ -346,7 +346,7 @@ static INT32 PS_GetMetricScreenValue(ps_metric_t *metric, boolean time_metric) else { if (time_metric) - return I_PreciseToMicros(metric->value.p); + return (metric->value.p) / (I_GetPrecisePrecision() / 1000000); else return metric->value.i; } diff --git a/src/p_setup.c b/src/p_setup.c index 267bcc175..7730a099f 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -4072,7 +4072,10 @@ static void P_RunSpecialStageWipe(void) { // wait loop while (!((nowtime = I_GetTime()) - lastwipetic)) - I_Sleep(); + { + I_Sleep(cv_sleep.value); + I_UpdateTime(cv_timescale.value); + } lastwipetic = nowtime; if (moviemode) // make sure we save frames for the white hold too M_SaveFrame(); diff --git a/src/screen.c b/src/screen.c index 62b1fe05c..9cac11263 100644 --- a/src/screen.c +++ b/src/screen.c @@ -479,12 +479,12 @@ void SCR_CalculateFPS(void) return; } - updateElapsed = I_PreciseToMicros(endTime - updateTime); + updateElapsed = (endTime - updateTime) / (I_GetPrecisePrecision() / 1000000); if (updateElapsed >= FPS_SAMPLE_RATE) { static int sampleIndex = 0; - int frameElapsed = I_PreciseToMicros(endTime - startTime); + int frameElapsed = (endTime - startTime) / (I_GetPrecisePrecision() / 1000000); fps_samples[sampleIndex] = frameElapsed / 1000.0f; diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index de7369236..343de61c8 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -2144,36 +2144,16 @@ ticcmd_t *I_BaseTiccmd2(void) static Uint64 timer_frequency; -// -// I_GetPreciseTime -// returns time in precise_t -// precise_t I_GetPreciseTime(void) { return SDL_GetPerformanceCounter(); } -int I_PreciseToMicros(precise_t d) +UINT64 I_GetPrecisePrecision(void) { - // d is going to be converted into a double. So remove the highest bits - // to avoid loss of precision in the lower bits, for the (probably rare) case - // that the higher bits are actually used. - d &= ((precise_t)1 << 53) - 1; // The mantissa of a double can handle 53 bits at most. - // The resulting double from the calculation is converted first to UINT64 to avoid overflow, - // which is undefined behaviour when converting floating point values to integers. - return (int)(UINT64)(d / (timer_frequency / 1000000.0)); + return SDL_GetPerformanceFrequency(); } -double I_PreciseElapsedSeconds(precise_t before, precise_t after) -{ - return (after - before) / (double)timer_frequency; -} - -// -// I_GetFrameTime -// returns time in 1/fpscap second tics -// - static UINT32 frame_rate; static double frame_frequency; @@ -2233,68 +2213,9 @@ void I_StartupTimer(void) elapsed_frames = 0.0; } -// -// I_Sleep -// Sleeps by the value of cv_sleep -// -void I_Sleep(void) +void I_Sleep(UINT32 ms) { - if (cv_sleep.value > 0) - SDL_Delay(cv_sleep.value); - - // I_Sleep is still called in a number of places - // we need to update the internal time state to make this work - I_UpdateTime(cv_timescale.value); -} - -// -// I_FrameCapSleep -// Sleeps for a variable amount of time, depending on how much time the frame took. -// -boolean I_FrameCapSleep(const double t) -{ - // SDL_Delay(1) gives me a range of around 1.95ms to 2.05ms. - // Has a bit extra to be totally safe. - const double delayGranularity = 2.1; - double frameMS = 0.0; - - double curTime = 0.0; - double destTime = 0.0; - double sleepTime = 0.0; - - if (frame_rate == 0) - { - // We don't want to cap. - return false; - } - - curTime = I_GetFrameTime(); - destTime = floor(t) + 1.0; - - if (curTime >= destTime) - { - // We're already behind schedule. - return false; - } - - frameMS = frame_rate * 0.001; // 1ms as frame time - sleepTime = destTime - (delayGranularity * frameMS); - - while (curTime < destTime) - { - if (curTime < sleepTime && cv_sleep.value > 0) - { - // Wait 1ms at a time (on default settings) - // until we're close enough. - SDL_Delay(cv_sleep.value); - } - - // This part will spin-lock the rest. - curTime = I_GetFrameTime(); - } - - // We took our nap. - return true; + SDL_Delay(ms); } #ifdef NEWSIGNALHANDLER diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 7e6f82a29..d325b2234 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -263,12 +263,25 @@ tic_t I_GetTime(void) return newtics; } -void I_Sleep(void) +precise_t I_GetPreciseTime(void) { - if (cv_sleep.value != -1) - Sleep(cv_sleep.value); + LARGE_INTEGER time; + BOOL res = QueryPerformanceCounter(&time); + if (!res) I_Error("QueryPerformanceCounter error"); // if this happens, you've gone back to the 90s + return (precise_t) time.QuadPart; +} - I_UpdateTime(cv_timescale.value); +UINT64 I_GetPrecisePrecision(void) +{ + LARGE_INTEGER time; + BOOL res = QueryPerformanceFrequency(&time); + if (!res) I_Error("QueryPerformanceFrequency error"); // if this happens, you've gone back to the 90s + return (precise_t) time.QuadPart; +} + +void I_Sleep(UINT32 ms) +{ + Sleep(ms); } // should move to i_video From 7ec0420ce63cba8fd2e0b74467d40cf3a48e6650 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 3 May 2022 15:07:35 -0500 Subject: [PATCH 106/137] Adjust spawned mobj z by gravity inversion --- src/p_mobj.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index dd076acd6..57442fe64 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -14084,6 +14084,7 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration) mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type) { mobj_t *newmobj; + fixed_t elementheight; xofs = FixedMul(xofs, mobj->scale); yofs = FixedMul(yofs, mobj->scale); @@ -14093,24 +14094,31 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo if (!newmobj) return NULL; + elementheight = FixedMul(newmobj->info->height, mobj->scale); + if (mobj->eflags & MFE_VERTICALFLIP) { - fixed_t elementheight = FixedMul(newmobj->info->height, mobj->scale); - newmobj->eflags |= MFE_VERTICALFLIP; newmobj->flags2 |= MF2_OBJECTFLIP; newmobj->z = mobj->z + mobj->height - zofs - elementheight; } + if (mobj->flags2 & MF2_OBJECTFLIP || mobj->eflags & MFE_VERTICALFLIP) + { + newmobj->old_z = mobj->old_z + mobj->height - zofs - elementheight; + newmobj->old_z2 = mobj->old_z2 + mobj->height - zofs - elementheight; + } else { + newmobj->old_z = mobj->old_z; + newmobj->old_z2 = mobj->old_z2; + } + newmobj->destscale = mobj->destscale; P_SetScale(newmobj, mobj->scale); newmobj->old_x2 = mobj->old_x2 + xofs; newmobj->old_y2 = mobj->old_y2 + yofs; - newmobj->old_z2 = mobj->old_z2 + zofs; newmobj->old_x = mobj->old_x + xofs; newmobj->old_y = mobj->old_y + yofs; - newmobj->old_z = mobj->old_z + zofs; // This angle hack is needed for Lua scripts that set the angle after // spawning, to avoid erroneous interpolation. From 1c11ddd6ae175343b9833092d942e77f624ee774 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 3 May 2022 15:23:00 -0500 Subject: [PATCH 107/137] Only check VERTICALFLIP for old_z calc --- src/p_mobj.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 57442fe64..8ec6a386c 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -14084,7 +14084,6 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration) mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zofs, mobjtype_t type) { mobj_t *newmobj; - fixed_t elementheight; xofs = FixedMul(xofs, mobj->scale); yofs = FixedMul(yofs, mobj->scale); @@ -14094,20 +14093,19 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo if (!newmobj) return NULL; - elementheight = FixedMul(newmobj->info->height, mobj->scale); - if (mobj->eflags & MFE_VERTICALFLIP) { + fixed_t elementheight = FixedMul(newmobj->info->height, mobj->scale); + newmobj->eflags |= MFE_VERTICALFLIP; newmobj->flags2 |= MF2_OBJECTFLIP; newmobj->z = mobj->z + mobj->height - zofs - elementheight; - } - if (mobj->flags2 & MF2_OBJECTFLIP || mobj->eflags & MFE_VERTICALFLIP) - { newmobj->old_z = mobj->old_z + mobj->height - zofs - elementheight; newmobj->old_z2 = mobj->old_z2 + mobj->height - zofs - elementheight; - } else { + } + else + { newmobj->old_z = mobj->old_z; newmobj->old_z2 = mobj->old_z2; } From bd73256390be7f1c2fc734349fe7fae338d8992b Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 3 May 2022 18:18:08 -0500 Subject: [PATCH 108/137] Fix Marathon Mode menu for uncapped --- src/m_menu.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index ecbebe5f4..673725773 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -10663,7 +10663,7 @@ static void M_Marathon(INT32 choice) titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please M_SetupNextMenu(&SP_MarathonDef); itemOn = marathonstart; // "Start" is selected. - recatkdrawtimer = 50-8; + recatkdrawtimer = (50-8) * FRACUNIT; char_scroll = 0; } @@ -10744,13 +10744,16 @@ void M_DrawMarathon(void) x = (((BASEVIDWIDTH-82)/2)+11)<>ANGLETOFINESHIFT) & FINEMASK; y -= (10*FINECOSINE(fa)); - recatkdrawtimer++; + if (renderisnewtic) + { + recatkdrawtimer += FRACUNIT; + } - soffset = cnt = (recatkdrawtimer%50); + soffset = cnt = ((recatkdrawtimer >> FRACBITS) % 50); if (!useBlackRock) { if (cnt > 8) @@ -10789,7 +10792,7 @@ void M_DrawMarathon(void) } w = char_scroll + (((8-cnt)*(8-cnt))<<(FRACBITS-5)); - if (soffset == 50-1) + if (soffset == 50-1 && renderisnewtic) w += FRACUNIT/2; { @@ -10844,11 +10847,11 @@ void M_DrawMarathon(void) if (!soffset) { - char_scroll += (360<= 360< (10*TICRATE)) - recatkdrawtimer -= (10*TICRATE); + if (recatkdrawtimer > ((10 << FRACBITS) * TICRATE)) + recatkdrawtimer -= ((10 << FRACBITS) * TICRATE); } M_DrawMenuTitle(); From 40c2f66a5a9baa40b728bdd3b6f800676f4f8c9a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 4 May 2022 20:17:35 -0400 Subject: [PATCH 109/137] Move screenshot code before timing --- src/d_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 3f539128e..2ff4bb1f6 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -893,6 +893,12 @@ void D_SRB2Loop(void) PS_STOP_TIMING(ps_swaptime); } + // Only take screenshots after drawing. + if (moviemode) + M_SaveFrame(); + if (takescreenshot) + M_DoScreenShot(); + // Fully completed frame made. finishprecise = I_GetPreciseTime(); if (!singletics) @@ -907,12 +913,6 @@ void D_SRB2Loop(void) finishprecise = I_GetPreciseTime(); deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision(); deltatics = deltasecs * NEWTICRATE; - - // Only take screenshots after drawing. - if (moviemode) - M_SaveFrame(); - if (takescreenshot) - M_DoScreenShot(); } } From e3fd3dfa65234db135d1f3319d9fcf2e5a7706d3 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 4 May 2022 20:40:45 -0500 Subject: [PATCH 110/137] Only play emerald hunt sounds on new tics --- src/st_stuff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index fcdde5826..c47dd6f51 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2540,7 +2540,7 @@ static void ST_doHuntIconsAndSound(void) interval = newinterval; } - if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0) + if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0 && renderisnewtic) S_StartSound(NULL, sfx_emfind); } @@ -2602,7 +2602,7 @@ static void ST_doItemFinderIconsAndSound(void) } - if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0) + if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0 && renderisnewtic) S_StartSound(NULL, sfx_emfind); } From c2e1b1be548024a770da88c0ba35fa357b972e7d Mon Sep 17 00:00:00 2001 From: katsy Date: Thu, 5 May 2022 13:18:01 -0500 Subject: [PATCH 111/137] Restore deleted zofs (fixes signpost sparkles etc) --- src/p_mobj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index 8ec6a386c..6d20f0569 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -14106,8 +14106,8 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo } else { - newmobj->old_z = mobj->old_z; - newmobj->old_z2 = mobj->old_z2; + newmobj->old_z = mobj->old_z + zofs; + newmobj->old_z2 = mobj->old_z2 + zofs; } newmobj->destscale = mobj->destscale; From 4d183299466dd48400ccce22d1da6f2d1e08ec0a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 5 May 2022 00:04:14 -0400 Subject: [PATCH 112/137] Revert to before screenUpdate boolean was added Was done this way for the sake of an older version of uncapped's timing; now that the new timing is much better, I decided it should remain as close to pre-uncapped as it can be. --- src/d_main.c | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 2ff4bb1f6..3786efd07 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -298,17 +298,17 @@ gamestate_t wipegamestate = GS_LEVEL; INT16 wipetypepre = -1; INT16 wipetypepost = -1; -static boolean D_Display(void) +static void D_Display(void) { boolean forcerefresh = false; static boolean wipe = false; INT32 wipedefindex = 0; if (dedicated) - return false; + return; if (nodrawers) - return false; // for comparative timing/profiling + return; // for comparative timing/profiling // Lactozilla: Switching renderers works by checking // if the game has to do it right when the frame @@ -682,10 +682,10 @@ static boolean D_Display(void) M_DrawPerfStats(); } - return true; // Do I_FinishUpdate in the main loop + PS_START_TIMING(ps_swaptime); + I_FinishUpdate(); // page flip or blit buffer + PS_STOP_TIMING(ps_swaptime); } - - return false; } // ========================================================================= @@ -703,7 +703,6 @@ void D_SRB2Loop(void) boolean interp = false; boolean doDisplay = false; - boolean screenUpdate = false; if (dedicated) server = true; @@ -793,7 +792,7 @@ void D_SRB2Loop(void) #endif interp = R_UsingFrameInterpolation() && !dedicated; - doDisplay = screenUpdate = false; + doDisplay = false; #ifdef HW3SOUND HW3S_BeginFrameUpdate(); @@ -871,10 +870,16 @@ void D_SRB2Loop(void) if (interp || doDisplay) { - screenUpdate = D_Display(); + D_Display(); } - // consoleplayer -> displayplayer (hear sounds from viewpoint) + // Only take screenshots after drawing. + if (moviemode) + M_SaveFrame(); + if (takescreenshot) + M_DoScreenShot(); + + // consoleplayer -> displayplayers (hear sounds from viewpoint) S_UpdateSounds(); // move positional sounds S_UpdateClosedCaptions(); @@ -884,21 +889,6 @@ void D_SRB2Loop(void) LUA_Step(); - // I_FinishUpdate is now here instead of D_Display, - // because it synchronizes it more closely with the frame counter. - if (screenUpdate == true) - { - PS_START_TIMING(ps_swaptime); - I_FinishUpdate(); // page flip or blit buffer - PS_STOP_TIMING(ps_swaptime); - } - - // Only take screenshots after drawing. - if (moviemode) - M_SaveFrame(); - if (takescreenshot) - M_DoScreenShot(); - // Fully completed frame made. finishprecise = I_GetPreciseTime(); if (!singletics) From 1920dba08230e1f62445e0bad3ae8589d97337de Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 5 May 2022 18:49:31 -0500 Subject: [PATCH 113/137] Run UpdateLevelInterpolators in preticker Fixes KartKrew/Kart-Public#10 --- src/p_tick.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_tick.c b/src/p_tick.c index a388ab3f2..7a2ceb3fc 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -830,6 +830,8 @@ void P_PreTicker(INT32 frames) LUA_HOOK(PostThinkFrame); + R_UpdateLevelInterpolators(); + P_MapEnd(); } From 73930c655bdc6334a399c88d2c9bad8b0779b03b Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 5 May 2022 19:23:26 -0500 Subject: [PATCH 114/137] Run UpdateMobjInterpolators in preticker --- src/p_setup.c | 1 - src/p_tick.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index be1d5a011..00030b944 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7680,7 +7680,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) R_ResetViewInterpolation(); R_ResetViewInterpolation(); - R_UpdateMobjInterpolators(); // No render mode or reloading gamestate, stop here. if (rendermode == render_none || reloadinggamestate) diff --git a/src/p_tick.c b/src/p_tick.c index 7a2ceb3fc..8a2e70ac7 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -792,6 +792,8 @@ void P_PreTicker(INT32 frames) { P_MapStart(); + R_UpdateMobjInterpolators(); + LUA_HOOK(PreThinkFrame); for (i = 0; i < MAXPLAYERS; i++) From d511857675a88320ad67f63a3a441bb0bb80ff41 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 5 May 2022 19:43:55 -0500 Subject: [PATCH 115/137] Reset view interp in preticker --- src/g_game.c | 11 ----------- src/p_setup.c | 3 --- src/p_tick.c | 3 +++ 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/src/g_game.c b/src/g_game.c index 1ea75844d..e1380e3a7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2367,11 +2367,6 @@ void G_Ticker(boolean run) F_TextPromptTicker(); AM_Ticker(); HU_Ticker(); - if (run) - { - R_UpdateViewInterpolation(); - } - break; @@ -2426,14 +2421,8 @@ void G_Ticker(boolean run) case GS_TITLESCREEN: if (titlemapinaction) - { P_Ticker(run); - if (run) - { - R_UpdateViewInterpolation(); - } // then intentionally fall through - } /* FALLTHRU */ case GS_WAITINGPLAYERS: F_MenuPresTicker(run); diff --git a/src/p_setup.c b/src/p_setup.c index 00030b944..afbd0f48e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -7678,9 +7678,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) P_MapEnd(); // just in case MapLoad modifies tmthing } - R_ResetViewInterpolation(); - R_ResetViewInterpolation(); - // No render mode or reloading gamestate, stop here. if (rendermode == render_none || reloadinggamestate) return true; diff --git a/src/p_tick.c b/src/p_tick.c index 8a2e70ac7..10270107f 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -770,6 +770,7 @@ void P_Ticker(boolean run) if (run) { R_UpdateLevelInterpolators(); + R_UpdateViewInterpolation(); } P_MapEnd(); @@ -833,6 +834,8 @@ void P_PreTicker(INT32 frames) LUA_HOOK(PostThinkFrame); R_UpdateLevelInterpolators(); + R_UpdateViewInterpolation(); + R_ResetViewInterpolation(); P_MapEnd(); } From 7c00cea1fc01cff3c1284f5912e6ffddcd607a80 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Thu, 5 May 2022 20:11:37 -0500 Subject: [PATCH 116/137] Add per-split player view resets --- src/p_tick.c | 2 +- src/r_fps.c | 33 ++++++++++++++++++++++++++++----- src/r_fps.h | 2 +- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/p_tick.c b/src/p_tick.c index 10270107f..217af3714 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -835,7 +835,7 @@ void P_PreTicker(INT32 frames) R_UpdateLevelInterpolators(); R_UpdateViewInterpolation(); - R_ResetViewInterpolation(); + R_ResetViewInterpolation(0); P_MapEnd(); } diff --git a/src/r_fps.c b/src/r_fps.c index 10e3cc10b..f3675ab97 100644 --- a/src/r_fps.c +++ b/src/r_fps.c @@ -83,7 +83,7 @@ static viewvars_t sky2view_old; static viewvars_t sky2view_new; static viewvars_t *oldview = &p1view_old; -static int oldview_invalid = 0; +static int oldview_invalid[MAXSPLITSCREENPLAYERS] = {0, 0}; viewvars_t *newview = &p1view_new; @@ -160,12 +160,23 @@ void R_InterpolateView(fixed_t frac) { viewvars_t* prevview = oldview; boolean skybox = 0; + UINT8 i; + if (FIXED_TO_FLOAT(frac) < 0) frac = 0; if (frac > FRACUNIT) frac = FRACUNIT; - if (oldview_invalid != 0) + if (viewcontext == VIEWCONTEXT_SKY1 || viewcontext == VIEWCONTEXT_PLAYER1) + { + i = 0; + } + else + { + i = 1; + } + + if (oldview_invalid[i] != 0) { // interpolate from newview to newview prevview = newview; @@ -201,12 +212,24 @@ void R_UpdateViewInterpolation(void) p2view_old = p2view_new; sky1view_old = sky1view_new; sky2view_old = sky2view_new; - if (oldview_invalid) oldview_invalid--; + if (oldview_invalid[0] > 0) oldview_invalid[0]--; + if (oldview_invalid[1] > 0) oldview_invalid[1]--; } -void R_ResetViewInterpolation(void) +void R_ResetViewInterpolation(UINT8 p) { - oldview_invalid++; + if (p == 0) + { + UINT8 i; + for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) + { + oldview_invalid[i]++; + } + } + else + { + oldview_invalid[p - 1]++; + } } void R_SetViewContext(enum viewcontext_e _viewcontext) diff --git a/src/r_fps.h b/src/r_fps.h index 97d6022b7..85c87a2f4 100644 --- a/src/r_fps.h +++ b/src/r_fps.h @@ -118,7 +118,7 @@ void R_InterpolateView(fixed_t frac); // Buffer the current new views into the old views. Call once after each real tic. void R_UpdateViewInterpolation(void); // Reset the view states (e.g. after level load) so R_InterpolateView doesn't interpolate invalid data -void R_ResetViewInterpolation(void); +void R_ResetViewInterpolation(UINT8 p); // Set the current view context (the viewvars pointed to by newview) void R_SetViewContext(enum viewcontext_e _viewcontext); From 32b166669e6028839f34b97fbbf3b0240d98f4be Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 17 May 2022 19:57:31 -0500 Subject: [PATCH 117/137] Don't interpolate during net lag --- src/d_clisrv.c | 16 ++++++++++++++++ src/d_clisrv.h | 3 +++ src/d_main.c | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 3068f2314..4cd6333c5 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -114,6 +114,9 @@ static INT16 consistancy[BACKUPTICS]; static UINT8 player_joining = false; UINT8 hu_redownloadinggamestate = 0; +// true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks +boolean hu_stopped = false; + UINT8 adminpassmd5[16]; boolean adminpasswordset = false; @@ -5259,8 +5262,16 @@ boolean TryRunTics(tic_t realtics) ticking = neededtic > gametic; + if (ticking) + { + if (realtics) + hu_stopped = false; + } + if (player_joining) { + if (realtics) + hu_stopped = true; return false; } @@ -5300,6 +5311,11 @@ boolean TryRunTics(tic_t realtics) break; } } + else + { + if (realtics) + hu_stopped = true; + } return ticking; } diff --git a/src/d_clisrv.h b/src/d_clisrv.h index c75f7f0bf..e07864122 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -458,4 +458,7 @@ extern UINT8 hu_redownloadinggamestate; extern UINT8 adminpassmd5[16]; extern boolean adminpasswordset; + +extern boolean hu_stopped; + #endif diff --git a/src/d_main.c b/src/d_main.c index 3786efd07..0ae48c927 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -853,7 +853,7 @@ void D_SRB2Loop(void) renderdeltatics = FLOAT_TO_FIXED(deltatics); - if (!(paused || P_AutoPause())) + if (!(paused || P_AutoPause()) && !hu_stopped) { rendertimefrac = g_time.timefrac; } From 516a5e8350df6dd92f8103c5e3bce4829d477335 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 18 May 2022 18:29:37 -0500 Subject: [PATCH 118/137] Remove hudlib getDeltaTime --- src/lua_hudlib.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index 0a4d0dcde..40c6f6e1f 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -1308,14 +1308,6 @@ static int libd_getusertransflag(lua_State *L) return 1; } -// Return the time elapsed for the previous frame, in tics. -static int libd_getDeltaTime(lua_State *L) -{ - HUDONLY - lua_pushfixed(L, renderdeltatics); - return 1; -} - static luaL_Reg lib_draw[] = { // cache {"patchExists", libd_patchExists}, @@ -1357,7 +1349,6 @@ static luaL_Reg lib_draw[] = { {"renderer", libd_renderer}, {"localTransFlag", libd_getlocaltransflag}, {"userTransFlag", libd_getusertransflag}, - {"getDeltaTime", libd_getDeltaTime}, {NULL, NULL} }; From 169f33a101d5276c27dde74188520eb879e17ee2 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Wed, 18 May 2022 21:04:33 -0500 Subject: [PATCH 119/137] Defensively recreate title drawlist Avoids a crash when connecting to a server in the Intro --- src/f_finale.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/f_finale.c b/src/f_finale.c index 1fb078b64..709d86ac1 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -3406,6 +3406,15 @@ void F_TitleScreenDrawer(void) } luahook: + // The title drawer is sometimes called without first being started + // In order to avoid use-before-initialization crashes, let's check and + // create the drawlist if it doesn't exist. + if (!LUA_HUD_IsDrawListValid(luahuddrawlist_title)) + { + LUA_HUD_DestroyDrawList(luahuddrawlist_title); + luahuddrawlist_title = LUA_HUD_CreateDrawList(); + } + if (renderisnewtic) { LUA_HUD_ClearDrawList(luahuddrawlist_title); From 79f736b75fa292c5130ef0a4484b8002ce452465 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 19 May 2022 16:37:33 -0400 Subject: [PATCH 120/137] Use double instead of precise_t for FPS counter Makes the displayed FPS more accurate to what it's actually displaying. Also removed HUDTRANS from it -- stop it fading out during level transitions, it's annoying when I actually want to see the FPS during those bits. --- src/screen.c | 58 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/screen.c b/src/screen.c index 9cac11263..ef1e1d323 100644 --- a/src/screen.c +++ b/src/screen.c @@ -454,55 +454,69 @@ boolean SCR_IsAspectCorrect(INT32 width, INT32 height) double averageFPS = 0.0f; -#define FPS_SAMPLE_RATE (50000) // How often to update FPS samples, in microseconds -#define NUM_FPS_SAMPLES 16 // Number of samples to store +#define USE_FPS_SAMPLES + +#ifdef USE_FPS_SAMPLES +#define FPS_SAMPLE_RATE (0.05) // How often to update FPS samples, in seconds +#define NUM_FPS_SAMPLES (16) // Number of samples to store static double fps_samples[NUM_FPS_SAMPLES]; +static double updateElapsed = 0.0; +#endif + +static boolean fps_init = false; +static precise_t fps_enter = 0; void SCR_CalculateFPS(void) { - static boolean init = false; + precise_t fps_finish = 0; - static precise_t startTime = 0; - precise_t endTime = 0; + double frameElapsed = 0.0; - static precise_t updateTime = 0; - int updateElapsed = 0; - int i; - - endTime = I_GetPreciseTime(); - - if (init == false) + if (fps_init == false) { - startTime = updateTime = endTime; - init = true; - return; + fps_enter = I_GetPreciseTime(); + fps_init = true; } - updateElapsed = (endTime - updateTime) / (I_GetPrecisePrecision() / 1000000); + fps_finish = I_GetPreciseTime(); + frameElapsed = (double)((INT64)(fps_finish - fps_enter)) / I_GetPrecisePrecision(); + fps_enter = fps_finish; + +#ifdef USE_FPS_SAMPLES + updateElapsed += frameElapsed; if (updateElapsed >= FPS_SAMPLE_RATE) { static int sampleIndex = 0; - int frameElapsed = (endTime - startTime) / (I_GetPrecisePrecision() / 1000000); + int i; - fps_samples[sampleIndex] = frameElapsed / 1000.0f; + fps_samples[sampleIndex] = frameElapsed; sampleIndex++; if (sampleIndex >= NUM_FPS_SAMPLES) sampleIndex = 0; - averageFPS = 0.0f; + averageFPS = 0.0; for (i = 0; i < NUM_FPS_SAMPLES; i++) { averageFPS += fps_samples[i]; } - averageFPS = 1000.0f / (averageFPS / NUM_FPS_SAMPLES); - updateTime = endTime; + if (averageFPS > 0.0) + { + averageFPS = 1.0 / (averageFPS / NUM_FPS_SAMPLES); + } } - startTime = endTime; + while (updateElapsed >= FPS_SAMPLE_RATE) + { + updateElapsed -= FPS_SAMPLE_RATE; + } +#else + // Direct, unsampled counter. + averageFPS = 1.0 / frameElapsed; +#endif } void SCR_DisplayTicRate(void) From 8040c8fe05bf5eeee34f94e7b0a92a88c0160feb Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 21 May 2022 12:32:40 -0500 Subject: [PATCH 121/137] Tweaks for kart v1 MR comments --- src/i_time.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/i_time.c b/src/i_time.c index c86973f6e..c1cc9dfd4 100644 --- a/src/i_time.c +++ b/src/i_time.c @@ -30,6 +30,12 @@ static precise_t enterprecise, oldenterprecise; static fixed_t entertic, oldentertics; static double tictimer; +// A little more than the minimum sleep duration on Windows. +// May be incorrect for other platforms, but we don't currently have a way to +// query the scheduler granularity. SDL will do what's needed to make this as +// low as possible though. +#define MIN_SLEEP_DURATION_MS 2.1 + tic_t I_GetTime(void) { return g_time.time; @@ -90,7 +96,7 @@ void I_SleepDuration(precise_t duration) precise_t dest; { - double gran = round(((double)(precision / 1000) * sleepvalue * 2.1)); + double gran = round(((double)(precision / 1000) * sleepvalue * MIN_SLEEP_DURATION_MS)); delaygranularity = (UINT64)gran; } From 1ef40c90370f057fb804c9616c7565620ba1cec5 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 21 May 2022 14:38:32 -0500 Subject: [PATCH 122/137] Update interpolation during objectplace --- src/p_tick.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_tick.c b/src/p_tick.c index 217af3714..20b709f0c 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -618,8 +618,10 @@ void P_Ticker(boolean run) if (OP_FreezeObjectplace()) { P_MapStart(); + R_UpdateMobjInterpolators(); OP_ObjectplaceMovement(&players[0]); P_MoveChaseCamera(&players[0], &camera, false); + R_UpdateViewInterpolation(); P_MapEnd(); S_SetStackAdjustmentStart(); return; From 8b175398f8165720cd3751e1aa98a366b182acb2 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 30 May 2022 18:22:46 -0400 Subject: [PATCH 123/137] Use old behavior when dipping below 35 with interp --- src/d_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index 0ae48c927..e73cb749e 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -853,7 +853,7 @@ void D_SRB2Loop(void) renderdeltatics = FLOAT_TO_FIXED(deltatics); - if (!(paused || P_AutoPause()) && !hu_stopped) + if (!(paused || P_AutoPause()) && deltatics < 1.0 && !hu_stopped) { rendertimefrac = g_time.timefrac; } From 41f17495c437363e639f97fd066c8dfe2d39515d Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sun, 9 Oct 2022 15:29:28 -0500 Subject: [PATCH 124/137] uncapped: Update closed captions only on new tics --- src/d_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d_main.c b/src/d_main.c index e73cb749e..91a42ff14 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -881,7 +881,8 @@ void D_SRB2Loop(void) // consoleplayer -> displayplayers (hear sounds from viewpoint) S_UpdateSounds(); // move positional sounds - S_UpdateClosedCaptions(); + if (realtics > 0 || singletics) + S_UpdateClosedCaptions(); #ifdef HW3SOUND HW3S_EndFrameUpdate(); From f43839ef8d938e3f05fdba72ca2e5929c14e45bb Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sat, 20 Aug 2022 13:42:34 -0500 Subject: [PATCH 125/137] uncapped: Reset cam interpolation on P_ResetCamera --- src/p_local.h | 1 + src/p_user.c | 1 + src/r_main.c | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/src/p_local.h b/src/p_local.h index 8a9189176..49af03f36 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -91,6 +91,7 @@ typedef struct camera_s // Camera demobjerization // Info for drawing: position. fixed_t x, y, z; + boolean reset; //More drawing info: to determine current sprite. angle_t angle; // orientation diff --git a/src/p_user.c b/src/p_user.c index 444da6fea..802c06155 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9656,6 +9656,7 @@ void P_ResetCamera(player_t *player, camera_t *thiscam) thiscam->x = x; thiscam->y = y; thiscam->z = z; + thiscam->reset = true; if ((thiscam == &camera && G_ControlStyle(1) == CS_SIMPLE) || (thiscam == &camera2 && G_ControlStyle(2) == CS_SIMPLE)) diff --git a/src/r_main.c b/src/r_main.c index b1ba15050..cd5e255ed 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1346,12 +1346,31 @@ void R_SkyboxFrame(player_t *player) boolean R_ViewpointHasChasecam(player_t *player) { + camera_t *thiscam; boolean chasecam = false; if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer]) + { + thiscam = &camera2; chasecam = (cv_chasecam2.value != 0); + R_SetViewContext(VIEWCONTEXT_PLAYER2); + if (thiscam->reset) + { + R_ResetViewInterpolation(2); + thiscam->reset = false; + } + } else + { + thiscam = &camera; chasecam = (cv_chasecam.value != 0); + R_SetViewContext(VIEWCONTEXT_PLAYER1); + if (thiscam->reset) + { + R_ResetViewInterpolation(1); + thiscam->reset = false; + } + } if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode) chasecam = true; // force chasecam on From 8fa553a1d087721d2c1a288b78bc04f8f01330f4 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 25 Oct 2022 19:32:28 -0500 Subject: [PATCH 126/137] Ensure view interpolates between T-1 to T --- src/p_tick.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/p_tick.c b/src/p_tick.c index 20b709f0c..0560c4f1e 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -23,6 +23,7 @@ #include "lua_hook.h" #include "m_perfstats.h" #include "i_system.h" // I_GetPreciseTime +#include "r_main.h" #include "r_fps.h" // Object place @@ -771,8 +772,30 @@ void P_Ticker(boolean run) if (run) { + player_t *player1; + R_UpdateLevelInterpolators(); R_UpdateViewInterpolation(); + + // Hack: ensure newview is assigned every tic. + // Ensures view interpolation is T-1 to T in poor network conditions + // We need a better way to assign view state decoupled from game logic + player1 = &players[displayplayer]; + if (player1->mo && skyboxmo[0] && cv_skybox.value) + { + R_SkyboxFrame(player1); + } + R_SetupFrame(player1); + + if (splitscreen) + { + player_t *player2 = &players[secondarydisplayplayer]; + if (player2->mo && skyboxmo[0] && cv_skybox.value) + { + R_SkyboxFrame(player2); + } + R_SetupFrame(player2); + } } P_MapEnd(); From 46603d607e830a277c8d8e56ed5e2645d5a4e703 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 25 Oct 2022 20:48:10 -0500 Subject: [PATCH 127/137] Clear and draw all game hud hook calls to 1 list Fixes splitscreen issues with lua hud hooks --- src/st_stuff.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/st_stuff.c b/src/st_stuff.c index c47dd6f51..ed130c912 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -2759,10 +2759,8 @@ static void ST_overlayDrawer(void) { if (renderisnewtic) { - LUA_HUD_ClearDrawList(luahuddrawlist_game); LUA_HUDHOOK(game, luahuddrawlist_game); } - LUA_HUD_DrawList(luahuddrawlist_game); } // draw level title Tails @@ -2841,6 +2839,10 @@ void ST_Drawer(void) if (st_overlay) { + if (renderisnewtic) + { + LUA_HUD_ClearDrawList(luahuddrawlist_game); + } // No deadview! stplyr = &players[displayplayer]; ST_overlayDrawer(); @@ -2850,5 +2852,7 @@ void ST_Drawer(void) stplyr = &players[secondarydisplayplayer]; ST_overlayDrawer(); } + + LUA_HUD_DrawList(luahuddrawlist_game); } } From fdd6550669d33db202cad862cb3dcd06914e376f Mon Sep 17 00:00:00 2001 From: Eidolon Date: Fri, 28 Oct 2022 23:02:56 -0500 Subject: [PATCH 128/137] Only run view update hack in no-render mode --- src/p_tick.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/p_tick.c b/src/p_tick.c index 0560c4f1e..61f33851f 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -25,6 +25,7 @@ #include "i_system.h" // I_GetPreciseTime #include "r_main.h" #include "r_fps.h" +#include "i_video.h" // rendermode // Object place #include "m_cheat.h" @@ -772,30 +773,32 @@ void P_Ticker(boolean run) if (run) { - player_t *player1; - R_UpdateLevelInterpolators(); R_UpdateViewInterpolation(); // Hack: ensure newview is assigned every tic. // Ensures view interpolation is T-1 to T in poor network conditions // We need a better way to assign view state decoupled from game logic - player1 = &players[displayplayer]; - if (player1->mo && skyboxmo[0] && cv_skybox.value) + if (rendermode != render_none) { - R_SkyboxFrame(player1); - } - R_SetupFrame(player1); - - if (splitscreen) - { - player_t *player2 = &players[secondarydisplayplayer]; - if (player2->mo && skyboxmo[0] && cv_skybox.value) + player_t *player1 = &players[displayplayer]; + if (player1->mo && skyboxmo[0] && cv_skybox.value) { - R_SkyboxFrame(player2); + R_SkyboxFrame(player1); + } + R_SetupFrame(player1); + + if (splitscreen) + { + player_t *player2 = &players[secondarydisplayplayer]; + if (player2->mo && skyboxmo[0] && cv_skybox.value) + { + R_SkyboxFrame(player2); + } + R_SetupFrame(player2); } - R_SetupFrame(player2); } + } P_MapEnd(); From af753b5268e616bfeac82bb8b0d1cd4e1632ab52 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sun, 30 Oct 2022 21:06:50 -0500 Subject: [PATCH 129/137] Only call SetupFrame in T-1 hack with player->mo --- src/p_tick.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/p_tick.c b/src/p_tick.c index 61f33851f..bf6e8f42e 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -786,7 +786,10 @@ void P_Ticker(boolean run) { R_SkyboxFrame(player1); } - R_SetupFrame(player1); + if (player1->mo) + { + R_SetupFrame(player1); + } if (splitscreen) { @@ -795,7 +798,10 @@ void P_Ticker(boolean run) { R_SkyboxFrame(player2); } - R_SetupFrame(player2); + if (player2->mo) + { + R_SetupFrame(player2); + } } } From f7bc03ad61fa086766d927fe8d20a724a3beb84a Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sun, 30 Oct 2022 23:14:11 -0500 Subject: [PATCH 130/137] Use interp position in GL billboarding --- src/hardware/hw_main.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index c8d227973..18e276e84 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3758,11 +3758,24 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts && spr && spr->mobj && !R_ThingIsPaperSprite(spr->mobj) && wallVerts) { - float basey = FIXED_TO_FLOAT(spr->mobj->z); + // uncapped/interpolation + interpmobjstate_t interp = {0}; + + // do interpolation + if (R_UsingFrameInterpolation() && !paused) + { + R_InterpolateMobjState(spr->mobj, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(spr->mobj, FRACUNIT, &interp); + } + + float basey = FIXED_TO_FLOAT(interp.z); float lowy = wallVerts[0].y; if (!precip && P_MobjFlip(spr->mobj) == -1) // precip doesn't have eflags so they can't flip { - basey = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height); + basey = FIXED_TO_FLOAT(interp.z + spr->mobj->height); } // Rotate sprites to fully billboard with the camera // X, Y, AND Z need to be manipulated for the polys to rotate around the From 5f6c56cf36f7c952139a47b52f5cbd89ef770fb8 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 31 Oct 2022 20:29:13 -0500 Subject: [PATCH 131/137] Use precip interp if gl sprite is for precip --- src/hardware/hw_main.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 18e276e84..8d2170435 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3760,23 +3760,42 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts { // uncapped/interpolation interpmobjstate_t interp = {0}; + float basey, lowy; // do interpolation if (R_UsingFrameInterpolation() && !paused) { - R_InterpolateMobjState(spr->mobj, rendertimefrac, &interp); + if (precip) + { + R_InterpolatePrecipMobjState(spr->mobj, rendertimefrac, &interp); + } + else + { + R_InterpolateMobjState(spr->mobj, rendertimefrac, &interp); + } } else { - R_InterpolateMobjState(spr->mobj, FRACUNIT, &interp); + if (precip) + { + R_InterpolatePrecipMobjState(spr->mobj, FRACUNIT, &interp); + } + else + { + R_InterpolateMobjState(spr->mobj, FRACUNIT, &interp); + } } - float basey = FIXED_TO_FLOAT(interp.z); - float lowy = wallVerts[0].y; - if (!precip && P_MobjFlip(spr->mobj) == -1) // precip doesn't have eflags so they can't flip + if (P_MobjFlip(spr->mobj) == -1) { basey = FIXED_TO_FLOAT(interp.z + spr->mobj->height); } + else + { + basey = FIXED_TO_FLOAT(interp.z); + } + lowy = wallVerts[0].y; + // Rotate sprites to fully billboard with the camera // X, Y, AND Z need to be manipulated for the polys to rotate around the // origin, because of how the origin setting works I believe that should From 0cd3629d00745b4f71123f809a855bbb44ece04c Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 1 Nov 2022 13:41:04 +0000 Subject: [PATCH 132/137] Explicit pointer cast for R_InterpolatePrecipMobjState --- src/hardware/hw_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 8d2170435..4bf5ccb68 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -3767,7 +3767,7 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts { if (precip) { - R_InterpolatePrecipMobjState(spr->mobj, rendertimefrac, &interp); + R_InterpolatePrecipMobjState((precipmobj_t *)spr->mobj, rendertimefrac, &interp); } else { @@ -3778,7 +3778,7 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts { if (precip) { - R_InterpolatePrecipMobjState(spr->mobj, FRACUNIT, &interp); + R_InterpolatePrecipMobjState((precipmobj_t *)spr->mobj, FRACUNIT, &interp); } else { From 4a580558f0ba3bafc9e2326a3a6c266fccfa3c13 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 7 Nov 2022 18:49:39 -0600 Subject: [PATCH 133/137] Tweak showfps alignment --- src/screen.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/screen.c b/src/screen.c index ef1e1d323..ef02a4771 100644 --- a/src/screen.c +++ b/src/screen.c @@ -547,20 +547,21 @@ void SCR_DisplayTicRate(void) } else if (cv_ticrate.value == 1) // full counter { + const char *drawnstr; + INT32 width; + + // The highest assignable cap is < 1000, so 3 characters is fine. if (cap > 0) - { - V_DrawString(vid.width-(104*vid.dupx), h, - V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); - V_DrawString(vid.width-(72*vid.dupx), h, - ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%4.0f/%4u", fps, cap)); - } + drawnstr = va("%3.0f/%3u", fps, cap); else - { - V_DrawString(vid.width-(88*vid.dupx), h, - V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); - V_DrawString(vid.width-(56*vid.dupx), h, - ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%4.0f", fps)); - } + drawnstr = va("%4.2f", averageFPS); + + width = V_StringWidth(drawnstr, V_NOSCALESTART); + + V_DrawString(vid.width - ((7 * 8 * vid.dupx) + V_StringWidth("FPS: ", V_NOSCALESTART)), h, + V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:"); + V_DrawString(vid.width - width, h, + ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, drawnstr); } } From 3c5855b64aeb5880ac4c1dbfa8453ed6bb393be9 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 7 Nov 2022 19:38:30 -0600 Subject: [PATCH 134/137] Uncap sound test --- src/m_menu.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index 673725773..b32561e9a 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -7670,7 +7670,7 @@ static void M_HandleEmblemHints(INT32 choice) static musicdef_t *curplaying = NULL; static INT32 st_sel = 0, st_cc = 0; -static tic_t st_time = 0; +static fixed_t st_time = 0; static patch_t* st_radio[9]; static patch_t* st_launchpad[4]; @@ -7734,16 +7734,17 @@ static void M_DrawSoundTest(void) { if (cv_soundtest.value) { - frame[1] = (2-st_time); + frame[1] = (2 - (st_time >> FRACBITS)); frame[2] = ((cv_soundtest.value - 1) % 9); frame[3] += (((cv_soundtest.value - 1) / 9) % (FIRSTSUPERCOLOR - frame[3])); - if (st_time < 2) - st_time++; + if (st_time < (2 << FRACBITS)) + st_time += renderdeltatics; } } else { - if (curplaying->stoppingtics && st_time >= curplaying->stoppingtics) + fixed_t stoppingtics = (fixed_t)(curplaying->stoppingtics) << FRACBITS; + if (stoppingtics && st_time >= stoppingtics) { curplaying = NULL; st_time = 0; @@ -7754,11 +7755,11 @@ static void M_DrawSoundTest(void) angle_t ang; //bpm = FixedDiv((60*TICRATE)<= (FRACUNIT>>1)) // prevent overflow jump - takes about 15 minutes of loop on the same song to reach - st_time = (work>>FRACBITS); + if (st_time >= (FRACUNIT << (FRACBITS - 2))) // prevent overflow jump - takes about 15 minutes of loop on the same song to reach + st_time = work; work = FixedDiv(work*180, bpm); frame[0] = 8-(work/(20<= i) - st_scroll %= i; + st_scroll += renderdeltatics; - x -= st_scroll; + while (st_scroll >= (i << FRACBITS)) + st_scroll -= i << FRACBITS; + + x -= st_scroll >> FRACBITS; while (x < BASEVIDWIDTH-y) x += i; From 62b142f13673b8bbf25836a249f6784ff2ae5b13 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Mon, 7 Nov 2022 20:08:33 -0600 Subject: [PATCH 135/137] Uncap room list ellipsis animation --- src/m_menu.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/m_menu.c b/src/m_menu.c index b32561e9a..622b26db6 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -11066,7 +11066,7 @@ static INT32 menuRoomIndex = 0; static void M_DrawRoomMenu(void) { - static int frame = -12; + static fixed_t frame = -(12 << FRACBITS); int dot_frame; char text[4]; @@ -11077,7 +11077,7 @@ static void M_DrawRoomMenu(void) if (m_waiting_mode) { - dot_frame = frame / 4; + dot_frame = (int)(frame >> FRACBITS) / 4; dots = dot_frame + 3; strcpy(text, " "); @@ -11090,8 +11090,9 @@ static void M_DrawRoomMenu(void) strncpy(&text[dot_frame], "...", min(dots, 3 - dot_frame)); } - if (++frame == 12) - frame = -12; + frame += renderdeltatics; + while (frame >= (12 << FRACBITS)) + frame -= 12 << FRACBITS; currentMenu->menuitems[0].text = text; } From dc1beb8e5b04069b65bb1dbd64944980ac6fa2d6 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 7 Nov 2022 20:30:14 -0800 Subject: [PATCH 136/137] Fix buffer overflow when pasting into chat --- src/hu_stuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index c4067d7d8..b02eecb6c 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1142,7 +1142,7 @@ boolean HU_Responder(event_t *ev) if (chatlen+pastelen > HU_MAXMSGLEN) return true; // we can't paste this!! - memmove(&w_chat[c_input + pastelen], &w_chat[c_input], pastelen); + memmove(&w_chat[c_input + pastelen], &w_chat[c_input], (chatlen - c_input) + 1); // +1 for '\0' memcpy(&w_chat[c_input], paste, pastelen); // copy all of that. c_input += pastelen; return true; From 6d1a3bfce0db4cca26b61107322ef4a0c5035521 Mon Sep 17 00:00:00 2001 From: Eidolon Date: Tue, 8 Nov 2022 18:48:50 -0600 Subject: [PATCH 137/137] Reset camera when moving player to spawn/starpost --- src/g_game.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/g_game.c b/src/g_game.c index e1380e3a7..abefac161 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2809,6 +2809,13 @@ void G_MovePlayerToSpawnOrStarpost(INT32 playernum) P_MovePlayerToStarpost(playernum); else P_MovePlayerToSpawn(playernum, G_FindMapStart(playernum)); + + R_ResetMobjInterpolationState(players[playernum].mo); + + if (playernum == consoleplayer) + P_ResetCamera(&players[playernum], &camera); + else if (playernum == secondarydisplayplayer) + P_ResetCamera(&players[playernum], &camera2); } mapthing_t *G_FindCTFStart(INT32 playernum)