From 1550210188b6a115b4e62f2a2e99c1b198c7fd9f Mon Sep 17 00:00:00 2001 From: Eidolon Date: Sun, 6 Oct 2019 17:40:52 -0500 Subject: [PATCH] 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 | 35 +++++++- src/d_main.h | 1 + src/dummy/i_system.c | 2 +- src/g_game.c | 12 ++- src/hardware/hw_main.c | 97 +++++++++++++++----- src/i_system.h | 4 + src/p_mobj.c | 20 +++++ src/p_mobj.h | 2 + src/p_tick.c | 1 + src/r_fps.c | 175 +++++++++++++++++++++++++++++++++++++ src/r_fps.h | 63 +++++++++++++ src/r_main.c | 167 ++++++++++++++++------------------- src/r_main.h | 6 ++ src/r_things.c | 106 +++++++++++++++------- src/sdl/i_system.c | 29 ++++-- src/win32/win_sys.c | 6 ++ 20 files changed, 573 insertions(+), 163 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 7a021dda7..27ac64e78 100644 --- a/src/Makefile.d/versions.mk +++ b/src/Makefile.d/versions.mk @@ -162,7 +162,7 @@ ifdef DEBUGMODE ifdef GCC48 opts+=-Og else -opts+=O0 +opts+=-O0 endif endif diff --git a/src/Sourcefile b/src/Sourcefile index 384af8da7..9bc27d4da 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -56,6 +56,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 908629bea..d8b81dcec 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 5b4141328..0f7227cb6 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5288,6 +5288,7 @@ void TryRunTics(tic_t realtics) while (neededtic > gametic) { DEBFILE(va("============ Running tic %d (local %d)\n", gametic, localgametic)); + prev_tics = I_GetTime(); ps_tictime = I_GetPreciseTime(); diff --git a/src/d_main.c b/src/d_main.c index 5ded2bf14..f611c4c3f 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -63,6 +63,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 @@ -154,6 +155,7 @@ event_t events[MAXEVENTS]; INT32 eventhead, eventtail; boolean dedicated = false; +boolean tic_happened = false; // Frame interpolation/uncapped // // D_PostEvent @@ -755,7 +757,7 @@ void D_SRB2Loop(void) debugload--; #endif - if (!realtics && !singletics) + if (!realtics && !singletics && cv_frameinterpolation.value != 1) { I_Sleep(); continue; @@ -771,15 +773,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(); @@ -788,7 +802,22 @@ void D_SRB2Loop(void) } else if (rendertimeout < entertic) // in case the server hang or netsplit { - D_Display(); +#if 0 + // Lagless camera! Yay! + if (gamestate == GS_LEVEL && netgame) + { + INT32 i; + + for (i = 0; i <= r_splitscreen; i++) + { + if (camera[i].chase) + P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false); + } + } +#endif + + // (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 81de0634d..26b5c4528 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 e964fb65d..cb2fa4e77 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -45,8 +45,8 @@ #include "y_inter.h" #include "v_video.h" #include "lua_hook.h" -#include "k_bot.h" #include "m_cond.h" // condition sets +#include "r_fps.h" // frame interpolation/uncapped #include "lua_hud.h" // SRB2kart @@ -56,6 +56,7 @@ #include "k_color.h" #include "k_respawn.h" #include "k_grandprix.h" +#include "k_bot.h" #include "doomstat.h" #ifdef HAVE_DISCORDRPC @@ -1920,6 +1921,8 @@ void G_Ticker(boolean run) F_TextPromptTicker(); AM_Ticker(); HU_Ticker(); + R_UpdateViewInterpolation(); + break; case GS_INTERMISSION: @@ -1976,7 +1979,12 @@ void G_Ticker(boolean run) break; case GS_TITLESCREEN: - if (titlemapinaction) P_Ticker(run); + if (titlemapinaction) + { + P_Ticker(run); + R_UpdateViewInterpolation(); + } + F_TitleScreenTicker(run); break; diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 205fc3ff6..c950e3b32 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" @@ -5013,10 +5014,6 @@ static void HWR_AddSprites(sector_t *sec) // BP why not use xtoviexangle/viewangletox like in bsp ?.... static void HWR_ProjectSprite(mobj_t *thing) { - fixed_t thingxpos = thing->x + thing->sprxoff; - fixed_t thingypos = thing->y + thing->spryoff; - fixed_t thingzpos = thing->z + thing->sprzoff; - gl_vissprite_t *vis; float tr_x, tr_y; float tz; @@ -5056,13 +5053,34 @@ static void HWR_ProjectSprite(mobj_t *thing) angle_t spriterotangle = 0; #endif + // uncapped/interpolation + fixed_t interpx; + fixed_t interpy; + fixed_t interpz; + angle_t interpangle; + if (!thing) return; if (thing->spritexscale < 1 || thing->spriteyscale < 1) return; - // hitlag vibrating + dispoffset = thing->info->dispoffset; + + interpx = thing->x + thing->sprxoff; + interpy = thing->y + thing->spryoff; + interpz = thing->z + thing->sprzoff; + 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; + } + + // hitlag vibrating (todo: interp somehow?) if (thing->hitlag > 0 && (thing->eflags & MFE_DAMAGEHITLAG)) { fixed_t mul = thing->hitlag * (FRACUNIT / 10); @@ -5072,20 +5090,18 @@ static void HWR_ProjectSprite(mobj_t *thing) mul = -mul; } - thingxpos += FixedMul(thing->momx, mul); - thingypos += FixedMul(thing->momy, mul); - thingzpos += FixedMul(thing->momz, mul); + interpx += FixedMul(thing->momx, mul); + interpy += FixedMul(thing->momy, mul); + interpz += FixedMul(thing->momz, mul); } - dispoffset = thing->info->dispoffset; - 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(thingxpos) - gl_viewx; - tr_y = FIXED_TO_FLOAT(thingypos) - 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); @@ -5108,8 +5124,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(thingxpos); - tr_y = FIXED_TO_FLOAT(thingypos); + tr_x = FIXED_TO_FLOAT(interpx); + tr_y = FIXED_TO_FLOAT(interpy); // decide which patch to use for sprite relative to player #ifdef RANGECHECK @@ -5157,7 +5173,7 @@ static void HWR_ProjectSprite(mobj_t *thing) I_Error("sprframes NULL for sprite %d\n", thing->sprite); #endif - ang = R_PointToAngle (thingxpos, thingypos) - mobjangle; + ang = R_PointToAngle (interpx, interpy) - interpangle; if (mirrored) ang = InvAngle(ang); @@ -5304,12 +5320,12 @@ static void HWR_ProjectSprite(mobj_t *thing) if (vflip) { - gz = FIXED_TO_FLOAT(thingzpos + 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(thingzpos) + (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); } @@ -5328,12 +5344,12 @@ static void HWR_ProjectSprite(mobj_t *thing) if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { if (gl_viewz < FIXED_TO_FLOAT(sectors[phs].floorheight) ? - FIXED_TO_FLOAT(thingzpos) >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) : + FIXED_TO_FLOAT(interpz) >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) : gzt < FIXED_TO_FLOAT(sectors[heightsec].floorheight)) return; if (gl_viewz > FIXED_TO_FLOAT(sectors[phs].ceilingheight) ? gzt < FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) && gl_viewz >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) : - FIXED_TO_FLOAT(thingzpos) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight)) + FIXED_TO_FLOAT(interpz) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight)) return; } @@ -5468,9 +5484,29 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) unsigned rot = 0; UINT8 flip; + // uncapped/interpolation + fixed_t interpx; + fixed_t interpy; + fixed_t interpz; + + if (!thing) + return; + + interpx = thing->x; + interpy = thing->y; + 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) @@ -5547,7 +5583,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing) #endif // 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; @@ -6651,6 +6687,7 @@ INT32 HWR_GetTextureUsed(void) void HWR_DoPostProcessor(player_t *player) { postimg_t *type = &postimgtype[0]; + fixed_t fractime; SINT8 i; HWD.pfnUnSetShader(); @@ -6702,6 +6739,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; @@ -6733,6 +6772,16 @@ void HWR_DoPostProcessor(player_t *player) HWD.pfnPostImgRedraw(v); if (!(paused || P_AutoPause())) disStart += 1; + 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 0d5898a72..4bc0e73da 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 2b2cfc251..e28c64a33 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3636,6 +3636,11 @@ void P_NullPrecipThinker(precipmobj_t *mobj) void P_PrecipThinker(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_RAINRETURN]) @@ -8593,6 +8598,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; + // Remove dead target/tracer. if (mobj->target && P_MobjWasRemoved(mobj->target)) P_SetTarget(&mobj->target, NULL); @@ -9743,6 +9753,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 initial old positions (for interpolation) + mobj->old_x = mobj->x; + mobj->old_y = mobj->y; + mobj->old_z = mobj->z; + return mobj; } @@ -9794,6 +9809,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 16055907b..3247c14d7 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -275,6 +275,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; @@ -412,6 +413,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 be82b9d40..9a4baa092 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -24,6 +24,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..ca1fa0852 --- /dev/null +++ b/src/r_fps.c @@ -0,0 +1,175 @@ +// 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" +#include "doomstat.h" // MAXSPLITSCREENPLAYERS +#ifdef HWRENDER +#include "hardware/hw_main.h" // for cv_glshearing +#endif + +static viewvars_t pview_old[MAXSPLITSCREENPLAYERS]; +static viewvars_t pview_new[MAXSPLITSCREENPLAYERS]; +static viewvars_t skyview_old[MAXSPLITSCREENPLAYERS]; +static viewvars_t skyview_new[MAXSPLITSCREENPLAYERS]; + +static viewvars_t *oldview = &pview_old[0]; +viewvars_t *newview = &pview_new[0]; + + +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 + for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) + { + if (newview == &skyview_new[i]) + { + skybox = true; + break; + } + } + + R_SetupFreelook(newview->player, skybox); +} + +void R_UpdateViewInterpolation(void) +{ + INT32 i; + + for (i = 0; i < MAXSPLITSCREENPLAYERS; i++) + { + pview_old[i] = pview_new[i]; + skyview_old[i] = skyview_new[i]; + } +} + +void R_SetViewContext(enum viewcontext_e _viewcontext) +{ + INT32 i; + + I_Assert(_viewcontext >= VIEWCONTEXT_PLAYER1 + && _viewcontext <= VIEWCONTEXT_SKY4); + viewcontext = _viewcontext; + + switch (viewcontext) + { + case VIEWCONTEXT_PLAYER1: + case VIEWCONTEXT_PLAYER2: + case VIEWCONTEXT_PLAYER3: + case VIEWCONTEXT_PLAYER4: + i = viewcontext - VIEWCONTEXT_PLAYER1; + oldview = &pview_old[i]; + newview = &pview_new[i]; + break; + case VIEWCONTEXT_SKY1: + case VIEWCONTEXT_SKY2: + case VIEWCONTEXT_SKY3: + case VIEWCONTEXT_SKY4: + i = viewcontext - VIEWCONTEXT_SKY1; + oldview = &skyview_old[i]; + newview = &skyview_new[i]; + 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..24b79c922 --- /dev/null +++ b/src/r_fps.h @@ -0,0 +1,63 @@ +// 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_PLAYER3, + VIEWCONTEXT_PLAYER4, + VIEWCONTEXT_SKY1, + VIEWCONTEXT_SKY2, + VIEWCONTEXT_SKY3, + VIEWCONTEXT_SKY4 +}; + +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 dfc11ab4a..6cb05801c 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -36,6 +36,7 @@ #include "r_main.h" #include "i_system.h" // I_GetPreciseTime #include "doomstat.h" // MAXSPLITSCREENPLAYERS +#include "r_fps.h" // Frame interpolation/uncapped #ifdef HWRENDER #include "hardware/hw_main.h" @@ -79,6 +80,8 @@ mobj_t *r_viewmobj; int r_splitscreen; +fixed_t rendertimefrac; + // // precalculated math tables // @@ -100,6 +103,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; @@ -172,6 +178,9 @@ consvar_t cv_fov[MAXSPLITSCREENPLAYERS] = { CVAR_INIT ("fov4", "90", CV_FLOAT|CV_CALL, fov_cons_t, Fov_OnChange) }; +// Frame interpolation/uncapped +consvar_t cv_frameinterpolation = CVAR_INIT ("frameinterpolation", "On", CV_SAVE, CV_OnOff, NULL); + // Okay, whoever said homremoval causes a performance hit should be shot. consvar_t cv_homremoval = CVAR_INIT ("homremoval", "Yes", CV_SAVE, homremoval_cons_t, NULL); @@ -1193,40 +1202,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)<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 (!demo.playback && player->playerstate != PST_DEAD) { - viewangle = localangle[i]; // WARNING: camera uses this - aimingangle = localaiming[i]; + newview->angle = localangle[i]; // WARNING: camera uses this + newview->aim = localaiming[i]; } } - 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) @@ -1338,6 +1316,7 @@ void R_SkyboxFrame(player_t *player) if (player == &players[displayplayers[i]]) { thiscam = &camera[i]; + R_SetViewContext(VIEWCONTEXT_SKY1 + i); break; } } @@ -1349,6 +1328,7 @@ void R_SkyboxFrame(player_t *player) } // cut-away view stuff + newview->sky = true; r_viewmobj = skyboxmo[0]; #ifdef PARANOIA if (!r_viewmobj) @@ -1359,31 +1339,31 @@ 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 (/*!demo.playback && */player->playerstate != PST_DEAD) { - viewangle = localangle[i]; - aimingangle = localaiming[i]; + newview->angle = localangle[i]; + newview->aim = localaiming[i]; } } - 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]) { @@ -1425,46 +1405,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) @@ -1737,4 +1717,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 5208b52a3..2ddec0ff1 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -33,6 +33,8 @@ extern fixed_t fovtan[MAXSPLITSCREENPLAYERS]; extern size_t validcount, linecount, loopcount, framecount; +extern fixed_t rendertimefrac; + // // Lighting LUT. // Used for z-depth cuing per column/row, @@ -111,6 +113,10 @@ extern consvar_t cv_fov[MAXSPLITSCREENPLAYERS]; 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 defd02a5f..90a0cb2c9 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1361,15 +1361,11 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, // static void R_ProjectSprite(mobj_t *thing) { - fixed_t thingxpos = thing->x + thing->sprxoff; - fixed_t thingypos = thing->y + thing->spryoff; - fixed_t thingzpos = thing->z + thing->sprzoff; - mobj_t *oldthing = thing; //const fixed_t oldthingxpos = oldthing->x + oldthing->sprxoff; //const fixed_t oldthingypos = oldthing->y + oldthing->spryoff; - const fixed_t oldthingzpos = oldthing->z + oldthing->sprzoff; + //const fixed_t oldthingzpos = oldthing->z + oldthing->sprzoff; fixed_t tr_x, tr_y; fixed_t tx, tz; @@ -1435,7 +1431,32 @@ static void R_ProjectSprite(mobj_t *thing) angle_t spriterotangle = 0; #endif - // hitlag vibrating + // uncapped/interpolation + fixed_t interpx = thing->x + thing->sprxoff; + fixed_t interpy = thing->y + thing->spryoff; + fixed_t interpz = thing->z + thing->sprzoff; + 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; + } + } + + // hitlag vibrating (todo: interp somehow?) if (thing->hitlag > 0 && (thing->eflags & MFE_DAMAGEHITLAG)) { fixed_t mul = thing->hitlag * (FRACUNIT / 10); @@ -1445,14 +1466,14 @@ static void R_ProjectSprite(mobj_t *thing) mul = -mul; } - thingxpos += FixedMul(thing->momx, mul); - thingypos += FixedMul(thing->momy, mul); - thingzpos += FixedMul(thing->momz, mul); + interpx += FixedMul(thing->momx, mul); + interpy += FixedMul(thing->momy, mul); + interpz += FixedMul(thing->momz, mul); } // transform the origin point - tr_x = thingxpos - viewx; - tr_y = thingypos - viewy; + tr_x = interpx - viewx; + tr_y = interpy - viewy; basetz = tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance @@ -1529,7 +1550,7 @@ static void R_ProjectSprite(mobj_t *thing) if (sprframe->rotate != SRF_SINGLE || papersprite) { - ang = R_PointToAngle (thingxpos, thingypos) - (thing->player ? thing->player->drawangle : thing->angle); + ang = R_PointToAngle (interpx, interpy) - interpangle; if (mirrored) ang = InvAngle(ang); } @@ -1544,7 +1565,7 @@ static void R_ProjectSprite(mobj_t *thing) else { // choose a different rotation based on player view - //ang = R_PointToAngle (thingxpos, thingypos) - thing->angle; + //ang = R_PointToAngle (interpx, interpy) - interpangle; if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right rot = 6; // F7 slot @@ -1755,12 +1776,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 = (thingxpos + sort_x) - viewx; - tr_y = (thingypos + 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[viewssnum], tz); @@ -1775,8 +1801,8 @@ static void R_ProjectSprite(mobj_t *thing) } else if (splat) { - tr_x = (thingxpos + sort_x) - viewx; - tr_y = (thingypos + sort_y) - viewy; + tr_x = (interpx + sort_x) - viewx; + tr_y = (interpy + sort_y) - viewy; sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); sortscale = FixedDiv(projectiony[viewssnum], sort_z); } @@ -1796,7 +1822,7 @@ static void R_ProjectSprite(mobj_t *thing) if (x2 < portalclipstart || x1 >= portalclipend) return; - if (P_PointOnLineSide(thingxpos, thingypos, portalclipline) != 0) + if (P_PointOnLineSide(interpx, interpy, portalclipline) != 0) return; } @@ -1865,12 +1891,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 = oldthingzpos + 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 = oldthingzpos + 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)); } } @@ -1889,7 +1915,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], thingxpos, thingypos); + fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interpx, interpy); if (h <= top) { light = lightnum - 1; break; @@ -1915,12 +1941,12 @@ static void R_ProjectSprite(mobj_t *thing) if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { if (viewz < sectors[phs].floorheight ? - thingzpos >= sectors[heightsec].floorheight : + interpz >= sectors[heightsec].floorheight : gzt < sectors[heightsec].floorheight) return; if (viewz > sectors[phs].ceilingheight ? gzt < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight : - thingzpos >= sectors[heightsec].ceilingheight) + interpz >= sectors[heightsec].ceilingheight) return; } @@ -1933,12 +1959,12 @@ static void R_ProjectSprite(mobj_t *thing) vis->sortscale = sortscale; vis->sortsplat = sortsplat; vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15 - vis->gx = thingxpos; - vis->gy = thingypos; + vis->gx = interpx; + vis->gy = interpy; vis->gz = gz; vis->gzt = gzt; vis->thingheight = thing->height; - vis->pz = thingzpos; + vis->pz = interpz; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = FixedDiv(gzt - viewz, spriteyscale); vis->scalestep = scalestep; @@ -2073,9 +2099,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 @@ -2139,12 +2178,12 @@ 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) @@ -2157,10 +2196,13 @@ 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 = interpz; + vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; vis->scalestep = 0; vis->paperdistance = 0; diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 2778e6b6f..71b5af958 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -181,7 +181,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" @@ -1640,17 +1640,29 @@ 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; + double f = 0.0; + UpdateElapsedTics(); + f = floor(elapsed_tics); + return (tic_t)f; +} - 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) @@ -1672,6 +1684,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 2609c3e31..9b2c5bd07 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 > 0)